user2808264
user2808264

Reputation: 569

Makefile Explanation

I am new to makefiles and trying to understand some code:

%.o:%.c
    $(CC) $^ -c -Wall
    $(CC) -MM $*.c > $*.dep
    $(OBJECTDUMP) -d -M intel -S $@
    @mv -f $*.dep $*.dep.tmp
    @sed -e 's|.*:|$*.o:|' < $*.dep.tmp > $*.dep
    @sed -e 's/.*://' -e 's/\\$$//' < $*.dep.tmp | fmt -1 | \
      sed -e 's/^ *//' -e 's/$$/:/' >> $*.dep
    @rm -f $*.dep.tmp

Can someone please explain what the last 5 lines of code are doing?

Upvotes: 1

Views: 240

Answers (2)

Beta
Beta

Reputation: 99094

The purpose of those lines is to deal with a problem with dependency handling.

Suppose you have a header file bar.h, and a source file foo.c that contains the line

#include "bar.h"

Now generate the dependency file:

$(CC) -MM $*.c > $*.dep

The file foo.dep now contains:

foo.o: foo.cc bar.h

Wonderful. I'm sure the makefile has a line like -include *.dep, so now Make will handle foo's dependencies correctly. But now suppose you edit foo.c, remove that #include line, and delete the no-longer-needed bar.h. The next time you try to make foo, Make will read the old foo.dep which calls for bar.h, see that there is no such header and no known way to build it, and abort. Make will not know that the header is not needed until it rebuilds the dep file, which it cannot do because the header is missing and Make thinks it is needed.

One solution is to delete foo.dep when this situation arises (before Make aborts, if possible). Another is to add a line to foo.dep:

bar.h:

which will assuage Make's fears about the missing header. The first approach requires human attention, the second can be automated:

@mv -f $*.dep $*.dep.tmp # rename foo.dep -> foo.dep.tmp
@sed -e 's|.*:|$*.o:|' < $*.dep.tmp > $*.dep # this does nothing and appears to be vestigal
@sed -e 's/.*://' \ # remove the target, leaving foo.c bar.h
  -e 's/\\$$//' \  # remove line continuation marks, if any
  < $*.dep.tmp | fmt -1 | \ # put each word on its own line
  sed -e 's/^ *//' \ # remove leading whitespace
  -e 's/$$/:/' \ # add a colon to the end of each line (making it a rule)
  >> $*.dep # save the result as foo.dep
@rm -f $*.dep.tmp  # delete the temporary file

Upvotes: 4

Jonathan Leffler
Jonathan Leffler

Reputation: 753725

$* corresponds roughly to the % in the first line.

  • The @mv line moves the old basename.dep file to basename.dep.tmp
  • The first @sed line edits what's in the basename.dep.tmp, replacing anything up to a colon with basename.o: (because the $* is expanded by make, not the shell).
  • The second @sed line and the following line do some more editing — appending another variant of the basename.dep.tmp file to the end of basename.dep.
  • The @rm line removes the temporary basename.dep.tmp file.

A more thorough analysis of the second sed sequence requires more detailed knowledge of what's in the .dep file and exactly what fmt -1 does for you.

However, it seems that the goal is to update the dependencies that apply to the source file, based on the information from the compiler plus massaging it in a way to suit the programmer. The why is not clear to me.

Upvotes: 3

Related Questions