Notes on make
Special variables
@D
: the directory (dirname
) of the target file.
Some notes about .PHONY
targets
From GNU Make manual:
A phony target should not be a prerequisite of a real target file; if it is, its recipe will be run every time make goes to update that file. As long as a phony target is never a prerequisite of a real target, the phony target recipe will be executed only when the phony target is a specified goal (see Arguments to Specify the Goals).
How make timestamps work
Does updating file contents in a directory always update the timestamp make looks at?
These are two different questions. One is about make behaviour, the other is about directory timestamps behaviour.
In general, make only looks at mtime.
Hence when a directory mtime changes, if that directory is a prerequisite, then make will rebuild the target
When a directory mtime changes? Not as intuitive as it seems: https://www.baeldung.com/linux/directory-last-modified-time#conclusion
TLDR:
Action | mtime changes |
---|---|
Renaming myDir | No |
Changing myDir‘s Permission | No |
Changing the content of files under myDir | No |
Adding, removing, or renaming files or subdirectories under myDir | Yes |
Make variables
Nomenclature
-
When running
make MYVAR=value
then MYVAR is said to be set with "a command argument". I.e., an argument that contains=
specifies the value of a variable. By doing that, all ordinary assignments of the same variable in theMakefile
being executed bymake
are ignored, i.e. the variable is overridden -
Normally make prints each line of the recipe before it is executed. This is called "recipe echoing", and it can be suppressed using
@
.
Priority
TLDR - Priority of how a value is set:
- (highest) value set in the makefile using the
override
keyword, e.g.override VAR = value
. - value passed to make via a command argument e.g.
make VAR=value
- value set in the makefile, e.g.
VAR = value
orVAR := value
- value set in an environment variable, e.g.
VAR=value make
- (lowest) value set in the makefile using conditional variable assignment,
e.g.
VAR ?= value
From make man pages:
Variables in make can come from the environment in which make is run. 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.
If the ‘-e’ flag is specified, then values from the environment override assignments in the makefile (but this is not recommended practice).
Given:
VAREQ = equal
VARCOLON := colon
VARQUEST ?= question
all:
@echo = \'$(VAREQ)\'
@echo := \'$(VARCOLON)\'
@echo ?= \'$(VARQUEST)\'
$ make
= 'equal'
:= 'colon'
?= 'question'
$ make VAREQ="neweq" VARCOLON="newcolon" VARQUEST="newquest"
= 'neweq'
:= 'newcolon'
?= 'newquest'
$ VAREQ="neweq" VARCOLON="newcolon" VARQUEST="newquest" make
= 'equal'
:= 'colon'
?= 'newquest'
$ VAREQ="neweq" VARCOLON="newcolon" VARQUEST="newquest" make VAREQ="neweq2" VARCOLON="newcolon2" VARQUEST="newquest2"
= 'neweq2'
:= 'newcolon2'
?= 'newquest2'
$ VAREQ="neweq" VARCOLON="newcolon" VARQUEST="newquest" make -e
= 'neweq'
:= 'newcolon'
?= 'newquest'
Keep going
Continue as much as possible after an error.
$ make --keep-going THE-TARGET
Target and recipes using foreach
Using the following method, each command is a dedicate recipe line. If a command fail, make will fail.
Instead, if you use bash for ... in; do
, then a command failure does not
stop executing the next ones. And if the last command succeeds, then make exits
with 0.
Note: The empty line before endef
is needed to expand each recipe_line
into
a full recipe line.
define recipe_line
$(recipe_line_command) $(1) [other options ...]
endef
.PHONY: all
all:
$(foreach arg,$(ALL_ARGUMENTS),$(call recipe_line,$(arg)))
$ make ALL_ARGUMENTS="ciao belli" recipe_line_command="/usr/bin/echo"
/usr/bin/echo ciao [other options ...]
ciao [other options ...]
/usr/bin/echo belli [other options ...]
belli [other options ...]
Spaces using in conditionals
Quoting: http://savannah.gnu.org/bugs/?59584
For conditionals, preceding whitespace is preserved in the left-hand side of the match, while trailing space is ignored. Bizarrely, for the right-hand side of the match leading whitespace is ignored while trailing whitespace is preserved.
I always recommend to everyone that they remove all leading/trailing whitespace in all conditionals, as a simple to remember and always-correct rule.
Both evaluate to false:
ifeq ( $(foo), $(foo))
# ...
ifeq ( $(foo),$(foo) )
Evaluate to true:
ifeq ($(foo) , $(foo))