Preface
You are using $(CPP)
and $(CPPFLAGS)
... that's for the preprocessor. What you want to use is $(CXX)
and $(CXXFLAGS)
, for the C++ compiler.
The following assumes GNU make and a GCC-compatible compiler (clang will do).
Step One
Use generic rules, not one per source file -- the latter will very quickly become unwieldly, and is very error-prone.
Either list your source files manually...
SOURCES := parking.cpp utils.cpp InputStateContext.cpp InputState.cpp InputStateA.cpp
...or have all source files listed automatically:
SOURCES := $(wildcard *.cpp)
You also need a list of the object files (one .o per .cpp):
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
Now provide a rule for the executable, depending on all the object files, with a command that links all those object files ($^
) into that same executable ($@
)...
parking: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ -o $@
...and a generic rule on how to generate individual object files (%.o
) from the corresponding source file (%.cpp
):
%.o: %.cpp Makefile
$(CXX) $(CXXFLAGS) &< -o $@
Making the object file depend on the Makefile as well ensures that changes in the Makefile, e.g. $(CXXFLAGS)
, trigger a recompile as well. $<
resolves to the first dependency (the source file).
We will extend this rule later.
Step Two
We will have a dependency file for each source file. (Bear with me here.) We can generate a list of those files the same as we did for object files...
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
...and include them into the Makefile:
-include $(DEPENDS)
The -
there means that make
will not complain if those files do not exist -- because they do not, at this point.
Step Three (Core of the answer to your question)
Have the compiler generate those dependency files for us -- because it knows best. For that, we extend our object file build rule:
%.o: %.cpp Makefile
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@
The -MMD
flag generates the dependency file (%.d
), which will hold (in Makefile syntax) rules making the generated file (%.o
in this case) depend on the source file and any non-system headers it includes. That means the object file gets recreated automatically whenever relevant sources are touched. If you want to also depend on system headers (i.e., checking them for updates on each compile), use -MD
instead.
The -MP
option adds empty dummy rules, which avoid errors should header files be removed from the filesystem.
At the first compile run, there is no dependency information -- but since the object files don't exist either, the compiler must run anyway. For every subsequent run, make
will include the auto-generated dependency files, and "do the right thing".
All-In-One (with some more syntactic sugar added):
SOURCES := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: parking
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
parking: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $@
-include $(DEPENDS)
%.o: %.cpp Makefile
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $@