An Introduction to Makefiles

A simple makefile consists of rules with the following shape:

1
2
3
4
target … : prerequisites …
        recipe

A target is usually the name of a file that is generated by a program, A target can also be the name of an action to carry out, such as clean.

A prerequisite is a file that is used as input to create the target. A target often depends on several files.

A recipe is an action that make carries out. A recipe may have more than one command. Put a tab character at the beginning of every recipe line!

All make does is execute the recipe you have specified when the target file needs to be updated.)

Bear in mind that make does not know anything about how the recipes work. It is up to you to supply recipes that will update the target file properly. All make does is execute the recipe you have specified when the target file needs to be updated.

By default, make starts with the first target (not targets whose names start with ‘.’ unless they also contain one or more ‘/’). This is called the default goal. Goals are the targets that make strives ultimately to update.

Thus, when you give the command:

1
make

make reads the makefile in the current directory and begins by processing the first rule.

Rules for Cleaning

Here is how we could write a make rule for cleaning our example editor:

1
2
clean:
        rm edit $(objects)

In practice, we might want to write the rule in a somewhat more complicated manner to handle unanticipated situations. We would do this:

1
2
3
.PHONY : clean
clean :
        -rm edit $(objects)

This prevents make from getting confused by an actual file called clean and causes it to continue in spite of errors from rm.

Writing Makefiles

Splitting Long Lines

Format makefiles for readability by adding newlines into the middle of a statement with a backslash (\) character.

1
2
var := one$\
       word

this is equivalent to:

1
var := one$ word

Then make will perform variable expansion. The variable reference ‘$ ’ refers to a variable with the one-character name “ ” (space) which does not exist, and so expands to the empty string, giving a final assignment which is the equivalent of:

1
var := oneword

Makefile file name

By default, when make looks for the makefile, it tries the following names, in order: GNUmakefile, makefile and Makefile.

We recommend Makefile because it appears prominently near the beginning of a directory listing, right near other important files such as README.

If you want to use a nonstandard name for your makefile, you can specify the makefile name with the ‘-f’ or ‘–file’ option.

Including Other Makefiles

The include directive tells make to suspend reading the current makefile and read one or more other makefiles before continuing. The directive is a line in the makefile that looks like this:

1
include filenames…

If you want make to simply ignore a makefile which does not exist or cannot be remade, with no error message, use the -include directive instead of include, like this:

1
-include filenames…

The Variable MAKEFILES

If the environment variable MAKEFILES is defined, make considers its value as a list of names (separated by whitespace) of additional makefiles to be read before the others. This works much like the include directive.

It is much better to write explicit include directives in the makefiles.

Pattern Target Rule

1
2
%:
	statements

The way this works is that the pattern rule has a pattern of just ‘%’, so it matches any target whatever.

1
target-name: ;

We give the target an empty recipe to prevent make from searching for an implicit rule to build it.

How make Reads a Makefile

GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values and implicit and explicit rules, and builds a dependency graph of all the targets and their prerequisites. During the second phase, make uses this internalized data to determine which targets need to be updated and run the recipes necessary to update them.

It’s important to understand this two-phase approach because it has a direct impact on how variable and function expansion happens; this is often a source of some confusion when writing makefiles.

We say that expansion is immediate if it happens during the first phase: make will expand that part of the construct as the makefile is parsed. We say that expansion is deferred if it is not immediate. Expansion of a deferred construct part is delayed until the expansion is used: either when it is referenced in an immediate context, or when it is needed during the second phase.

Variable Assignment

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
immediate = deferred
immediate ?= deferred
immediate := immediate
immediate ::= immediate
immediate :::= immediate-with-escape
immediate += deferred or immediate
immediate != immediate

define immediate
  deferred
endef

define immediate =
  deferred
endef

define immediate ?=
  deferred
endef

define immediate :=
  immediate
endef

define immediate ::=
  immediate
endef

define immediate :::=
  immediate-with-escape
endef

define immediate +=
  deferred or immediate
endef

define immediate !=
  immediate
endef

Variables

A variable is a name defined in a makefile to represent a string of text, called the variable’s value. In some other versions of make, variables are called macros.

Variable names are case-sensitive. The names ‘foo’, ‘FOO’, and ‘Foo’ all refer to different variables.

It is traditional to use upper case letters in variable names, but we recommend using lower case letters for variable names that serve internal purposes in the makefile

Defining Variables

Whitespace around the variable name and immediately after the ‘=’ is ignored.

Recursively Expanded Variable Assignment

Variables of this sort are defined by lines using ‘=’ (see Setting Variables) or by the define directive.

if it contains references to other variables, these references are expanded whenever this variable is substituted.

1
foo = value

A major disadvantage is that you cannot append something on the end of a variable, as in:

1
CFLAGS = $(CFLAGS) -O

it will cause an infinite loop in the variable expansion.

Simply Expanded Variable Assignment

Simply expanded variables are defined by lines using ‘:=’ or ‘::=’ .

The value of a simply expanded variable is scanned once, once that expansion is complete the value of the variable is never expanded again.

Therefore,

1
2
3
x := foo
y := $(x) bar
x := later

is equivalent to

1
2
y := foo bar
x := later

Simply expanded variables generally make complicated makefile programming more predictable because they work like variables in most programming languages.

Leading whitespace characters are discarded from your input before substitution of variable references and function calls; this means you can include leading spaces in a variable value by protecting them with variable references, like this:

1
2
nullstring :=
space := $(nullstring) # end of the line

Conversely, if you do not want any whitespace characters at the end of your variable value, you must remember not to put a random comment on the end of the line after some whitespace, such as this:

1
dir := /foo/bar    # directory to put the frobs in

Here the value of the variable dir is ‘/foo/bar ’ (with four trailing spaces), which was probably not the intention. (Imagine something like ‘$(dir)/file’ with this definition!)

Immediately Expanded Variable Assignment

This type of assignment uses the ‘:::=’ operator.

Another form of assignment allows for immediate expansion, but unlike simple assignment the resulting variable is recursive: it will be re-expanded again on every use.

In order to avoid unexpected results, after the value is immediately expanded it will automatically be quoted: all instances of $ in the value after expansion will be converted into $$.

1
2
3
var = first
OUT :::= $(var)
var = second

results in the OUT variable containing the text ‘first’, while here:

1
2
3
var = one$$two
OUT :::= $(var)
var = three$$four

results in the OUT variable containing the text ‘one$$two’. The value is expanded when the variable is assigned, so the result is the expansion of the first value of var, ‘one$two’; then the value is re-escaped before the assignment is complete giving the final result of ‘one$$two’.

Conditional Variable Assignment

There is another assignment operator for variables, ‘?=’. This is called a conditional variable assignment operator, because it only has an effect if the variable is not yet defined.

1
FOO ?= bar
1
2
3
ifeq ($(origin FOO), undefined)
  FOO = bar
endif
Output Variable Assignment

The shell assignment operator ‘!=’ can be used to execute a shell script and set a variable to its output.

If the result of the execution ends in a newline, that one newline is removed; all other newlines are replaced by spaces. The resulting string is then placed into the named recursively-expanded variable.

1
2
hash != printf '\043'
file_list != find . -name '*.c'

If the result of the execution could produce a $, and you don’t intend what follows that to be interpreted as a make variable or function reference, then you must replace every $ with $$ as part of the execution. Alternatively, you can set a simply expanded variable to the result of running a program using the shell function call.

1
2
hash := $(shell printf '\043')
var := $(shell find . -name "*.c")
Defining Multi-Line Variables
1
2
define variableName
endef

The final newline before the endef is not included in the value; if you want your value to contain a trailing newline you must include a blank line.

1
2
3
4
define two-lines
echo foo
echo $(bar)
endef

When used in a recipe, the previous example is functionally equivalent to this:

1
two-lines = echo foo; echo $(bar)

Using two separate lines means make will invoke the shell twice, running an independent sub-shell for each line.

If you want variable definitions made with define to take precedence over command-line variable definitions, you can use the override directive together with define:

1
2
3
4
override define two-lines =
foo
$(bar)
endef

Variables Assignment

Appending More Text to Variables

preceded by a single space, if it has a value already

1
2
objects = main.o foo.o bar.o utils.o
objects += another.o

sets objects to ‘main.o foo.o bar.o utils.o another.o’.

Using ‘+=’ is similar to:

1
2
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

Variable References

1
$(foo)
1
${foo}

Variable references work by strict textual substitution.

A dollar sign followed by a character other than a dollar sign, open-parenthesis or open-brace treats that single character as the variable name. Thus, you could reference the variable x with $x. However, this practice can lead to confusion (e.g., ‘$foo’ refers to the variable f followed by the string oo) so we recommend using parentheses or braces around all variables, even single-letter variables, unless omitting them gives significant readability improvements.

Substitution References

A substitution reference substitutes the value of a variable with alterations that you specify.

1
$(var:a=b)
1
${var:a=b} 

its meaning is to take the value of the variable var, replace every a at the end of a word with b in that value, and substitute the resulting string.

Overriding Variables

An argument that contains ‘=’ specifies the value of a variable: ‘v=x’ sets the value of the variable v to x. If you specify a value in this way, all ordinary assignments of the same variable in the makefile are ignored; we say they have been overridden by the command line argument.

1
make variable=value
The override Directive

If a variable has been set with a command argument, then ordinary assignments in the makefile are ignored. If you want to set the variable in the makefile even though it was set with a command argument, you can use an override directive, which is a line that looks like this:

1
override variable = value
1
override variable := value

Undefining Variables

If you want to clear a variable, setting its value to empty is usually sufficient, it yield empty string. Use the undefine directive to make a variable appear as if it was never set.

1
2
undefine foo
undefine bar

If you want to undefine a command-line variable definition, you can use the override directive together with undefine:

1
override undefine variable

Variables from the Environment

Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value. However, an explicit assignment in the makefile, or with a command argument, overrides the environment.

Other use of variables from the environment is not recommended. It is not wise for makefiles to depend for their functioning on environment variables set up outside their control, since this would cause different users to get different results from the same makefile. This is against the whole purpose of most makefiles.

Target-specific Variable Values

Variable values in make are usually global. Target-specific variable allows you to define different values for the same variable, based on the target that make is currently building. As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).

Set a target-specific variable value like this:

1
target … : variable-assignment

Pattern-specific Variable Values

1
pattern … : variable-assignment

For example:

1
%.o : CFLAGS = -O

will assign CFLAGS the value of ‘-O’ for all targets matching the pattern %.o.

Suppressing Inheritance

make variables are inherited by prerequisites. Sometimes, however, you may not want a variable to be inherited. For these situations, make provides the private modifier. Any variable marked private will be visible to its local target but will not be inherited by prerequisites of that target. A global variable marked private will be visible in the global scope but will not be inherited by any target, and hence will not be visible in any recipe.

1
2
3
4
EXTRA_CFLAGS =

prog: private EXTRA_CFLAGS = -L/usr/local/lib
prog: a.o b.o

Due to the private modifier, a.o and b.o will not inherit the EXTRA_CFLAGS variable assignment from the prog target.

Automatic Variables

variables descriptions
$@ The file name of the target of the rule.
$% The target member name, when the target is an archive member. ‘$%’ is empty when the target is not an archive member.
$< The name of the first prerequisite.
$? The names of all the prerequisites that are newer than the target, with spaces between them.
$^ The names of all the prerequisites, with spaces between them.
$+ This is like ‘$^’, but prerequisites listed more than once are duplicated in the order they were listed in the makefile.
$| The names of all the order-only prerequisites, with spaces between them.
$* The stem with which an implicit rule matches.
$(@D)
$(@F)
$(*D)
$(%D)
$(?D)
$(?F)

Other Special Variables

Control Flow

if Statements

It is optional to have an else in a conditional.

1
2
3
4
5
ifeq (param1,param2)
        statements
else
        statements
endif

The syntax of a complex conditional is as follows:

1
2
3
4
5
6
7
conditional-directive-one
    text-if-one-is-true
else conditional-directive-two
    text-if-two-is-true
else
    text-if-one-and-two-are-false
endif

Often you want to test if a variable has a non-empty value. Whitespace characters usually are not seen as empty. Use the strip function to avoid interpreting whitespace as a non-empty value.

1
2
3
ifeq ($(strip $(foo)),)
    text-if-empty
endif

Expand all variable references in arg1 and arg2 and compare them:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ifeq (arg1, arg2)
ifeq 'arg1' 'arg2'
ifeq "arg1" "arg2"
ifeq "arg1" 'arg2'
ifeq 'arg1' "arg2"

ifneq (arg1, arg2)
ifneq 'arg1' 'arg2'
ifneq "arg1" "arg2"
ifneq "arg1" 'arg2'
ifneq 'arg1' "arg2"

Take the name of a variable as its argument, not a reference to a variable:

Note that ifdef only tests whether a variable has a value. It does not expand the variable to see if that value is nonempty. Consequently, tests using ifdef return true for all definitions except those like foo =. To test for an empty value, use ifeq ($(foo),).

1
2
3
ifdef variable-name

ifndef variable-name
1
2
3
4
5
6
7
bar =
foo = $(bar)
ifdef foo
    frobozz = yes
else
    frobozz = no
endif

sets ‘frobozz’ to ‘yes’, while:

1
2
3
4
5
6
foo =
ifdef foo
    frobozz = yes
else
    frobozz = no
endif

sets ‘frobozz’ to ‘no’.

make evaluates conditionals when it reads a makefile. Consequently, you cannot use automatic variables in the tests of conditionals because they are not defined until recipes are run.

Writing Rules

Reference

GNU make