Gaston
Gaston

Reputation: 629

Create dependency files in Makefile

I am using a Makefile including a rule to create a dependency file. The compiler is GCC.

%.d: %.c
    mkdir -p $(@D)
    $(CC) $(CFLAGS) $(CPPFLAGS) -M $< | \
    sed 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > [email protected]
    mv [email protected] $@

I am quite new in Makefile technique and I find it a little bit difficult to understand this rule composed of a mixture of several options.
Can somebody give a simple explanation how this rule works? Thanks in advance.

Upvotes: 2

Views: 3389

Answers (1)

user657267
user657267

Reputation: 20990

%.d: %.c

All files ending in .d can be made using this rule, as long as there is a .c file with the same directory and stem relative to the current directory or one of the vpaths.

mkdir -p $(@D)

Create the topmost and all intermediate directories for $(@D), which is an automatic make variable that expands to the directory part of the current target.

$(CC) $(CFLAGS) $(CPPFLAGS) -M $< | \

Invoke the C compiler on the first prerequisite (whatever.c) and tell it to output a list of make dependencies to the standard output. Pipe this output to

sed 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > [email protected]

sed. The rules in the output will have the same path as the source files, but whoever wrote this rule wants the objects files in a different directory so we need sed to substitute the paths.

Sed captures any rules with targets ending with .o that match $(notdir $*). $* is another automatic variable that expands to the pattern that matches % in the current rule, and notdir will strip any directory parts so you're left with the filename stem with no extension.

Sed then prepends $(dir $@) to the object file target, which is the same thing as $(@D) we saw above, and adds the dependency file itself ($@) as a target of the same prerequisites. This output is redirected to a file with the name of the current target + .tmp.

mv [email protected] $@

Moves the previous file to the real target of the rule.


Side note: if you don't mind the dependency files being generated in the same directory as the object files then these recipes are outdated, you can achieve the same thing with something like:

sources := src/somefile1.c src/somefile2.c
objects := $(sources:src/%.c=obj/%.o)
deps    := $(objects:.o=.d)

CFLAGS := -MMD -MP

.PHONY: all
all $(objects)

$(objects): obj/%.o: src/%.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

-include $(deps)

Upvotes: 3

Related Questions