1

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.

Community
  • 1
  • 1
jasper77
  • 1,553
  • 5
  • 19
  • 31
  • Is there by any chance a `firstfile.h` and a `secondfile.h` but no `thirdfile.h`? – Ben Jackson Jul 05 '11 at 20:52
  • 1
    Not related to your question, but you don't seem to be including the dependency files anywhere, making them useless. – interjay Jul 05 '11 at 20:55
  • interjay, I seem to have oversimplified the makefile I typed in. I'll add those lines back above. – jasper77 Jul 05 '11 at 21:48
  • 3
    Please don't post fake examples. Simplify your makefile as much as possible, but then test to make sure it still exhibits the problem and post *real* output. For instance, your example output doesn't show creation of the .d files, but I don't know if that's because of a problem or because you edited it. – interjay Jul 05 '11 at 22:04
  • I second @interjay's request: eliminate all the irrelevant stuff (dependencies, etc.), and boil your makefile down to the simplest version possible that still causes a problem. – Oliver Charlesworth Jul 06 '11 at 00:45

3 Answers3

3

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.)

Beta
  • 96,650
  • 16
  • 149
  • 150
  • You nailed it. When it got to thirdfile, the makefile was invoking the implicit rule. I added INCS to CFLAGS and then did not need the explicit %.o rule any more, and it works beautifully. Thank you. – jasper77 Jul 06 '11 at 13:51
2

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.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • These header files do indeed exist with the paths specified with the -I flag. The difference is that with thirdfile.c the gcc line omits the -I information. If I type in the line by hand, with the -I parts, the .o file builds just fine. – jasper77 Jul 05 '11 at 21:42
1

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.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138