Make¶
This document mainly summarizes the “GNU make” manual.
1 overview¶
The make
utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them. It runs in two phases:
first phase
reads all
makefile
’s, including the ones included in amakefile
internalize all the variables, values, implicit/explicit rules, and builds a dependency graph of all targets and prerequisites
second phase
determine which targets need to be updated and run the recipes accordingly.
When you give the command:
$ make
make
reads the makefile
in the current directory and begins by processing the first rule, the default goal, whose name does not start with ‘.
’.
This behavior can be overridden using the command line (see Arguments to Specify the Goals) or with the
.DEFAULT_GOAL
special variable.
Before make
can fully process this rule, it must process the rules for the files, prerequisites, that the first rule depends on. Each of these files is processed according to its own rule.
These rules say to update each file by compiling its source file.
The recompilation must be done if the source file, or any of the header files named as prerequisites, is more recent than the object file, or if the object file does not exist.
A Rule that is not a prerequisite of the goal, or a prerequisite of a prerequisite, …, that rule is not processed, unless you tell make
to do so (eg. the shell command $ make clean
).
2 Rule¶
2.1 Explicit rules¶
targets : prerequisites
recipe
…
targets : prerequisites ; recipe
recipe
…
A rule tells make two things:
when the targets are out of date, and
how to update them when necessary.
The targets are file names that needs to be updated, if necessary.
in case of multiple targets, they are separated by spaces.
Wildcard characters may be used
a name of the form
a(m)
represents memberm
in archive filea
(archiving members as targets).Usually there is only one target per rule, but occasionally there is a reason to have more.
The recipe specifies how to update the target
lines start with a tab character (or the first character in the value of the
.RECIPEPREFIX
variable).How to update the target is specified by a recipe. is one or more lines to be executed by the shell (normally ‘sh’), but with some extra features
The first recipe line
may appear on the line after the prerequisites, with a tab character, or
may appear on the same line, with a semicolon.
Either way, the effect is the same. There are other differences in the syntax of recipes.
A target is considered out of date if it does not exist or if it is older, in terms of last-modification time, than any of the prerequisites.
The prerequisites consist of file names (with wildcards or archive members) separated by spaces.
If any of the prerequisites changes, the contents of the existing target file are considered no longer valid.
long line: There is no limit on the length of a line but we may use a backslash
/
followed by a newline, but this is not required.make
will combine the newline with surrounding spaces into a single space.If we don’t want space for the line breaking, we can do the following:
var := one$\ word
This will be interpreted as
var := one$ word
that isvar := one$( )word
and since the variable ” ” does not exists, i.e., ‘$( )=
’, it becomesvar := oneword
.
2.2 Implicit rules¶
The following does not provides recipes for rules but it works since they are regarded as ‘implicit’, i.e.,
make
can ‘deduce’ these rules by itself:objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h
there are built-in rules that can be used implicitly
chained rules combines implicit rules
pattern rules defines implicit rules and its target contains
%
suffix rules are the obsolete way of defining implicit rules for
make
but supported for backward compatibility.implicit rule search describes how
make
searches for an implicit rule
2.3 Last-resort rule¶
last resort is a recipe for rules which cannot be found, explicitly or implicitly, written as a terminal ‘match-anything pattern rule’, so that it will match any target, with no prerequisites.
3 operators¶
4 assignments¶
lists
objects = main.o foo.o bar.o utils.o
defines a variable named
objects
with value “main.o foo.o bar.o utils.o
”. Whitespace around the variable name and immediately after the ‘=’ is ignored.recursively expanded variables: if it contains references to other variables, these references are expanded whenever this variable is substituted (called recursive expansion but doesn’t seem to be really recursive but ‘asynchronous’).
foo = $(bar) bar = $(ugh) ugh = Huh? all:;echo $(foo)
will echo Huh?
.
simply expanded variables: this is synchronous in a sense that it contains their values as of the time the variable was defined.
x := foo y := $(x) bar x := later
is equivalent to
y := foo bar x := later
conditional variable: define if undefined
FOO ?= bar
is equivalent to
ifeq ($(origin FOO), undefined) FOO = bar endif
shell assignment: execute a shell script (on the RHS) and set a variable (on the LHS) to its output.
hash != printf '\043' file_list != find . -name '*.c
is equivalent to
hash := $(shell printf '\043') var := $(shell find . -name "*.c")
the exit status of the just-invoked shell script is stored in the
.SHELLSTATUS
variable+=
appendvariable := value variable += more
is equivalent to
variable := value variable += more
and similar to
temp = value variable = $(temp) more
The difference is that when
+=
is applied to a recursively expanded variable, it stores the text verbatim (value
), and saves these variable (temp
) and function references to be expanded later, when you refer to the new variable (as$(variable)
). Here, the variabletemp
is never defined though.
5 directives¶
A directive is an instruction for make
to do something special while reading the makefile.
include <filenames>
suspend reading the current makefile and read one or more other makefiles before continuing. The environment variableMAKEFILES
, if defined, does the same without the explicitinclude
directive.ifeq
,ifneq
,ifdef
,ifndef
are conditional directives. See “conditional”.define
is another way of setting a value for a variable that can include the newline characters. Eg:define := two-lines echo foo echo $(bar) endef
is functionally equivalent to
two-lines := echo foo; echo $(bar)
(‘functionally’ equivalent because two shell commands separated by ‘
;
’ behave like two separated shell commands.)We can use any value assigning operator ‘
=
’, ‘+=
’, etc, in place of ‘:=
’. If omitted, it will be assumed the asynchronous ‘=
’.The last newline character will be ignored. So, if we want to assign a single newline character to a variable, we have to put two lines:
define newline endef
6 functions¶
origin <variable>
will return the ‘origin’ of ~<variable>.$(origin variable)
will return a string that indicates how the variable was defined.
‘
undefined
’: it was never defined‘
default
’: a default definition; the later definition if multiply defined‘
environment
’: if inherited from the outer environment‘
environment override
’: inherited from the environment but ‘over-rided’ by ‘-e
’ option‘
file
’: defined in a makefile‘
command line
’: defined on the command line‘
override
’: defined with an ~override’ directive in a makefile‘
automatic
’: automatic variable defined for the execution of the recipe
include <filenames>
suspend reading the current makefile and read one or more other makefiles before continuing.include foo *.mk $(bar)
is equivalent to
include foo a.mk b.mk c.mk bish bash
7 special variables¶
.SHELLSTATUS
.DEFAULT_GOAL
~MAKEFILES
8 special targets¶
8.1 Phony targets¶
Consider the following:
clean: rm *.o temp
There are two possibilities:
if there is no file named “
clean
” then$ make clean
will run therm
command;if there is a file named “
clean
” then, since there is no prerequisites andclean
does not create a file, the file will be considered up to date and the recipe won’t be executed.
If we want to run the recipe regardless of whether a file “
clean
” exists or not, we explicitly declare the target to be phony by making it a prerequisite of the special target.PHONY
8.2 clean¶
This is a typical example of using
.PHONY
rule..PHONY: clean clean: rm *.o temp
8.3 silent¶
.SILENT
without prerequisites prevents all recipe echoing, as if all recipes started with ‘@’.
9 The dollar sign¶
$(<function> <arguments>)
or$(<function> <arguments>)
a function call
<function>
is a function name<arguments>
separated from the function name by one or more spaces or tabs, and if there is more than one argument, then they are separated by commasIf the arguments themselves contain other function calls or variable references, it is wisest to use the same kind of delimiters for all the references; write
$(subst a,b,$(x))
, not$(subst a,b,${x})
In case if one need to put
$
in a target or prerequisite, see the manual “§4.2 Rule Syntax”.A variable with
$
in its name might have strange results, see the manual “§6.3.2 Computed Variable Names”.$(<variable>)
or${<variable}
strict textual substitution of a variable’s value, called the variable referencing. The following
foo = c prog.o : prog.$(foo) $(foo)$(foo) -$(foo) prog.$(foo)
is equivalent to
prog.o : prog.c cc -c prog.c
can be used in any context: targets, prerequisites, recipes, most directives, and new variable values
$
followed by a character other than ‘$
’, ‘(
‘ or ‘{
‘ treats that single character as the variable name; thus$foo
is regarded as$(f)
+ the stringoo
10 Recipe echoing¶
Each line of the recipe is printed (echoed) before it is executed (send to the shell).
When a line starts with ‘@’, the echoing of that line is suppressed and the ‘@’ is discarded before the line is passed to the shell.
echo About to make distribution files
will result the following duplicates
echo About to make distribution files About to make distribution files
but
@echo About to make distribution files
will give
About to make distribution files
11 flags¶
‘-n’ or ‘–just-print’ it only echoes most recipes, including even the recipe lines starting with ‘@’, without executing them (dry-running).
‘-s’ or ‘–silent’ flag to make prevents all echoing, as if all recipes started with ‘@’. A rule in the makefile for the special target .SILENT without prerequisites has the same effect
12 conditional¶
syntax
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif
Conditionals may be nested many times or it may not have else
and text-if-false
part at all.
12.1 ifdef
, ifndef
¶
ifdef <variable-name>
If the value of that variable has a non-empty, the
text-if-true
is effective;bar = foo = $(bar) ifdef foo frobozz = yes else frobozz = no endif
sets
frobozz
toyes
(the variable is not expanded - otherwise the result would beno
.)otherwise,
the text-if-false
, if any, is effective.Variables that have never been defined have an empty value.
ifdef foo frobozz = yes else frobozz = no endif
sets
frobozz
tono
.
Because
ifdef
does not expand the variable, it will return true for all definitions except those likefoo =
. To test for an empty value, useifeq ($(foo),)
.
12.2 ifeq
, ifneq
¶
ifeq (arg1, arg2)
orifeq 'arg1' 'arg2'
orifeq "arg1" "arg2"
ifeq
expand all variable references inarg1
andarg2
and compare them.If they are identical, the
text-if-true
is effective;otherwise, the
text-if-false
, if any, is effective.
foo: $(objects) ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif
When the variable CC has the value ‘gcc’, the above example has this effect:
foo: $(objects)
$(CC) -o foo $(objects) $(libs_for_gcc)
When the variable CC has any other value, the effect is this:
foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)
ifneq (arg1, arg2)
orifneq 'arg1' 'arg2'
orifneq "arg1" "arg2"
will do the opposite.