Special Variables in Makefile - Default Target and Automatic Variables

Tips about some special variables used in makefile: automatic variables, $@, $<, $^; wildcard placeholder % in targets and dependencies and $* in recipe; and .DEFAULT_GOAL.

automatic variable
A variable whose value is automatically redefined for each rule. Make’s automatic variables include $@, which holds the rule’s target, $^, which holds its dependencies, and, $<, which holds the first of its dependencies, and $*, which holds the stem with witch the pattern was matched. Automatic variables are typically used in pattern rules.

The first three are not hard to understand but not easy to remember clearly. The last one needs to be elaborated with the wildcard placeholder %.
The wildcard placeholder % takes part in the composition of a pattern. Its function is like (.+) in regular expression. If Make finds a dependency matching the pattern, then the “group” caught in the pattern is substituted into the target. For example,

%.out: %.cpp $(DEPENDENT_HEADERS)

might be expanded to be

CLBase: CLBase.cpp ../src/command_line.hpp

if there is an file called CLBase.cpp under the current path. While % could only be used in the targets and depedencies, to access the match in the recipe, use $* instead. For example,

%.out: ./%.cpp ../src/*.hpp
    $(CXX) $(CXX_FLAGS) $< -o $*
    $(MV) $* $@

The .DEFAULT_GOAL works like an environment variable to specify which is the default target that Make would build when target is absent from the command line. .DEFAULT_GOAL would be set to the first valid target (pseudo-target is not in the consideration) appears after it. So usually, the first target in a makefile would be the default target, but it can be customized explicitly:

.DEFAULT_GOAL := all

or

.DEFAULT_GOAL :=
all: $(TARGETS)

Two more special variables in Makefile I learned recently: $(MAKECMDGOALS) and $(MAKECMDLINE). They enable the Makefile to refer to the command line and do things special, for example:

ifeq ($(MAKECMDGOALS), clean) # no error on clean
else ifndef CC # condition to raise error
$(error must set CC)
endif

Credits