Reputation: 629
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
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