23

I'm using GCC to generate a dependency file, but my build rules put the output into a subdirectory. Is there a way to tell GCC to put my subdirectory prefix in the dependency file it generates for me?

gcc $(INCLUDES) -E -MM $(CFLAGS) $(SRC) >>$(DEP)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
KPexEA
  • 16,560
  • 16
  • 61
  • 78

7 Answers7

44

I'm assuming you're using GNU Make and GCC. First add a variable to hold your list of dependency files. Assuming you already have one that lists all our sources:

SRCS = \
        main.c \
        foo.c \
        stuff/bar.c

DEPS = $(SRCS:.c=.d)

Then include the generated dependencies in the makefile:

include $(DEPS)

Then add this pattern rule:

# automatically generate dependency rules

%.d : %.c
        $(CC) $(CCFLAGS) -MF"$@" -MG -MM -MP -MT"$@" -MT"$(<:.c=.o)" "$<"

# -MF  write the generated dependency rule to a file
# -MG  assume missing headers will be generated and don't stop with an error
# -MM  generate dependency rule for prerequisite, skipping system headers
# -MP  add phony target for each header to prevent errors when header is missing
# -MT  add a target to the generated dependency

"$@" is the target (the thing on the left side of the : ), "$<" is the prerequisite (the thing on the right side of the : ). The expression "$(<:.c=.o)" replaces the .c extension with .o.

The trick here is to generate the rule with two targets by adding -MT twice; this makes both the .o file and the .d file depend on the source file and its headers; that way the dependency file gets automatically regenerated whenever any of the corresponding .c or .h files are changed.

The -MG and -MP options keep make from freaking out if a header file is missing.

Don McCaughey
  • 9,532
  • 3
  • 30
  • 36
  • 3
    For me, on gcc 4.1.2, gmake 3.8.1, if a header file does not exist the recipe '$(CC) $(CCFLAGS) -MF"$@" -MG -MM -MP -MT"$@" -MT"$(<:.c=.o)" "$<"' infinite loops. // Removing the -MP option stops the infinite loop. – Krazy Glew Apr 30 '12 at 23:32
23

The answer is in the GCC manual: use the -MT flag.

-MT target

Change the target of the rule emitted by dependency generation. By default CPP takes the name of the main input file, deletes any directory components and any file suffix such as .c, and appends the platform's usual object suffix. The result is the target.

An -MT option will set the target to be exactly the string you specify. If you want multiple targets, you can specify them as a single argument to -MT, or use multiple -MT options.

For example, -MT '$(objpfx)foo.o' might give

$(objpfx)foo.o: foo.c
LogicStuff
  • 19,397
  • 6
  • 54
  • 74
bk1e
  • 23,871
  • 6
  • 54
  • 65
  • `-MT` is not available for my gcc 2.9.5, guest should be available 3.x.x above – checksum Nov 28 '13 at 09:34
  • 2
    @checksum: ... wasn't [2.9.5](http://gcc.gnu.org/gcc-2.95/) was released >14 years ago? – Mechanical snail Dec 10 '13 at 06:40
  • Yup, I found that out when maintaining a legacy code with out of date build platform. :| It is still using 2.9.1.57 (was call egcs instead of gcc) and the good thing is it has minimum dependency with 4 files only and less than 700k. :) The bad thing is it has no `-MT` support. :( – checksum Dec 10 '13 at 06:57
12

You may like this briefer version of Don McCaughey's answer:

SRCS = \
    main.c \
    foo.c \
    stuff/bar.c

DEPS = $(SRCS:.c=.d)

Add -include $(DEPS) note the - prefix, which silences errors if the .d files don't yet exist.

There's no need for a separate pattern rule to generate the dependency files. Simply add -MD or -MMD to your normal compilation line, and the .d files get generated at the same time your source files are compiled. For example:

%.o: %.c
     gcc $(INCLUDE) -MMD -c $< -o $@

# -MD can be used to generate a dependency output file as a side-effect of the compilation process.
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steve Pitchers
  • 7,088
  • 5
  • 41
  • 41
  • 2
    By the way, be sure to avoid placing the "include" above your first target. It's logical to place it at the bottom of the Makefile, because that was always the traditional place to put dependencies, back when they had to be crafted by hand! – Steve Pitchers Jun 06 '13 at 18:09
3

Detailing on DGentry's answer, this has worked well for me:

.depend: $(SOURCES)
    $(CC) $(CFLAGS) -MM $(SOURCES) | sed 's|[a-zA-Z0-9_-]*\.o|$(OBJDIR)/&|' > ./.depend

This also works in the case where there is only one dependency file that contains the dependency rules for all source files.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rsp1984
  • 1,877
  • 21
  • 23
2

Ok, just to make sure I've got the question right: I'm assuming you have test.c which includes test.h, and you want to generate subdir/test.d (while not generating subdir/test.o) where subdir/test.d contains

subdir/test.o: test.c test.h

rather than

test.o: test.c test.h

which is what you get right now. Is that right?

I was not able to come up with an easy way to do exactly what you're asking for. However, looking at Dependency Generation Improvements, if you want to create the .d file while you generate the .o file, you can use:

gcc $(INCLUDES) -MMD $(CFLAGS) $(SRC) -o $(SUBDIR)/$(OBJ)

(Given SRC=test.c, SUBDIR=subdir, and OBJ=test.o.) This will create both subdir/test.o and subdir/test.d, where subdir/test.d contains the desired output as above.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

If there is an argument to GCC to do this, I don't know what it is. We end up piping the dependency output through sed to rewrite all occurrences of <blah>.o as ${OBJDIR}/<blah>.o.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DGentry
  • 16,111
  • 8
  • 50
  • 66
0
  1. [GNU] make gets angry if you don't place the output in the current directory. You should really run make from the build directory, and use the VPATH make variable to locate the source code. If you lie to a compiler, sooner or later it will take its revenge.

  2. If you insist on generating your objects and dependencies in some other directory, you need to use the -o argument, as answered by Emile.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
florin
  • 13,986
  • 6
  • 46
  • 47