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.
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:
|$@||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:
|D||the directory part||
|F||the file-within-directory part||
Modifiers are added right next to the variable and need to be wrapped in parenthesis, for example if
As automatic variables can be difficult to remember, here are a couple of resources to help you:
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 '*: $*'
note: If you are using another editor there are tools to convert between snippets formats.