Rate this page

Flattr this

Automatically generate makefile dependencies

Tested on

Debian (Etch, Lenny, Squeeze)
Ubuntu (Lucid, Maverick, Natty, Precise, Trusty)

Objective

To automatically list dependencies between the files in a body of source code, in a form suitable for use within a makefile

Background

When make builds a program it uses timestamps to determine which files need to be rebuilt and which do not. In order to do this it needs to know how the source, intermediate and executable files depend on each other. That information is provided by the makefile in the form of rules. For example, the line:

main.o: main.c foo.h bar.h

indicates that the object file main.o depends on the source file main.c and on the header files foo.h and bar.h.

Creating these rules manually is both tedious and error-prone. Mistakes can be difficult to diagnose, because they result in a compiled program that does not correspond to the source code. For these reasons, the use of an automated mechanism for identifying dependencies is highly desirable for all but the simplest of programs.

Scenario

Suppose you have a makefile which compiles all files with the extension .c that are located in the same directory, then links them into an executable called hello_world:

SRC = $(wildcard *.c)

hello_world: $(SRC:%.c=%.o)
	$(LD) -o $@ $^

This will correctly rebuild the executable when one of the .c files is changed, but not when an .h file included by one of the .c files is changed.

You wish to rectify this deficiency without having to explicitly specify which headers are used by which source files. You are building the program using GCC and GNU Make.

Method

GCC has the ability to create lists of dependencies as a program is being compiled. This feature is invoked using:

Including system headers is the more robust alternative, however they change rarely and can greatly increase the number of dependencies listed.

By default the dependency list is written to a file with the extension .d and is in the correct format for inclusion in a makefile. All you need do to automate the process is:

A useful embellishment is to invoke the -MP option, which creates an empty rule for generating each dependency. This suppresses the errors that would otherwise occur when a header file is deleted or renamed.

Because -MD and -MP are preprocessor options, the standard method for setting them within a makefile is to append them to CPPFLAGS:

CPPFLAGS += -MD -MP

The include directive must list the dependency files. Most makefiles will already have a list of source or object files, from which the names of the dependency files can be obtained by substitution. In this particular example it is possible to use the variable SRC which is a list of source files:

-include $(SRC:%.c=%.d)

The purpose of the initial hyphen is to suppress the error messages that would otherwise appear when the dependency files do not already exist.

The include directive must not precede the default target, otherwise the first rule to be included would supercede the default target. A simple way to prevent this from happening is to place the include directive at the end of the makefile.

Do not add a rule for explicitly building the dependency files. The method presented here will build or rebuild those files when needed without them being an explicit part of the dependency graph, so adding a rule would merely create unnecessary work for make. The way this is achieved is subtle but effective:

Here the complete makefile for the scenario described:

CPPFLAGS += -MD -MP

SRC = $(wildcard *.c)

hello_world: $(SRC:%.c=%.o)
	$(LD) -o $@ $^

-include $(SRC:%.c=%.d)

Alternatives

Use the -M option with sed

The GNU Make manual recommends creating the dependency files explicitly using a pattern rule:

%.d: %.c
	@set -e; rm -f $@; \
	$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
	sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

This has the advantage of using the -M option in place of -MD, the former being more widely supported by compilers other than GCC. Disadvantages are that:

Use GNU Automake

Automake is a tool for automatically generating portable makefiles that conform to the GNU Coding Standards. It is normally used in conjunction with Autoconf, and often with Libtool. It generates dependencies using the compiler if it can, or using makedepend if not.

Tags: make