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.ofromfoo.c, and infoo.cit encounters#include "foo.h", it goes looking forfoo.h. The-Iflags tell it where to look. If it is invoked without the flags it needs to findfoo.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 arefoo.c foo.d foo.h, so it goes looking for those prerequisites. How is it to know wherefoo.his? 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%.orule 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
INCStoCFLAGSand 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:
(You may notice that this is redundant with your
INCSvariable, and redundancy is bad– you can eliminate this redundancy, but I urge you to get it working first.)