GNU Makefile surprise

make

I am try to build a simple, two-stage project Makefile with GNU make.

The logic I want to follow is

  1. First I construct the dependencies (by gcc -M)
  2. I include the generated .dep files into the Makefile in a second stage build.

The relevant part of my project is the following:

MAKEDEP:=$(CXX) $(CXXFLAGS) -M
ALL_SRCS:=$(ALL_OBJS:.o:.cc)
CXX_DEPS:=$(patsubst %.o,.%.dep,$(ALL_OBJS))

-include $(CXX_DEPS)

%.o: %.cc .%.dep
        $(CXX) $(CXXFLAGS) -c -o $@ $<

.%.dep: %.cc
        $(MAKEDEP) -o $@ $<

clean:
        $(RM) -vf $(ALL_OBJS) $(ALL_LIBS) $(ALL_APPS)

dep: $(CXX_DEPS)

Everything works fine, with a single exception: if I run a make clean, it rebuilds the dependencies! As if a clean: dep line would exist instead of a simple clean: line:

$ make clean
g++ -Wall -std=c++11 -M -o .file1.dep file1.cc
g++ -Wall -std=c++11 -M -o .file2.dep file2.cc
g++ -Wall -std=c++11 -M -o .file3.dep file3.cc
rm -vf file1.o file2.o file3.o app
$

What is in the background? Why does it need to rebuild the dependencies before a cleanup? I didn't give such a dependency.

Best Answer

Because you have asked make to include the files, it then follows the rules to build them.

Now I will try to remember how I solved it on my project:

First realise that we do not care about extra dependencies the first time, as we have to build the object file anyway.

Then if we add (or remove) dependencies we must change something that we already depend on ( the .cc or one of the existing .h ).

In summary we do not need the full list of dependencies for the current state, the dependencies for the previous state are good enough. Therefore we can build the .deps at the same time as the .o (this is also quicker as only one CC pass is needed).

[the next bit I am a bit less certain about]

Now we need to bootstrap the dependencies: Write a rule to create some dummy (empty) .dep files (whenever a .cc is created (this can be very quick)).

Now we still have to create these dummy .dep files, and then clean them. If you avoid recursive make, then you should not need clean to work around bugs (only needed to clean-up to save disk space).

The last step was to add one level of recursion (remember recursive make (usually) is considered harmful http://lcgapp.cern.ch/project/architecture/recursive_make.pdf )

Write a simple makefile for clean rules, that calls make on another makefile for any rule it can not do.

You may only need this last step, but I will not delete the beginning of the answer, as it shows you how to improve the makefile.

Related Question