2

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.

asked Jul 14, 2016 at 7:54

1 Answer 1

3

%.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)
answered Jul 14, 2016 at 13:56
Sign up to request clarification or add additional context in comments.

1 Comment

Excellent. Thanks you!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.