Automatic makefile dependencies

For years I’ve known that some compilers can generate dependency files — text files that can be included in a Makefile to declare dependencies — but I’ve only lately cracked the nut on how to do this.  My attempts at Googling the solution to this did not turn up a simple example, so I decided to write this note on the subject.

First off, here’s the goal: after the initial build of a project, if a header file in the project is subsequently changed, then re-executing make should rebuild each (but only!) object file that depends on the header.

(Rebuilding from scratch is a waste of time, but imagine the potential frustration if dependent files are not rebuilt.)

The manual approach would be to add dependency lines with no recipes for every header in a source file:

foo.o:    includes/foo.h includes/bar.h

objs/%.o: src/%.cpp
    g++ -c -Iincludes  -o"$@" "$<"

Clearly (rignt?), the above will not scale, especially since it depends on the developer updating the build script every time he/she adds or deletes an “#include” directive.  But g++ and no doubt other compilers support the optional to generate snippets of makefile with the correct and complete dependency declarations.  Here’s how:

objs/%.o: src/%.cpp
    g++ -c -Iinlcudes -MMD -MF"$(@:objs/%.o=deps/%.d)" -o"$@" "$<"

The -MMD option instructs g++ to create dependency files, but not for system headers. (If the system header files have changed, I recommend rebuilding your project from scratch.) The -MF option specifies the name of the dependency file. In the example above, compiling source file src/foo.cpp would generate objs/foo.o and deps/foo.d.

A dependency file is a text file of legal makefile syntax.  For example, if foo.cpp included foo.h and bar.h, then foo.d would be

objs/foo.o: src/foo.cpp includes/foo.h includes/bar.h

To make use of the generated dependency files,  assuming they are deposited in directory deps, add the following line to your Makefile:

-include deps/*

The leading dash instructs make to simply ignore an include file that does not exist or cannot be remade.

Finally, I like to have the clean target remove the *.d files along with the *.o files and executable. And if you are using git, you will probably want to add line *.d to .gitignore

A simple makefile that illustrates the use of generated dependencies can be found here.  It is part of a project that was built on Linux Mint 17.2 Rafaela, using g++ 4.9.3 and GNU Make 3.81.

Advertisements

2 thoughts on “Automatic makefile dependencies

  1. Ashley Roeckelein says:

    Thanks for the tip Bob!

    How about a slight simplification: use a single “build” dir/tree for both .o’s and .d’s instead of objs/ and deps/ (just a single build artifacts dir/tree to remember to clean / be distracted by), then a little change:

    -include $(shell find ./build -name *.d)

    Anyway, nice post – finally got me running auto dependencies now, after being lazy for so long 😉

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s