Search code examples
csedmakefile

Understand sed function call in a makefile


I came across the following makefile in a software:

CFLAGS = -O6 -g -Wall
CC     = gcc
VPATH  = ./code

LIB_MOD    = common arith inout log
valid_MOD  = valid $(LIB_MOD)
xporta_MOD = porta four_mot portsort largecalc mp $(LIB_MOD)
ALL_MOD    = $(valid_MOD) $(xporta_MOD)

all: xporta valid

valid: $(valid_MOD:%=%.d) $(valid_MOD:%=%.o) 
    $(CC) -o bin/$@ $(valid_MOD:%=%.o)

xporta: $(xporta_MOD:%=%.d) $(xporta_MOD:%=%.o) 
    $(CC) -o bin/$@ $(xporta_MOD:%=%.o)

clean:
    rm -f *.o bin/xporta bin/valid

%.d: %.c
    $(SHELL) -ec 'gcc -MM $(CPPFLAGS) $< \
        | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \
        [ -s $@ ] || rm -f $@'

include $(ALL_MOD:%=%.d)

While I am able to understand the other parts of it, I am unable to understand what the following line does towards the bottom of the makefile:

| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \ [ -s $@ ] || rm -f $@'

What does this expand to and what is the equivalent syntax without the sed function call?

This is an old software written in C and I am trying to rewrite the makefile into a format that is more verbose so that I can understand what is going on.

This is a cross post from /r/c_programming I made where I could not get a specific answer.


Solution

  • The actual sed command is:

    sed 's/\($*\)\.o[ :]*/\1.o $@ : /g'
    

    '\'' is needed because this is inside the argument to $(SHELL) -ec, which is a single-quoted string; it terminates that quote, adds a literal quote, then continues the quoted string.

    $* and $@ are automatic variables that get replaced by make.

    • $* is replaced with the stem of the rule, which is the part of the filename that matched % in the rule.
    • $@ is replace with the target of the pattern.

    So if the rule is being used to create foo.d, the stem is foo and the target is foo.d. Therefore, the sed command becomes

    sed 's/\(foo\)\.o[ :]*/\1.o foo.d : /g'
    

    This basically finds any instances of foo.o : in the output of gcc -MM $< and inserts foo.d between foo.o and :.

    gcc -MM is used to create a file containing makefile rules describing all the preprocessor dependencies in the C file. This adds a corresponding .d file to any .o targets that it generates.