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.
1 Answer 1
%.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)