Variables: =, :=, ?= and +=

Make · Essentials · 12 min

Variables keep compilers, flags and file lists in one place and let users override them from the command line.

Variables hold text. Define them at the top of the Makefile and reference them as $(NAME) (or ${NAME}). Conventional names: CC and CXX (compilers), CFLAGS, CXXFLAGS, CPPFLAGS, LDFLAGS, LDLIBS.

There are four assignment operators:

  • = recursive: the value is stored as written and expanded every time it's used. Later changes to variables it references are seen.
  • := (or ::=) simple: the right-hand side is expanded once, right now. Predictable and cheaper; prefer it for computed values.
  • ?= assigns only if the variable isn't already set, a way to provide defaults that environment variables can override.
  • += appends, with a space.

Values can come from several places, in increasing priority: environment variables, the Makefile, and the command line. make CFLAGS=-O0 overrides the Makefile's assignment entirely (unless it uses override).

A dollar sign in a Makefile always starts a make variable, so $HOME means $(H) followed by OME. Write $(HOME) to use the environment variable through make, or $$HOME to pass a literal $HOME to the shell. Single-letter variables like $@ don't need parentheses.

Whitespace matters: trailing spaces after a value are kept, which can break paths.

Example

PREFIX  ?= /usr/local
CFLAGS  := -Wall -O2
CFLAGS  += -g
SRC     := main.c util.c

A = $(B)
B = later
X := $(Y)
Y = later

show:
	@echo "PREFIX=$(PREFIX) CFLAGS=$(CFLAGS)"
	@echo "A=$(A) X=$(X)"
	@echo "home via make: $(HOME), via shell: $$HOME"

# $ make show
# PREFIX=/usr/local CFLAGS=-Wall -O2 -g
# A=later X=
# $ make show CFLAGS=-O0
# PREFIX=/usr/local CFLAGS=-O0
# $ PREFIX=/opt make show
# PREFIX=/opt CFLAGS=-Wall -O2 -g

Remember

  • = expands at use time, := expands once at definition
  • ?= sets a default, += appends
  • Command-line assignments override the Makefile; use $$ for a literal shell $

Watch out for

  • Writing $HOME or $PATH in a recipe; make reads it as $(H)OME. Use $$HOME.
  • Writing CC ?= gcc: make predefines CC as cc, so the default never applies. Use CC := gcc or let users pass CC=.

Check yourself

  1. Given X := $(Y) followed by Y = 1, what is $(X)?
  2. Which assignment lets an environment variable PREFIX take precedence?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.gnu.org/software/make/manual/make.html#Flavors

Variables: =, :=, ?= and += · Make · Topolearn