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"$@" "$<"
-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
A dependency file is a text file of legal makefile syntax. For example, if
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:
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
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.