This model explains every puzzling variable value and unlocks generating rules programmatically.
GNU make works in two phases. In the read phase it parses all makefiles, expands what must be known now, and builds the dependency graph. In the build phase it decides what's out of date and runs recipes.
Each construct is expanded either immediately (during reading) or deferred (when used later):
- Immediate: the right side of
:=,::=and!=, the targets and prerequisites of rules, and conditionals. - Deferred: the right side of
=and?=,defineblocks, and recipes, which are expanded only just before they run.+=keeps the flavour the variable already had.
That's why a recipe can use a variable defined further down the file, while a prerequisite list cannot.
$(call fn,a,b) expands a variable with $(1), $(2) bound to arguments: user-defined functions. $(eval text) takes text and parses it as makefile syntax during the read phase, so you can generate rules in a loop:
$(foreach p,$(PROGRAMS),$(eval $(call PROGRAM_template,$(p))))Inside the template, anything that must survive until the eval parses it needs $$: one level of $ is consumed by call, the second by eval. Debug templates by replacing $(eval ...) with $(info ...) to print the generated text.
Example
PROGRAMS := server client
server_SRC := server.c net.c
client_SRC := client.c net.c
define PROGRAM_template
$(1): $$($(1)_SRC:.c=.o)
$$(CC) -o $$@ $$^
ALL += $(1)
endef
$(foreach p,$(PROGRAMS),$(eval $(call PROGRAM_template,$(p))))
all: $(ALL)
show:
@echo "ALL=$(ALL)"
@echo "late=$(LATE)"
# recipes are expanded later, so a variable defined below the rule works
LATE = defined after the rule
# $(info $(call PROGRAM_template,server)) would print:
# server: $(server_SRC:.c=.o)
# $(CC) -o $@ $^
# ALL += serverRemember
- Read phase builds the graph; build phase runs recipes
- := is immediate, = and ?= are deferred, recipes expand just before running
- $(eval $(call template,...)) generates rules; escape with $$
Watch out for
- Using a variable in a prerequisite list before it is defined in the file; prerequisites are expanded immediately.