Makefile, header dependencies
DependenciesMakefileHeader FilesDependencies Problem Overview
Let's say I have a makefile with the rule
%.o: %.c
gcc -Wall -Iinclude ...
I want *.o to be rebuilt whenever a header file changes. Rather than work out a list of dependencies, whenever any header file in /include
changes, then all objects in the dir must be rebuilt.
I can't think of a nice way to change the rule to accomodate this, I'm open to suggestions. Bonus points if the list of headers doesn't have to be hard-coded
Dependencies Solutions
Solution 1 - Dependencies
If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:
depend: .depend
.depend: $(SRCS)
rm -f "$@"
$(CC) $(CFLAGS) -MM $^ -MF "$@"
include .depend
or
depend: .depend
.depend: $(SRCS)
rm -f "$@"
$(CC) $(CFLAGS) -MM $^ > "$@"
include .depend
where SRCS
is a variable pointing to your entire list of source files.
There is also the tool makedepend
, but I never liked it as much as gcc -MM
Solution 2 - Dependencies
Most answers are surprisingly complicated or erroneous. However simple and robust examples have been posted elsewhere [codereview]. Admittedly the options provided by the gnu preprocessor are a bit confusing. However, the removal of all directories from the build target with -MM
is documented and not a bug [gpp]:
> By default CPP takes the name of the main input file, deletes any > directory components and any file suffix such as ‘.c’, and appends the > platform's usual object suffix.
The (somewhat newer) -MMD
option is probably what you want. For completeness an example of a makefile that supports multiple src dirs and build dirs with some comments. For a simple version without build dirs see [codereview].
CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow
# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build
# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)
# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)
# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)
# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
# Create build directories - same structure as sources.
mkdir -p $(@D)
# Just link all the object files.
$(CXX) $(CXX_FLAGS) $^ -o $@
# Include all .d files
-include $(DEP)
# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
mkdir -p $(@D)
# The -MMD flags additionaly creates a .d file with
# the same name as the .o file.
$(CXX) $(CXX_FLAGS) -MMD -c $< -o $@
.PHONY : clean
clean :
# This should remove all generated files.
-rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)
This method works because if there are multiple dependency lines for a single target, the dependencies are simply joined, e.g.:
a.o: a.h
a.o: a.c
./cmd
is equivalent to:
a.o: a.c a.h
./cmd
as mentioned at: https://stackoverflow.com/questions/6215287/makefile-multiple-dependency-lines-for-a-single-target
Solution 3 - Dependencies
As I posted here gcc can create dependencies and compile at the same time:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<
The '-MF' parameter specifies a file to store the dependencies in.
The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).
Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated file.d will still contain file.o, not obj/_file__c.o.
Solution 4 - Dependencies
How about something like:
includes = $(wildcard include/*.h)
%.o: %.c ${includes}
gcc -Wall -Iinclude ...
You could also use the wildcards directly, but I tend to find I need them in more than one place.
Note that this only works well on small projects, since it assumes that every object file depends on every header file.
Solution 5 - Dependencies
Martin's solution above works great, but does not handle .o files that reside in subdirectories. Godric points out that the -MT flag takes care of that problem, but it simultaneously prevents the .o file from being written correctly. The following will take care of both of those problems:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) -o $@ $<
Solution 6 - Dependencies
This will do the job just fine , and even handle subdirs being specified:
$(CC) $(CFLAGS) -MD -o $@ $<
tested it with gcc 4.8.3
Solution 7 - Dependencies
Here's a two-liner:
CPPFLAGS = -MMD
-include $(OBJS:.c=.d)
This works with the default make recipe, as long as you have a list of all your object files in OBJS
.
Solution 8 - Dependencies
A slightly modified version of Sophie's answer which allows to output the *.d files to a different folder (I will only paste the interesting part that generates the dependency files):
$(OBJDIR)/%.o: %.cpp
# Generate dependency file
mkdir -p $(@D:$(OBJDIR)%=$(DEPDIR)%)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM -MT $@ $< -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
# Generate object file
mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
Note that the parameter
-MT $@
is used to ensure that the targets (i.e. the object file names) in the generated *.d files contain the full path to the *.o files and not just the file name.
I don't know why this parameter is NOT needed when using -MMD in combination with -c (as in Sophie's version). In this combination it seems to write the full path of the *.o files into the *.d files. Without this combination, -MMD also writes only the pure file names without any directory components into the *.d files. Maybe somebody knows why -MMD writes the full path when combined with -c. I have not found any hint in the g++ man page.
Solution 9 - Dependencies
I prefer this solution, over the accepted answer by Michael Williamson, it catches changes to sources+inline files, then sources+headers, and finally sources only. Advantage here is that the whole library is not recompiled if only a a few changes are made. Not a huge consideration for a project with a couple of files, bur if you have 10 or a 100 sources, you will notice the difference.
COMMAND= gcc -Wall -Iinclude ...
%.o: %.cpp %.inl
$(COMMAND)
%.o: %.cpp %.hpp
$(COMMAND)
%.o: %.cpp
$(COMMAND)
Solution 10 - Dependencies
The following works for me:
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
%.o: %.cpp
$(CXX) $(CFLAGS) -MMD -c -o $@ $<