If you've ever looked in a Makefile you'll realize that Makefile variables (often called macros) form the backbone of any Make process. The variables usually define which files will be compiled, what command-line parameters to pass to compilers, even where to find the compiler itself. And if you've ever tried to debug a Makefile you'll know that the number 1 question you ask yourself is “What is the value of variable X?.”
There aren't any debuggers for Make and Make doesn't provide the sort of interactivity you'd see from a scripting language like Perl or Python. So how do you figure out the value of a variable? Take a look at this simple Makefile (which does nothing but set various variables):
X=$(YS) hate $(ZS)
Y=dog YS=$(Y)$(S) Z=cat ZS=$(Z)$(S) S=s all:
What's the value of X? The small size and simplicity of this Makefile means that tracing through all the variable assignments is feasible, leading to the conclusion the X is “dogs hate cats”. In a real multi-thousand line Makefile that unleashes the power of GNU Make's variables and functions figuring out the value of a variable can be a laborious task. But here's a little Make recipe that does all the work for you. Create a Makefile called helper.mak and place in it:
@echo $* = $($*)
Now we can find the value of variable X with the following command:
gmake -f Makefile -f helper.mak print-X
The first -f Makefile tells GNU Make to load our original Makefile, and the second -f helper.mak loads in the receipe. The print-X directs make to “build” the target named print-X. Since there isn't an explicit rule to build print-X GNU Make looks for a pattern and finds print-% (the % acts as a wildcard) and runs the associated command.
The command uses $* (a special GNU Make variable that will have the value matched by the % in the rule) to print the name of the variable and then by doing $($*) gets the value of the variable named by $*. So experimenting with it we can see the following:
$ gmake -f Makefile -f helper.mak print-X X = dogs hate cats $ gmake -f Makefile -f helper.mak print-YS YS = dogs $ gmake -f Makefile -f helper.mak print-S S = s
Sometimes it's useful to know how a variable was defined. GNU Make provides the $(origin) function that returns a string containing the type of the variable
(e.g. Whether it was defined in a Makefile, on the command-line, or in the environment). Modifying helper.mak prints out origin information as well.
print-%: @echo $* = $($*) @echo $*\'s origin is $(origin $*)
Now we see that YS is defined in the Makefile.
$ gmake -f Makefile -f helper.mak print-YS
YS = dogs YS's origin is file
If we override the value of YS on the GNU Make command-line we'll see:
$ gmake -f Makefile -f helper.mak print-YS YS=fleas
YS = fleas YS's origin is command line
Next time I'll serve up a recipe for printing every variable in a Makefile.