I was taking a look through Makefile documentation when I found:
Target-specific Variable ValuesTarget specific variables allow you to use a general build rule, yet still have target specific variables (CFLAGS, CXXFLAGS, etc.) when applying those rules. They give the general pattern as:
target … : variable-assignment
Example:
prog : CFLAGS = -g
prog : prog.o foo.o bar.o
Here the output
prog is built from three object files. Those three object files are then built using the built-in implicit rules to build .o files from .c files. Target specific variables are inherited when building dependencies, so this value is passed down to the built-in implicit rule. The built-in implicit rule references the
CFLAGS variable, which is set to
-g (generate debug info).
This is perhaps a surprisingly obvious feature in hindsight. Many of the OPU repositories have Makefiles with duplication of rules using different variable names to address the very problem this feature solves. For example, the difference between building the main project versus building the unit test project:
COMPILE.cpp = $(CXX) $(OUTPUT_OPTION) $(DEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(TARGET_ARCH) -c $<
$(OBJS): $(INTDIR)/%.o : $(SRCDIR)/%.cpp $(INTDIR)/%.d | build-folder
$(COMPILE.cpp)
$(POSTCOMPILE)
# ...
TESTCOMPILE.cpp = $(CXX) $(OUTPUT_OPTION) $(TESTCPPFLAGS) $(DEPFLAGS) $(CXXFLAGS) $(TARGET_ARCH) -c $<
$(TESTOBJS): $(TESTINTDIR)/%.o : $(TESTDIR)/%.cpp $(TESTINTDIR)/%.d | test-build-folder
$(TESTCOMPILE.cpp)
$(POSTCOMPILE)
The two rules are basically doing the same thing, but were written twice to account for the different variables. The main project rule expands to use the
CPPFLAGS variable, while the test project rule expands to use the
TESTCPPFLAGS variable. The main difference being, the test project adds an include folder for the main project so it can find the header files.
By using the target-specific variable feature of Makefiles, these rules can potentially be shortened into one, allowing for simpler and shorter Makefiles.