Rediscovering make: automatic variables

January 22, 2018

Despite its simplicity, automatic variables are very convenient when writing non-trivial makefiles. This article covers what they are and how to use them.

note: if you need a quick refresher on rules, check out the previous post on the make series.

Automatic variables

As patterns can be really useful to define targets and prerequisites, they are also dynamic: every time the recipe is run the wildcard can be matching different files, which is a problem if you need to reference them in your recipe.

You can deal with this using automatic variables. As the name implies, make defines a set of variables for you every time a rule is executed, based on the target and the prerequisites of the rule.

While automatic variables are most useful with patterns, the following examples use static file names in order to simplify the concepts, but all of what's described above works for patterns too.

Suppose you have the following rule:

targetdir/targetfile.o : pre.c predir/pre.h | order-only.c
# recipe

When the recipe is run, the following variables are automatically assigned:

Variable Meaning Example
$@ file name of the target targetdir/targetfile.o
$< name of the first prerequisite pre.c
$? names of all prerequisites newer than the target depends on context
$^ names of all prerequisites pre.c predir/pre.h
$| names of all the order-only prerequisites order-only.c
$* stem with which an implicit rule matches targetdir/targetfile
$% name of the archive member (see archives) -


Sometimes, you may only need only the directory or the filename of the variable, for this scenario make offers two modifiers you can add to your variables:

Modifier Meaning Example
D the directory part dir
F the file-within-directory part simple.c

Modifiers are added right next to the variable and need to be wrapped in parenthesis, for example if $@ is targetdir/targetfile.o:


As automatic variables can be difficult to remember, here are a couple of resources to help you:

Phony makefile

A good way to learn is by experimentation: create a directory, place mock files in there, and define your targets and prerequisites, then, instead of doing something useful in the recipe, just print the variables:

targetdir/targetfile.o : predir/pre.h | order-only.c
@echo '@: $@'
@echo '%: $%'
@echo '<: $<'
@echo '?: $?'
@echo '^: $^'
@echo '|: $|'
@echo '*: $*'


I published snippet packs for Visual Studio Code and Sublime Text that may come in handy: they give you a list of the available variables, followed by a short explanation of their purpouse:


note: If you are using another editor there are tools to convert between snippets formats.