Identifying Dependencies Automatically

Tags:

GCC has a set of preprocessor options intended for use with GNU Make, the -M options. The gcc -M options generate a set of include-file names on which a source file depends, in the form of a GNU Make rule. I use g++ -MM in a Makefile rule to identify dependencies for my .cpp files. The -MM option omits system header files from the dependency list.

# Add .d to Make's recognized suffixes.
SUFFIXES += .d
 
# Generate file.d from file.cpp.
%.d: %.cpp
        $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -MM $< > $@

This rule is just the built-in rule for generating .o files from .cpp files, but using -MM instead of -c. The built-in rule is exposed by GNU Make's -p, as discussed in the section called “The Makefile of No Makefile”.

For example, for a file ../src/RNG.cpp that includes ../include/RNG.h, gcc/g++ -MM produces:

RNG.o: ../src/RNG.cpp ../include/RNG.h

By including this in my Makefile I tell GNU Make to rebuild RNG.o whenever either ../src/RNG.cpp or ../include/RNG.h changes. No explicit command is specified, so GNU Make will use its built-in rule for compiling RNG.o from RNG.cpp.

GNU Make can keep .d files current with the .cpp files as well. To do this I define a target set of dependency file names from my source file names, using the GNU Make wildcard function. Next I include all the .d files in my GNU Makefile, but only if I am not doing a make clean or make distclean:

sources = $(wildcard *.cpp)
dependencies = $(sources:.cpp=.d)
 
ifeq (0, $(words $(findstring $(MAKECMDGOALS), clean distclean)))
include $(dependencies)
endif

If GNU Make cannot find a .d file given as an include argument it will try to (re-)make it. When it does, it uses the rule shown previously for creating file.d from file.cpp, invoking g++ to parse the C++ files for their list of include files.