GNU Make with several folders and files - file

I have to write a "good" makefile for a program that has several folders:
bin, inc, obj, src. Here are my make files. If I type make it just says that nothing can be done although the program is not compiled at all. Guess I have a error somewhere but I really can't find it. (ps I'm quite new to make).
Thanks a lot for your help!
makefile in bin folder:
vpath %.o ../obj/
$(prog): $(objs)
$(cc) $(ccflags) -o $# $^ $(ldflags)
makefile in obj folder:
vpath %.c ../src
vpath %.h ../inc
all: $(objs)
%.o: %.c %.h
$(cc) $(ccflags) -c $<
-include *.d
general makefile:
export prog := inv_svn
export objs := $(patsubst %.c, %.o, $(wildcard src/*.c)))
export src_dir := src
export inc_dir := inc
export obj_dir := obj
export bin_dir := bin
export cc := gcc
export ccflags := -I $(PWD)/$(inc_dir) -MMD -g -Wall
export ldflags := -lcurses -lgdbm
test := ./$(prog)
all: $(prog)
$(prog): $(bin_dir)
$(bin_dir): $(obj_dir)
$(bin_dir):
make -C $#
$(obj_dir):
make -C $#
.PHONY: clean
clean:
rm -f $(obj_dir)/*.[od]$(prog)

There are too many problems here to fix all at once. Let's start small and simple, and build up.
First, you're using Make recursively when you really don't have to. Later, you should reconsider this design. For now, let's see if we can get obj/makefile working.
Second, the sub-makefiles depend on variables (like objs) passed down from the invoking makefile, variables which they could just as well construct themselves. This is bad design. We'll put the assignment in obj/makefile:
objs := $(patsubst %.c, %.o, $(wildcard ../src/*.c))
(Note that I've removed an extra ) that was messing things up.)
Third, when we test this, we get ../src/foo.o ../src/bar.o, which is probably not what we want; we want to build the objects in obj/, not src/ (the assignment in the main makefile had the same problem). So we change it:
objs := $(patsubst ../src/%.c, %.o, $(wildcard ../src/*.c))
(There are more graceful ways, but never mind that for now.)
Fourth, I trust you can make similar changes to bin/makefile.
Fifth, in the main Makefile, you treat the subdirectories as targets, when they really aren't; the point of those rules isn't to construct the subdirectories, but to run Make in them. If they already exist (which they do), Make is satisfied, and concludes that $(prog) and all need not be rebuilt. We can solve this with some PHONY targets:
.PHONY: RUN_IN_$(obj_dir) RUN_IN_$(bin_dir)
$(prog): RUN_IN_$(bin_dir)
RUN_IN_$(bin_dir): RUN_IN_$(obj_dir)
RUN_IN_$(bin_dir):
make -C $(bin_dir)
RUN_IN_$(obj_dir):
make -C $(obj_dir)
Crude but effective.
That should be enough to get you off the ground.

Related

How to have gnu make treat intermediate files as out of date

I've been following http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine to create a Makefile that will generate a dependency list too, so the list of header files a .o target depends on (from the related .c file) is automatically generated.
The Makefile I have ended up with is
DEPDIR := .deps
$(shell mkdir -p $(DEPDIR))
DEPFLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.Td
INCDIR = ../includes
CFLAGS = -I$(INCDIR)
CC = gcc
SRCS = main.c chunk.c memory.c
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
%.o: %.c
%.o: %.c $(DEPDIR)/%.d
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))))
running make main.o generates main.o and .deps/main.d as expected, and changing one of the header files included in main.c causes main.o to be out of date and regenerated as desired.
However, main.o should also be out of date if .deps/main.d does not exist, but deleting .deps/main.d doesn't cause make to see main.o as out of date.
What needs to be changed to make deleting .deps/main.d cause make to see main.o as out of date?
I've been meaning to update my blog post. You need to ensure that the dependency files are listed as prerequisites somewhere so they're not considered intermediate. Change this line:
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))))
to something like:
ALLDEPS := $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS)))
build-deps: $(ALLDEPS)
.PHONY: build-deps
include $(wildcard $(ALLDEPS))
I'm not 100% sure why these are considered intermediate and yet make doesn't delete them; I'll have to look into it more closely.

Makefile for multiple files in different directories

I am a newbie in creating makefiles, and would be glad if someone could help me.
I have created several header files (for function declarations) and corresponding .c programs (8 in total), for the function definitions (including the main function). These are listed in the .../include/ directory. Additionally, I have created another directory for the storing the output files : .../bin/ after compilation. I tried to link the .o files, but was unsuccessful. I have attached a small piece of the makefile code (similar one taken from the internet) :
CC = g++
CFLAGS = -Wall -O3
INC_DIR := /media/sf_~share/151*/Codes/include
OBJ_DIR := /media/sf_~share/151*/Codes/obj
INC_FILES := $(wildcard $(INC_DIR)/%.c)
OBJ_FILES := $(patsubst $(INC_DIR)/%.c, $(OBJ_DIR)/%.o, $(INC_FILES))
all : $(APP)
$(APP) : $(OBJ_FILES)
$(CC) $(CFLAGS) -o $# $^
$(OBJ_DIR)/%.o : $(INC_DIR)/%.c
$(CC) $(CFLAGS) -o $# $<
clean:
rm -f *.o $(APP)
I would be glad if someone could either suggest me a different code, or rectify this as it is.
There are a few mistakes in your Makefile:
Wildcard usage
You should use *.c rather than %.c for wildcard expansion, like this:
INC_FILES := $(wildcard $(INC_DIR)/*.c)
Patsubst usage
You don't need to specify the full pattern $(INC_DIR)/%.c for patsubst, instead, simply use:
OBJ_FILES := $(patsubst %.c, %.o, $(INC_FILES))
Missing $(APP) value
I don't know if you simply forgot to add this to the sample or not, but since $(APP) is an empty string, the makefile says:
make: Nothing to be done for `all'.
Adding APP := program triggers a build for all the *.c files in include.

Makefile to convert all *.c to *.o

I am writing a Makefile for compiling all *.c files in a directory into
*.o . There are many *.c files so I don't want to do it on individual basis,
I tried
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
but this isn't working ... please help me understand what's going wrong here ...
You told make how to generate a *.o out of a corresponding *.c file. (Not that you needed to, because make already knows as much, at least as long as you don't try anything more specific than what you wrote in your rule.)
You didn't tell make you wanted any specific foo.o or bar.o, so make does nothing.
Either add a list of object files you want generated to the Makefile, or call make foo.o specifically.
----
For what it's worth, have a look at this... there are some tricks and lessons in there, which I trust your curiosity will find out about. Most importantly, it adds compiler warnings, and automated header dependency handling.
This is assuming GNU make for e.g. patsubst, the existence of find, and GCC (for the dependency handling via -MMD -MP). If you want to go cross-platform, I'd suggest a meta-build system like CMake, which I am using myself.
PROJNAME := MyProject
PROJDIRS := subdir1 subdir2
SRCFILES := $(shell find $(PROJDIRS) -type f -name "\*.c")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
WARNINGS := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-Wredundant-decls -Wnested-externs -Winline \
-Wuninitialized -Wconversion -Wstrict-prototypes
CFLAGS := -g -std=c99 $(WARNINGS)
.PHONY: all clean
all: $(PROJNAME)
clean:
-#$(RM) $(wildcard $(OBJFILES) $(DEPFILES) $(PROJNAME))
-include $(DEPFILES)
$(PROJNAME): $(OBJFILES)
#$(CC) $(LDFLAGS) $^
%.o: %.c Makefile
#$(CC) $(CFLAGS) -MMD -MP -c $< -o $#
Your rule maps a single .c file to a single .o, and mirrors an existing implicit rule.
In order to generate all the .o files corresponding to a set of .c files, you can create a list of object file names from the list of .c files, and then make a target that depends on that list:
SRC = $(wildcard *.c) # list of source files
OBJS = $(patsubst %.c, %.o, $(SRC)) # list of object files
objs : $(OBJS) # target
Then generate the object files with
make objs
This will build a .o file for each .c one.
You can add a rule OBJS, it will do it for you
OBJS = $(SRCS:.c=.o)
With you .c files in the SRCS, and if they are too many do:
SRCS = $(wildcard *.c)
Then add it when you'll run make
$(NAME) : $(OBJS)
[...]

GNU make implicit archive rule with stem

I am trying to setup a Makefile to build either static (.a) and dynamic (.so) libraries depending on the target file extension.
I previously used the following Makefile for static libraries only :
NAME := config
LIB := lib$(NAME).a
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
CFLAGS += -W -Wall
.PHONY: all clean fclean re
all: $(LIB)
clean:
#$(RM) $(OBJ)
fclean: clean
#$(RM) $(LIB)
re: fclean all
$(LIB): $(LIB)($(OBJ))
ranlib $#
My main goal is to be able to compile multiple libraries by only changing the LIB and NAMEvariables.
Everything worked fine, so I added the following for the dynamic libraries :
LDFLAGS += -shared
%.so: CFLAGS += -fPIC
%.so: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^
And changed the $(LIB): rule by the following generic rule :
%.a: %.a($(OBJ))
ranlib $#
If I change LIB to lib$(NAME).so everything works as expected, but with the .a extension, make prints me this error :
make: *** No rule to make target 'libconfig.a', needed by 'all'. Stop.
The only solution I found was to add another explicit rule like that :
%.a($(OBJ)): $(OBJ)
$(AR) rv $# $^
And now everything works.
But adding this explicit rule prevents me from relying only upon GNU make's implicit rules, and makes me call explicitly ar, which I wanted to avoid.
Is this some kind of bug or am I missing something ?
GNU Make 3.82
Built for x86_64-unknown-linux-gnu
Some quick testing seems to indicate that this can't be done. It appears that the specialized make archive support is a makefile parse time feature. That is the literal archive name must exist in the actual makefile for it to take effect.
I tried a couple of workarounds but wasn't able to get any of them to work correctly. The closest I could manage was:
$(foreach a,$(filter %.a,$(MAKECMDGOALS) $(.DEFAULT_GOAL)),$(eval $a: $a($$(OBJ)); ranlib $$#))
which doesn't work for a default goal of all but would if the default was the library name and/or if the library name is an explicit make target. You could stick any other known library names in there too and then they should work even as implicit requirements of other targets but that's a manual process.
You need to tell make which .o files a given .a file depends on. You can do that with a simple dpendency with no action:
libconfig.a: libconfig.a($(OBJ))
make will then invoke the default rule for putting .o files into a .a file to actually build libconfig.a
Archives and shared libraries don't share the same prerequisites syntax, so it is not possible to have a single rule that handle both.
The simplest solution is to use a conditional on the target extension:
ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
endif
A working Makefile that meets the requirements looks now like this:
NAME := config
LIB := lib$(NAME).so
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP
CFLAGS := -W -Wall
LDFLAGS := -shared
ARFLAGS := rs
.PRECIOUS: $(OBJ)
.PHONY: all clean fclean re
all: $(LIB)
clean:
$(RM) $(OBJ) $(DEP)
fclean: clean
$(RM) $(LIB)
re: fclean all
ifeq "$(suffix $(LIB))" ".a"
$(LIB): $(LIB)($(OBJ))
else ifeq "$(suffix $(LIB))" ".so"
$(LIB): override CFLAGS += -fPIC
$(LIB): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
endif
ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif
Note that the ARFLAGS variable controls which flags are passed to the invocation of ar. Here I use the r flag to replace existing object if it exists and the s flag to build or update the index (ranlib is not necessary anymore with this).

How to make `make` make an a executable for each C file in a folder?

My question is deceptively simple, but I have lost several hours of study trying to get the solution. I'm trying to create a Makefile that builds an executable for each .c file in a directory.
I have tried the following:
CC = gcc
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
all: $(OBJS)
$(CC) $< -o $#
%.o: %.c
$(CC) $(CPFLAGS) -c $<
but this way it is creating only .o files, and not any executables. I need a rule that makes an executable for each of these .o files. Something like the following:
gcc src.o -o src
rob's answer doesn't seem to work on my machine. Perhaps, as the complete Makefile:
SRCS = $(wildcard *.c)
all: $(SRCS:.c=)
.c:
gcc $(CPFLAGS) $< -o $#
(The last two lines, are on my machine, unnecessary, as the default rules are adequate.)
Your all is telling it just to build the object files. Add something like
EXEC = $(patsubst %.c,%,$(SRCS))
all: $(EXEC)
Try the following:
% : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $# $<
all: $(basename $(wildcard *.c))
and you don't even need the first two lines, as make knows how to compile and link .c files into executables. Still, it is often necessary to change make's built-in recipes.
This is the Makefile I use to compile a bunch of scheme files.
SRCS = $(wildcard *.scm)
all: $(SRCS:.scm=)
%: %.scm
chicken-csc -o $# $<

Resources