Notes on Makefiles

User manuals

The official GNU Make manual

Managing Projects with GNU Make

Debugging makefile

GNU Make Debugger

Basic makefile syntax

target1 target2 ... : prerequisite1 prerequisite2 ...
        command1
        command2
        ...
It's important to put a TAB in front of every command.

Note that the above multi-target syntax is equivalent to:

target1: prerequisite1 prerequisite2 ...
        command1
        command2
        ...

target2: prerequisite1 prerequisite2 ...
        command1
        command2
        ...

Regular variables

To get the value of variable VAR:
$(VAR)
(If VAR is a single letter, one can remove the parentheses.)

To assign or define a variable VAR:

Assignment operatorMeaning
VAR = right-hand-sideRecursively expand: The variable is evaluated every time VAR is referred and is evaluated only when VAR is referred.
VAR := right-hand-sideSimply expand: The variable is evaluated immediately on reading the line VAR := .. It is evaluated only once.
VAR ?= right-hand-sideConditional: VAR is assigned only if it is undefined.

Note that this is the same as:

ifeq ($(origin VAR), undefined)
  VAR = right-hand-side
endif
VAR += right-hand-sideAppending
undefine VARUndefining

A more flexible way of defining a variable is the define/endef directives. It has the following form:

define VAR
  command1
  command2
  ...
  ...
endef
For example, the following two are equivalent:
define two-lines
  echo foo
  echo $(bar)
endef
and
two-lines = echo foo ; echo $(bar)

To pass down the value of variable VAR when invoking make recursively:

export VAR
or
export VAR = right-hand-side

Advanced variable manipulations

To substitute certain part of the value of variable VAR, one can do, for example:
foo := a.o b.o c.o
bar := $(foo:.o=.c)
or better yet,
bar := $(foo:%.o=%.c)
and bar's value would be a.c b.c c.c

Target/Pattern-specific variable assignments

prog: CFLAGS=-g
prog: prog.o foo.o bar.o
will set CFLAGS to -g when building prog and all of its prerequisites (prog.o, foo.o, and bar.o)

Similarly,

%.o: CFLAGS=-O
will assign CFLAGS to -O for all targets matching the pattern %.o

Where do variables come from ?

  • Defined in the makefile, as above.
  • Command line. For example: make CFLAGS=-g CPPFLAGS='-DDEBUG -DLINUX'
  • Internal database. To see them, execute make -p
  • Environmental variables. One can also see them by executing make -p

Special variables

VariableMeaning
$@The targets
$*The root of targets (i.e. without extension)
$<The first prerequisite
$^All prerequisites.
$+Like $^, but includes duplicates.
$?All prerequisites that are newer than the target.

This is useful when building archive libraries, e.g.

libfoo.a: bar.o baz.o
        $(AR) $(ARFLAGS) $@ $?
        $(RANLIB) $@
Some useful suffix rules for managing archive libraries are here.
$%File name of the archive member (libxxx.a) of the target, e.g.
libfoo.a(bar.o): bar.o
        $(AR) $(ARFLAGS) $@ $?
Then $% would be the bar.o inside the parentheses, and $@ would be libfoo.a.

All of above variables have two variants by appending D or F. For example:

$(@D)The directory part of targets

It's defined as

$(patsubst %/,%,$(dir $@))
$(@F)The file name part of targets

It's defined as

$(notdir $@)

Commonly-defined/Implicit variables in Make

One can also see them by executing make -p

VariableMeaning
ARArchive-maintaining program
ARFLAGSFlags passed to the archiver
ASAssembler
CCC compiler
CFLAGSFlags passed to the C compiler
COMPILE.cDefined as
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
COMPILE.cpp
COMPILE.cc
COMPILE.C
Defined as
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
COMPILE.f
COMPILE.F
Defined as
$(FC) $(FFLAGS) $(TARGET_ARCH) -c
CPPThe command to run the C preprocessor.
CPPFLAGSFlags passed to the C preprocessor (which in fact will be passed to C/C++ compiler as well)
CURDIRCurrent working directory
CXXC++ compiler
CXXFLAGSFlags passed to the C++ compiler
FC
F77
Fortran 77 compiler
FFLAGS
F77FLAGS
Flags passed to the Fortran 77 compiler
.INCLUDE_DIRSList of directories that make searches for included makefiles
LDLink editor
.LIBPATTERNSNaming of the libraries make searches for, and their order. This is used in the following situation, for example:
foo: foo.c -lbar
        $(CC) $^ -o $@
Then make would execute
cc foo.c libbar.so -o foo
if foo.c or libbar.so are newer than foo.

(By default, .LIBPATTERNS is defined as lib%.so lib%.a)

Make searchs for libbar.so first in the current working directory, then vpath, then VPATH, and finally, /lib and /usr/lib

LINK.cDefined as
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
LINK.cpp
LINK.cc
LINK.C
Defined as
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
MAKECMDGOALSThe targets given to make on the command-line
MAKEFLAGSCommand-line options passed to invoke this make
MAKEFILES Makefiles to be read on every invocation of make
MAKEFILE_LIST List of makefiles parsed so far, in the order in which it is parsed
MAKELEVELThe number of levels of recursion.
MAKE_VERSIONVersion of GNU make.
OUTPUT_OPTIONDefined as
-o $@
RMThe command to delete files.
SHELLCurrent shell
.VARIABLESList of all global variables defined so far
VPATH Directory search path for files not found in the current working directory

Special targets

.PHONY When it is time to consider such a target, make will run its commands unconditionally, regardless of whether a file with that name exists or what its last modification.

Common/standard phony targets are, for example:

.PHONY: all install clean clobber
.DEFAULT_GOAL If make is invoked without specifying a specific target, then by default make will just achieve the first target in the makefile and stops.

This variable can override it.

.EXPORT_ALL_VARIABLES Export all variables when invoking make recursively
.INTERMEDIATE Prerequisites of this special targets are treated as intermediate files an will be deleted when make finishes.
.DELETE_ON_ERROR Always delete the targets if there is any error during make.
.PRECIOUS Never delete the targets even if there is an error during make.
.SILENT Do not echo the commands before executing them.

Also see the "Commands" section below.

.IGNORE Ignore the error if the commands fail.

Also see the "Commands" section below.

.ONESHELL Execute all commands in a single subshell.

This is useful if the commands use shell built-in commands such as cd, pushd, popd, etc.

Where to find prerequisites ?

If the prerequisites are not in the current working directory, one can specify paths to search for prerequisites:
  • Special make variable VPATH. For example:
    VPATH = ../headers:../src
  • vpath directive. For example:
    vpath %.c src/:src2/
    vpath %.h include/
    

Commands

Each command is executed in a separate subshell. This can cause issues if the command is actually a shell built-in command, such as cd, pushd, popd, etc. To fix this issue, either use the special target .ONESHELL, or put all relevant commands in one line:
foo: bar/lose
       cd $(@D) && gobble $(@F) > ../$@

The default shell is /bin/sh. To override it, set the special variable SHELL.

Some special characters ("command modifiers"), when they appear in front of a command, can have different effects:

Command modifiersEffect
@Do not echo the command.

Also see the special target .SILENT

+Echo the command, but do not execute.
-Ignore the error if the command fails.

Also see the special target .IGNORE

Pattern rules/Suffix rules

A pattern rule contains the character % in the target. It behaves similar to the wildcard character * in UNIX shells.

Suffix rules are the old-fashioned (and obsolete) way of defining implicit rules for make.

For example:

Pattern ruleSuffix rule
%.o: %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
.c.o:
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
(%.o): %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
        $(AR) $(ARFLAGS) $@ $*.o
        $(RM) $*.o
.c.a:
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
        $(AR) $(ARFLAGS) $@ $*.o
        $(RM) $*.o
%: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
.c:
        $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@
%.tab.c %.tab.h: %.y
        bison -d $<
(No equivalent)

Implicit rules and variables

Make's internal database already contains many pattern rules, and they are called implicit rules because one can use them without defining them in a makefile. To see them, execute make -p.

For example, if one has a file foo.c in the current working directory, then executing

make foo
will execute the following command
cc foo.c -o foo
even if there is no makefile in the current working directory. This is because there is a pattern rule in make's default database:
%: %.c
        $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@

Control flows

makefile can have conditionals as below:
if-conditional
  command1
  command2
  ...
else
  more commands
  ...
endif
where if-conditional can be:
ifdef VAR
ifndef VAR
ifeq (arg1, arg2)
ifneq (arg1, arg2)

Automatic dependency rule generation

With gcc's -M and -MM command-line options, one can create dependency rule automatically. However, to incorporate them into a makefile requires some efforts. See here for details.

Functions

make has many built-in functions. A function call syntax is
$(function arg1,arg2,..)
Note that there must NOT be any extraneous spaces around the commas, or between the last argument and ).

Arguments can be texts (space-separated words) or variables.

FunctionsEffect
$(filter patterns,text)
$(filter-out patterns,text)
Return words in text which match/don't match patterns (each of which can contain %'s).

For example:

$(filter foo% %bar,$(word))
$(findstring hay,stack) Return hay if it appears in stack, or nothing otherwise.
$(strip string) Remove leading and trailing spaces of string.
$(subst from,to,text)
$(patsubst fromPat,toPat,text)
Replace from by to in text.

For patsubst, the fromPat and toPat are patterns which may contain at most one % (the rest %'s would be ignored).

For example

$(patsubst %.c,%.o,x.c.c bar.c)
generates x.o.c bar.o
$(sort list) Sort the words of list.
$(words list) Get the number of words in list.
$(word n,list)
$(wordlist s,e,list)
$(firstword list)
$(lastword list)
Return the nth word of list, n starts from 1.

For wordlist, return words from the sth position to the eth position.

firstword and lastword return the first and last word, respectively.

$(dir list)
$(notdir list)
Each word in list is treated as a file name, and dir will extract the directory part of the word, while notdir will remove the directory part.
$(suffix list)
$(basename list)
$(realpath list)
$(abspath list)
Extract the extension of a file name. If no extension, return an empty string.

basename extracts all but the extension of a file name.

realpath returns the canonical absolute name.

abspath is like realpath, but it does not resolve symbolic links.

$(addsuffix suffix,list)
$(addprefix prefix,list)
Append suffix or prepend prefix to each file name in list.
$(join list1,list2) Concatenate the two lists word by word.

For example,

$(join a b,.c .o)
produces a.c b.o
$(wildcard pattern) Get a list of file names matching pattern, which can contain UNIX shell wildcards such as * or ?
$(shell command) Execute the command in a subshell and return the results.
$(info text)
$(warning text)
$(error text)
Display text.

For error, make will also terminate.