| 
Home arrow Articles arrow Columns arrow Ask Mr. Make arrow Dumping Every Makefile Variable
Dumping Every Makefile Variable Print
Written by John Graham-Cumming   
Monday, 12 July 2004


In a previous tip I showed how to print out the value of a single Makefile variable using a special rule:


print-%:
@echo $* = $($*)

But what if you want to print out every variable defined in a Makefile? In this tip I'm going to show you how and introduce GNU Make's powerful functions.

Consider the following example Makefile (cunningly named Makefile):

X=$(YS) hate $(ZS)
Y=dog
YS=$(Y)$(S)
Z=cat
ZS=$(Z)$(S)
S=s

all:

It sets five variables: X, Y, Z, S, YS, and ZS. Using the special rule shown above it's possible to type commands like

gmake print-X

to get the value of X once for each variable you are interested in. In GNU Make 3.80 the authors introduced a couple of new features that make it feasible to print out the value of all the variables defined in a Makefile with a single rule. But be prepared, this tip requires unleashing the power of GNU Make's functions. A full reference to GNU Make's functions can be found in the GNU Make manual here.

Create a Makefile named helper.mak containing the following:

.PHONY: printvars
printvars:
@$(foreach V,$(sort $(.VARIABLES)),
$(if $(filter-out environment% default automatic,
$(origin $V)),$(warning $V=$($V) ($(value $V)))))

Before understanding how this works we can try it out on the sample Makefile above:

gmake -f Makefile -f helper.mak printvars

That command directs GNU Make to load Makefile and then load helper.mak and then “build” printvars. Here's the output:

helper.mak:3: MAKEFILE_LIST= Makefile helper.mak ( Makefile helper.mak)
helper.mak:3: MAKEFLAGS= ()
helper.mak:3: S=s (s)
helper.mak:3: SHELL=/bin/sh (/bin/sh)
helper.mak:3: X=dogs hate cats ($(YS) hate $(ZS))
helper.mak:3: Y=dog (dog)
helper.mak:3: YS=dogs ($(Y)$(S))
helper.mak:3: Z=cat (cat)
helper.mak:3: ZS=cats ($(Z)$(S))

GNU Make has thrown in three extra variables that weren't explicitely defined (MAKEFILE_LIST, MAKEFLAGS and SHELL), but the rest are all the variables defined in Makefile. Each line shows the name of the variable, its fully substituted value and the way in which is was defined.

Now to understand how this works. It's a lot easier to understand the long complex line used to print out the variables if we reformat it a bit, like this:

$(foreach V,
$(sort $(.VARIABLES)),
$(if
$(filter-out environment% default automatic,
$(origin $V)),
$(warning $V=$($V) ($(value $V)))
)
)

Start by finding .VARIABLES. That's a new feature of GNU Make 3.80: it's a variable whose value is a list of the names of all the variables defined in the Makefile. The first thing we do is sort it into order: $(sort $(.VARIABLES)). Then we go through the list element by element (i.e. variable name by variable name) setting a variable called V to the name of the variable we are considering: $(foreach V, $(sort (.VARIABLES)),...).

For each variable name we decide whether to print or ignore it based on where the variable was defined. If it was one of GNU Make's built-in variables (like $@ or $(CC)) or came from the environment we don't want to print it out. To make that decision we use $(if).

If $(if)'s predicate is true then we do $(warning $V=$($V) ($(value $V))) to output a warning containing the name of the variable, it's fully expanded value, and its defined value.

The other cool feature in GNU Make 3.80 is the $(value) function which outputs the value of a variable without expanding it. In our Makefile example above YS will have the value dogs when used in the form $(YS), but $(value YS) would return $(Y)$(S): it shows us how YS is defined, not its final value. That's a very useful debugging feature.

So now for the hard part: how to decide which variables to print and which to ignore. $(if) will print the variable information if its predicate is not an empty string. GNU Make is very string-centric and thinks of false as 'empty string' and true as 'not an empty string'. The predicate $(filter-out environment% default automatic,$(origin $V)) figures out where the variable referenced by $V was defined by calling $(origin $V). That returns a string describing where the variable was defined (e.g. it returns environment for environment variables, file for variables defined in a Makefile and default for things the GNU Make defines by itself).

The $(filter-out environment% default automatic,$(origin $V)) says if the result of $(origin) matches any of the patterns environment% (), default or automatic then return an empty string, otherwise leave it alone. Combined with the $(if) this results on only variables defined in the Makefile being printed.



John Graham-Cumming
is Founder and VP of Engineering at Electric Cloud, Inc. Prior to joining Electric Cloud, John was a Venture Consultant with Accel Partners, VP of Internet Technology at Interwoven, Inc. (IWOV), VP of Engineering at Scriptics Corporation (acquired by Interwoven), and Chief Architect at Optimal Networks, Inc.

John holds BA and MA degrees in Mathematics and Computation and a Doctorate in Computer Security from Oxford University. John is the creator of the highly acclaimed open source POPFile project. He also holds two patents in network analysis and has others pending.
Trackback(0)
Comments (2)add
...
written by lex , March 05, 2007
the comment system is eating backslash, anyway, add some to make it work.
report abuse
vote down
vote up
Votes: +0
...
written by lex , March 05, 2007
This function need some newline escape to work on my computer (linux & make 3.81)

.PHONY: printvars
printvars:
@$(foreach V,$(sort $(.VARIABLES)),
$(if $(filter-out environment% default automatic,
$(origin $V)),$(warning $V=$($V) ($(value $V)))))

report abuse
vote down
vote up
Votes: +0
Write comment
smaller | bigger

security image
Write the displayed characters


busy
 
< Prev   Next >

Video News

Whitepaper Spotlight

Stay up to date with Configuration Management and Application Lifecycle Management technology products and services by browsing our featured white papers below: See all the Featured Whitepapers>>
Tool Spotlight
CollabNet
CollabNet Subversion is an enterprise-ready distribution of Subversion® that includes, in one package,...
Read More
AccuRev
AccuRev is a best-of-breed, process-centric software configuration management (SCM) solution for...
Read More
IBM Rational Build Forge Express Edition
IBM Rational Build Forge Express Edition is a flexible and robust build automation framework developed,...
Read More
Sapient ResultSpace
ResultSpace is the Agile Application Lifecycle Management (ALM) solution that enables software development...
Read More