Table of Contents
Open Table of Contents
Conditional Assignment
The first one is not too difficult to understand, basically in Makefiles you can assign a value to a variable unless it already has a value in which case you just leave it alone. The way this looks is
DIR ?= ~/code/Python/
This is useful since it enables you to set default values for variables but ensures that in case the user already specified a value, to use that instead. Using conditional assignment allows your rules to be configurable but also not fail when a value isn’t supplied.
eval
It is very rare to hear eval in any language being spoken of positively given that it is very easy
to misuse. Regardless, due to the nature of Makefiles as kind of an weird macro language, eval
exists and is sometimes useful. To understand how we’ll go on a bit of a tangent.
If you’ve ever seen a Makefile you know that it roughly consists of a bunch of variables followed by sections describing how to perform certain tasks. The part that interests us are the task descriptions. The syntax is roughly:
rulename: prerequisites
command1
command2
...
commandn
The section with the commands is not technically Make in the sense that it is treated as text that
is just ‘preprocessed’ and then passed on to the relevant program to be executed. Suppose we want to
do Make specific things like set variables in this section and have them persist in Make’s
environment, eval comes in handy here:
py3-proj:
$(eval DIR ?= ~/code/Python/)
$(MAKE) -f $(AFILE) create-project DIR=$(DIR) TYPE=Python3 EDIT=$(EDIT)
What is happening above is first we checks if a DIR variable is already set (perhaps was specified
on the command line) before setting a default. Then we call Make recursively (😎) to run
a different rule with some ‘arguments’.
Changing SHELL
If I could only write about one interesting feature this would definitely be it. I remember reading
about it in the GNU docs and thinking it was such a cool feature. The reason why is that it frees
you from the restriction of using shell which also has it’s own unique set of problems.
SHELL = /usr/bin/python3
.ONESHELL:
chaos-game:
import turtle
from random import choice
edges = [(-200, 200), (200, 200), (200, -200), (-200, -200)]
current = choice(edges)
last = edges[0]
turtle.speed(0)
turtle.penup()
turtle.hideturtle()
for i in range(5000):
while last == current:
current = choice(edges)
tx, ty = turtle.position()
new_x, new_y = ((current[0] + tx) / 2, (current[1] + ty) / 2)
turtle.setpos(new_x, new_y)
turtle.dot(8, "red")
last = current
current = choice(edges)
turtle.done()
.ONESHELL from the docs:
If .ONESHELL is mentioned as a target, then when a target is built all lines of the recipe will be given to a single invocation of the shell rather than each line being invoked separately
.SHELLFLAGS is also a useful variable to set as it controls the arguments that are passed to the
program in SHELL. By default it is set to -c.
Canned Recipes and call
Canned recipes allow you to define a sequence of commands that can be used in multiple recipes
saving it in a variable. Combining this with the call function leads to something very useful.
call is used to create new parameterized functions by writing an expression in a variable (using
define for instance) then expanding it with temporary variables $1, $2 and so forth that hold
the arguments the call was made with.
Here is a useful example that adds simple notifications depending on the exit status of the last shell command.
define notify =
if [[ $$? -eq 0 ]];then
notify-send -t 5000 $1
else
notify-send -t 5000 $2
fi
endef
# example usage
cap-screen:
# Take screenshot of selection
scrot -q 100 -s
$(call notify, "Screenshot taken", "Failed to take screenshot")
Going Further
Turns out that Make is a lot more flexible than it appears at first glance. There’s a ton of more
lesser known features I have not covered here but are in the official documentation for GNU Make.
Take a look at it and feel free to send me an e-mail if you find another gem.
- The gist with the Makefile
- The GNU Make Standard library is full of crazy things you wouldn’t think are possible with Make
- GNU Make official documentation