Iterating over a directory of files using GNU Make - c

My project has a directory called tests/ which contains an arbitrary number of C source files, each one is a self-contained program designed to test a library. For each of these sourcefiles, I want to create an executable of the same name in my build/ directory.
E.g. tests/test_init.c would compile to an executable file build/test_init.
Currently, my Makefile snippet looks like the following:
BUILD_DIR = build
TEST_DIR = tests
test_sources:= $(TEST_DIR)/*.c
test_executables:= $(patsubst %.c, %, $(test_sources))
.PHONY: tests
tests: $(test_executables)
$(CC) $^ -o $# -g
But this fails to produce to desired result. Any help would be much appreciated.

First you need the wildcard function to find the sources:
test_sources:= $(wildcard $(TEST_DIR)/*.c)
Then the correct names for the executables:
test_executables:= $(patsubst $(TEST_DIR)/%.c, $(BUILD_DIR)/%, $(test_sources))
Then a pattern rule to build a test executable from the corresponding source:
$(BUILD_DIR)/%: $(TEST_DIR)/%.c
$(CC) $< -o $# -g
(A static pattern rule might be a little tidier, but it's a more advanced method.)
Finally a phony target to build all of the tests:
.PHONY: tests
tests: $(test_executables)
If you wanted Make to run all of these tests, you could make a phony pattern rule run_test_%, but that can wait for another day.

This Makefile will detect all files in test/*.c and provides tasks build_tests, run_tests, and clean_tests.
all: build_tests
define test_template
build_tests: test/$(1)
run_tests: build_tests run_test_$(1)
test/$(1) : test/$(1).c
$$(CC) $$^ -o $$#
.PHONY : run_test_$(1)
run_test_$(1) : test/$(1)
test/$(1)
endef
clean: clean_tests
clean_tests:
rm -fv $(foreach test, $(tests),test/$(test))
# Auto detect the tests (any .c file in the test directory),
# and store the list of tests names.
tests := $(foreach test, $(wildcard test/*.c),$(patsubst %.c,%,$(notdir $(test))))
# Add information about each test to the Makefile.
$(foreach test, $(tests), $(eval $(call test_template,$(test))))
Note: I'm not sure how to get tabs working inside a code block in markdown, so you'll need to replace spaces with a single tab on each indented line if you copy and paste this.

Related

How to build multiple targets with similar name?

So I have the exact same question as the one below, but no one has answered it.
Pattern matching Makefile with multiple executable targets
I am trying to build a series of small test files each have a pattern of "test*.c" to test my library.
I wanted to write a makefile that builds executables for every one of the test files all at once (each name: test1, test2, test3..etc.). However, I am not sure how to achieve that.
What I have so far is the following:
SRC := $(shell find *.c)
ALL_PROG := $(patsubst %.c, %, *.c)
.PHONY: all
all: $(ALL_PROG)
$(ALL_PROG): $(SRC)
-gcc $< -o $#
This is a bad attempt because the targets take all .c files as dependency, which caused circular dependency.
Using shell script can get the job done very easily, but I am wondering if there's a way to do the same job.
Thanks in advance.
Use $(ALL_PROG): %: %.c instead of $(ALL_PROG): $(SRC).
Here is an example Makefile I might use with GNU make:
CC := gcc
CFLAGS := -Wall -O2
LDFLAGS := -lm
PROGS := $(patsubst %.c, %, $(wildcard *.c))
.PHONY: all clean test $(patsubst %, test#%, $(PROGS))
all: $(PROGS)
clean:
rm -f $(PROGS)
$(PROGS): %: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $#
$(patsubst %, test#%, $(PROGS)): test#%: %
./$^
test: $(patsubst %, test#%, $(PROGS))
As usual, note that the indentation should use a Tab rather than spaces; the editor used here on stackoverflow.com auto-converts them to spaces.
The PROGS variable will contain the names of all *.c files in the directory.
The .PHONY: directive tells Make which targets do not refer to actual files. The $(patsubst %, test#%, $(PROGS)) expands to the list of executable names, with each name prepended with test#: if the directory contains files foo.c and bar.c, this expands to test#foo test#bar.
The $(PROGS): %: %.c recipe compiles each .c file to the corresponding binary.
The $(patsubst %, test#%, $(PROGS)): test#%: % recipe creates a test target for each binary. If we have files foo.c and bar.c, then this rule expands to test#foo test#bar: test#%: %. This means that for both test#foo and test#bar targets, the corresponding test#% target requires the % binary. The ./$^ in turn expands to ./%, and thus the binary name. (If you don't want Make to show the command being run, use #./$^. If you don't care if a test fails, use -./$^.)
The test recipe expands to test#foo test#bar if we have foo.c and bar.c; i.e. all possible test targets.
You can run make clean test to recompile all .c files in the directory, and execute them.
If you are only worried about a specific test program, say foo.c, you can run make test#foo, which will recompile the program if foo.c is newer than foo.
You can do that. I am updating a simple make file which builds multiple targets. You can modify it as your requirement.
TEST1 = test1.exe
TEST2 = test2.exe
### Executable Program Files ###
all : $(TEST1) $(TEST2)
$(TEST1) : test1.c
gcc -o $(TEST1) test1.c
$(TEST2) : test2.c
gcc -o $(TEST2) test2.c

how to manage c files dependencies in make

i'm starting with make and i was searching how to automaticly generate dependencies for my c files, i found this piece of code :
# pull in dependency info for *existing* .o files
-include $(OBJS:.o=.d)
# compile and generate dependency info
%.o: %.c
gcc -c $(CFLAGS) $*.c -o $*.o
gcc -MM $(CFLAGS) $*.c > $*.d
what i don't understand is when i generate the dependencies file %.d, i already have built the %.o file, so what it the point to creating this dependencies file, and the -include i executed before everything so no dependencies file will exist.
-include means to include the dep file if it is there but not fail if it isn't.
The trick, and this is common in make dependency tracking, is that your dependencies are actually one build out of date. You're including, if they are there, the dependency files that were built the last time around.
This is not a problem because for dependencies to change, changes have to be made to something that the target depended on during the last build -- so even though make doesn't know the full new dependencies, it knows that it has to rebuild the target (and generate a new dependency file in the process).
Addendum: By the way, gcc and clang have a -MD option that can generate a dependency file while building the .o (by default with a .d suffix). This means that you can do automatic dependency tracking with implicit rules and cut down your Makefile to the bare minimum like so (for a simple project with .c files in a flat directory):
#!/usr/bin/make -f
# name of the binary to build
TARGET = target
CC = gcc
# These flags are used by the implicit rules for C preprocessor flags,
# C compiler flags, linker flags, and libraries to link (-lfoo options)
# -MD in CPPFLAGS means that the implicit rules for .o files will also
# generate a corresponding .d file that contains the dependencies.
# The values here are just examples (thank you, Rear Admiral Obvious!)
CPPFLAGS = -MD -I somewhere/include
CFLAGS = -O2 -g
LDFLAGS = -L somewhere/lib
LDLIBS = -lsomelibrary
# SRCS is a list of all .c files in the directory, the other two are
# pattern substitution expressions that take SRCS and replace the .c with .o
# and .d, respectively
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
DEPS = $(OBJS:.o=.d)
all: $(TARGET)
$(TARGET): $(OBJS)
# Look, Ma, no explicit rules for .o files!
clean:
rm -f $(TARGET) $(OBJS)
.PHONY: all clean
# include dep files (if available).
-include $(DEPS)
I usually add phony target depend, like this:
depend: $(SOURCES)
makedepend -Y. $(CFLAGS) $^ 2>/dev/null
and run make depend time to time to update depenencies.
See man makedepend for details.

sample make file for creating more than one exe files with different directory [duplicate]

This question already has answers here:
Building multiple executables with similar rules
(5 answers)
Closed 9 years ago.
I am having a directory called test where make file should be. i am having subdirectory called sub1, sub2, sub3.
test/Makefile
test/sub1
test/sub2
test/sub3
I want to create exe1 by compiling sub1, exe2 by compiling sub2 and exe3 from sub3.
Can i add more than one directory in vpath?? or any other solution
You could simply have a very simple makefile in the test directory, just going into the subdirectories and calling makefiles in them. The subdirectories have makefiles that builds normally, but simply put the executable in the parent directory.
First of all: Yes you could add more than one directory in vpath. Each entry is separated with a colon ':'
vpath %.c test/sub1:test/sub2:test/sub3
But you'll getting into trouble as soon you have the same filename (with different content) in two directories. Consider:
test/Makefile
test/sub1/main.c
test/sub1/foo.c
test/sub1/bar.c
...
test/sub2/main.c
test/sub2/blish.c
test/sub3/blash.c
...
test/sub3/main.c
test/sub3/okEnoughForNow.c
And your makefile containing:
vpath %.c sub1:sub2:sub3
exe1.exe : main.c foo.c bar.c
gcc -o $# $^
exe2.exe : main.c blish.c blash.c
gcc -o $# $^
exe3.exe : main.c okEnoughForNow.c
gcc -o $# $^
The result would be:
gcc -o exe1.exe sub1/main.c sub1/foo.c sub1/bar.c
gcc -o exe2.exe sub1/main.c sub2/blish.c sub2/blash.c
gcc -o exe3.exe sub1/main.c sub3/okEnoughForNow.c
As you can see, all exe's contain sub1/main.c as this is the main.c found first; Its path appears first on the vpath.
Joachim's Approach is definitive a simple, and very common solution. I would choose it as well if the programs in your subfolders are completely unrelated: You could have in each directory a makefile containing something like:
SRC := $(wildcard *.c)
%.exe : $(SRC)
gcc -o $# $^
Assuming, all .c files in each of your sub* shall be part of your program, and there are no subfolders in your sub's. Otherwise you'll need a different approach to scan your .c files, or specify them individually.
In your main makefile you can run for each subfolder a new instance of make, using those makefiles. Which gives you a main Makefile like:
# Get all subfolders name without trailing slash
PROGS := $(patsubst %/,%,$(wildcard */))
# Each subfolder can be made by calling make in
# that folder. A file prog.exe is created.
.PHONY : $(PROGS)
$(PROGS) :
$(MAKE) -C $# prog.exe
# Now every .exe depends on its subfolder, calls
# Make there - see rule above and copies the
# prog.exe from there into the root, with the name
# of the subfolder. (Alternatively you could use
# mv instead of cp)
%.exe : %
cp $</prog.exe $#
Assuming the name of your .exe is the same as the directory name and all subfolders are containing programs.
However, calling make from a running make instance (recursive make) can cause a real headache as soon as there are any dependencies between the generated files of the subfolders.
Another solution:
A different approach whithout using recursive make is having rules dynamically created. In that case your main Makefile could look like this. (I'm again assuming all subfolders are containing programs, all subfolders are flat, and all .c files in those subfolders are part of your program) This has the advantage that you'll have to maintain just one makefile, and there can be any dependency between the different programs. But still it has the disadvantage that you cannot manage your different programs seperately.
That's the complete makefile:
%.exe :
gcc -o $# $^
PROGS := $(patsubst %/,%,$(wildcard */))
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(wildcard $(P)/*.c)))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
.PHONY : all
all : $(addsuffix .exe,$(PROGS)
We're starting with a rule for compiling: Any .exe is generated by invoking gcc having all prerequisites as source files.
%.exe :
gcc -o $# $^
Then, next step is to obtain all "programs" by scanning for all subfolders and stripping off the trailing slash
PROGS := $(patsubst %/,%,$(wildcard */))
The next step is to create for each program a variable containig all Sources. Note the eval function expands, and passes everything to make as it has been written in the Makefile.
$(foreach P,$(PROGS),$(eval SRC_$(P) := $(wildcard $(P)/*.c)))
Thus the line above, with your sub1, sub2 and sub3 will become:
SRC_sub1 := $(wildcard sub1/*.c)
SRC_sub2 := $(wildcard sub2/*.c)
SRC_sub3 := $(wildcard sub3/*.c)
The eval function can even be used to create rules:
$(foreach P,$(PROGS),$(eval $(P).exe : $(SRC_$(P))))
So this will expand to (assuming the file structure in the example above)
sub1.exe : sub1/main.c sub1/foo.c sub1/bar.c
sub2.exe : sub2/main.c sub2/blish.c sub2/blash.c
sub3.exe : sub3/main.c sub3/okEnoughForNow.c
Now we have three rules without a recipe. Make says "if you have a rule without recipe, and an implicit rule that matches can be found, this rule is used with the prerequisites added from the rule that does not have the recipe" Thus, for those 3 rules the implicit rule of %.exe above applies.
Basically that's the trick. For your convenience you can add
.PHONY : all
all : $(addsuffix .exe,$(PROGS))
So make all makes everything.
Extension:
If you'd like to be able to make the .o files seperately as well, you could add one more implicit rule like:
%.o : %.c
gcc -c -o $# $<
and make your programs dependent on the .o rather than on the .c files:
$(foreach P,$(PROGS),$(eval OBJ_$(P) := $(patsubst %.c,%.o,$(wildcard $(P)/*.c))))
$(foreach P,$(PROGS),$(eval $(P).exe : $(OBJ_$(P))))
Then you'll have your .exe dependend on the .o that can be found by changing .c into .o after scanning all sources. Via the implicit rule chain %.o : %.c make will know what to do.

Including multiple sub directories in a make file

I am trying to write a makefile for a small scale application I wrote in C under Linux. Currently all my source files .c are in the top level directory and all header files in
an include directory. Here is the makefile I used for this.
IDIR =include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
_OBJ = main.o kernel.o user_app.o myargs.o ofp_msgs.o pkt_ip.o pkt_ether.o pkt_tcp.o pkt_udp.o pkt_icmp.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
#DEPS = ofp_msgs.h
$(ODIR)/%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
all: jam
jam: $(OBJ)
gcc -o $# $^ $(CFLAGS) -lpthread
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ jam
It works fine but what I want is that for example I make a sub directory called "Packet" and all my packet parsing files i-e "pkt_ip.c, pkt_tcp.c etc" should be in that directory where as their header files should still be in the top level directory i-t "toplevel/include". I did a bit of search and the most common way was to use recursive make. Then I see a lots of pages complaining about recursive make. Can anyone please help me in this as how to do this right ?
Thanks
I recommend checking out the method described in Recursive Make Considered Harmful.
I have used it on several projects (small to medium-size), and find it simpler to use, and easier to wrap ones head around, than the recursive approach.
Basically, you have a Makefile in the root directory which includes a (partial) makefile from each of the subdirectories:
SRC := main.c
MODULES := Packet lib etc
-include $(patsubst %, %/module.mk, $(MODULES))
OBJ := $(patsubst %.c, %.o, $(filter %.c,$(SRC)))
# (...)
Packet/module.mk:
SRC += Packet/pkt_ip.c Packet/pkt_tcp.c
LIBS += -lsome_library
These module makefiles can of course also define their own module targets, or special build requirements.
Unlike recursive make, "make" will only be invoked once, which for most use cases will lead to a faster build.
However, for most smaller projects neither build time nor complexity will be a major concern, so use what feels most natural.
there are several ways to do this but you can certainly use VPATH:=Packet to tell make to look for source files inside the 'Packet' directory. see make manual

Why does this makefile not apply includes to all objects?

This makefile does not behave as I expect. I want it to build .o files for each .c file in the current directory and subdirectories, and put them in a static library. However, it stops applying my $(INCS) after the first or second file. When it tries to build the second .o file, I don't see the -I paths in the build line and it complains about not finding a header file therein. Names have been genericized to simplify things. I'm using cygwin on Windows XP. I'm using an ARM cross compiler that is not under the cygwin tree. I based this makefile off an answer here. There are only about two dozen .c files so the overhead of creating the dependency files this way isn't a big deal.
# Project specific options
CC = my-cross-gcc
INCS := -I. -Iinc
INCS += -Imy/inc/path
CFLAGS := -Wall -fPIC -static -cross-compiler-specific-options
OUT := bin/libmylib.a
MKDIR:=mkdir -p
### Generic C makefile items below:
# Add .d to Make's recognized suffixes.
SUFFIXES += .d
NODEPS:=clean
#Find all the C files in this directory, recursively
SOURCES:=$(shell find . -name "*.c")
#These are the dependency files
DEPFILES:=$(patsubst %.c,%.d,$(SOURCES))
OBJS:= $(patsubst %.c,%.o,$(SOURCES))
#Don't create dependencies when we're cleaning, for instance
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
-include $(DEPFILES)
endif
#This is the rule for creating the dependency files
%.d: %.c
$(CC) $(INCS) $(CFLAGS) -MM -MT '$(patsubst %.c, %.o,$(patsubst %.c,%.o,$<))' $< > $#
#This rule does the compilation
%.o: %.c %.d %.h
$(CC) $(INCS) $(CFLAGS) -o $# -c $<
# Now create a static library
all: $(OBJS)
#$(MKDIR) bin
ar rcsvq $(OUT) $(OBJS)
clean:
rm -rf $(OBJS) $(OUT) $(DEPFILES)
Why does this makefile not apply $(INCS) when building subsequent .o files? How do I fix it? Output resembles this:
$ make all
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o firstfile.o -c firstfile.c
my-cross-gcc -I. -Iinc -Imy/inc/path -<compiler options> -o secondfile.o -c secondfile.c
my-cross-gcc -<compiler flags> -o thirdfile.o -c thirdfile.c
thirdfile.c:23:18: fatal error: myinc.h: No such file or directory
compilation terminated.
When I go to the command line and type in the gcc line to build thirdfile.o and use the -I paths, the object file is successfully built.
There are two different mechanisms for handling header files at work here:
When the compiler is trying to build foo.o from foo.c, and in foo.c it encounters #include "foo.h", it goes looking for foo.h. The -I flags tell it where to look. If it is invoked without the flags it needs to find foo.h, it will complain and die.
When Make is trying to build foo.o, and considering which rule to use, it looks at the prerequisites. The prerequisites for your rule are foo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know where foo.h is? Note that the compiler flag inside one of its commands is of no use-- it won't make any deductions about that. If it can't find (and doesn't know how to make) a prerequisite, it will reject that rule and look for another one, such as the implicit %.o rule which knows nothing about your $(INCS) variable, and that leads you to the problem described above.
If this is the problem (and you can check by looking at the locations of the headers and doing some experiments) you have a couple of options:
A) You can use the implicit rule, and it's variables. Just add INCS to CFLAGS and you'll probably get the results you want. This tells the compiler what to do, but it still leaves Make in the dark about the dependencies, so you'll probably have to double-check that your dependency handling is correct.
B) You can tell Make where to find the header files:
vpath %.h inc my/inc/path
(You may notice that this is redundant with your INCS variable, and redundancy is bad-- you can eliminate this redundancy, but I urge you to get it working first.)
I'm going to guess that you have files named firstfile.h, secondfile.h, but no file named thirdfile.h?
I would then suppose that make cannot use the rule you gave it because and can't find or build the .h file. So it decides to use the default implicit rule instead.
All I can imagine is that for "thirdfile" your depfile is somehow out-of-date or corrupt. Perhaps it is bad enough that it's confusing make into calling some other default target.

Resources