A very common way to influence the operation of a Makefile is through the use of variables, so it's useful to know the tricky rules regarding them.

Specifying variables

Values can come from command line parameters, assignment in the Makefile, from the environment, or be predefined. In addition the precedence from highest to lowest follows that order. I.E. if you do make CFLAGS=blah, that will override any CFLAGS assigned in the Makefile, whereas if you do CC=gcc in the Makefile, then any CC environment variable will be ignored which is often problematic. There are also predefined variables which one can see with make -p.

To demonstrate the various methods for specifying variables and the associated precedence rules I'll use this Makefile:

static := $(recurse) #empty at assignment time, so 'static' remains empty
recurse = $(_recurse)
_recurse = recurse
condit ?= condit
append += append
override pappend += pappend #handle parameters to `make`

.PHONY: all
all:
	@echo $(CC) $(recurse) $(condit) $(append) $(pappend)

Running the Makefile above with various command lines gives this output:

command builtin=?=+=override
make cc recurse conditappend pappend
recurse=RECURSE make cc recurse conditappend pappend
recurse=RECURSE make -e cc RECURSE conditappend pappend
CC=CC make CC recurse conditappend pappend
condit=CONDIT make cc recurse CONDITappend pappend
make recurse=RECURSE cc RECURSE conditappend pappend
append=APPEND make cc recurse conditAPPEND appendpappend
make append=APPEND cc recurse conditAPPEND pappend
make pappend=PAPPEND cc recurse conditappend PAPPEND pappend

Common variables

There are a few defacto standard variables for controlling Makefile operation

CC

This is a builtin variable which on my system with ccache installed is resolved as: $(CC) = cc => /usr/lib/ccache/cc -> ccache => /usr/bin/cc -> gcc. Alternatively the variable can be overridden using the environment which is the case when running the clang static analyzer like: scan-build -o clang make

CFLAGS

This usually specifies compiler flags and is often appended to, so take special note of the append examples in the table above. Here is an example to issue a build with the same CFLAGS as what the coreutils package was built with: CFLAGS=$(rpm -q --qf="%{OPTFLAGS}" coreutils) make

DESTDIR

This often controls the prefix used by the install target. I.E. where the files are temporarily installed to, which is useful for testing or for package creation scripts etc. Note this doesn't influence relative references within a project, which is usually controlled with ./configure --prefix=...

Inspecting variables

[Update Dec 2010: This excellent post on inspecting make variables details a wrapper script you can use with any Makefile to output values and even the origins of a variable. In summary, you can add the following to your Makefile to support make print-MAKE_VERSION.
# sed is used to highlight "unusual" chars like (trailing) spaces etc.
# This works on GNU and BSD and falls back to cat on solaris.
print-%:
	@printf '%s=%s\n' '$*' '$($*)' | \
	 { ESC=$$(printf '\033'); \
           sed "s/[^[:digit:][:alpha:].=/_-]/$$ESC[7m&$$ESC[m/g" \
             2>/dev/null || cat; }
	@echo '  origin = $(origin $*)'
	@echo '  flavor = $(flavor $*)'
	@echo '   value = $(value  $*)'
Also useful to inspect make variables is the gmake --print-data-base option.]
© Nov 14 2009