Makefile Optimization: $(eval) and macro caching


The $(eval) function was introduced in GNU Make 3.80 but was a little buggy, 3.81 has fixed those bugs in $(eval) is ready for prime time.  $(eval)'s argument is expanded and then parsed as if it were part of a Makefile.   

About $(eval)

The $(eval) function was introduced in GNU Make 3.80 but was a little buggy, 3.81 has fixed those bugs in $(eval) is ready for prime time.  $(eval)'s argument is expanded and then parsed as if it were part of a Makefile.   

That means that within an $(eval) (which could be inside a variable definition) you can programmatically define variables, create rules (explicit or pattern), include other Makefiles, etc.  It's a really powerful function.

See page 84 of the GNU Make Manual (section 8.8, The eval function for more details on the use of $(eval).

A simple example is

set = $(eval $1 := $2)

$(call set,FOO,BAR)

$(call set,A,B)

This results in FOO having the value BAR and A having the value B.  Obviously, this example could have been achieved without $(eval).  For more complex examples, see the discussion of $(eval) in Managing Projects with GNU Make by Robert Mecklenburg and published by O'Reilly

An $(eval) side effect

One use of $(eval) is to create side effects.  For example, here's a variable that is actually an auto-incrementing counter (it uses the arithmetic function from the GNU Make Standard Library, see

include gmsl

c-value := 0

counter = $(c-value)$(eval c-value := $(call plus,$(c-value),1))

Every time counter is used its value is incremented by one.  For example, the followed sequence of $(info) functions outputs numbers in sequence starting from 0. ($(info)) was introduced in GNU Make 3.81 and is GNU Make's equivalent of print; it just prints out its argument on stdout).

$(info Starts at $(counter))

$(info Then it's $(counter))

$(info And then it's $(counter))

The actual output is

Starts at 0

Then it's 1

And then it's 2

You could use a simple side effect like that to find out just how often a particular macro is reevaluated by GNU Make.  You might be surprised at the result.  For example, when building GNU Make itself the variable srcdir is accessed 48 times. OBJEXT is accessed 189 times, and that's in a very small simple project.

All those accesses to an unchanging variable add up to time wasted by GNU Make looking at the same string over and over again.  If the variable being accessed is long (such as a long path), or contains calls to $(shell) or complex GNU Make functions the performance of macro handling could effect the overall run time of a make. 

That's especially important if you are trying to minimize build time by parallelizing the make, or if a developer is running an incremental build requiring just a few files to be rebuilt.  In both cases a long start up time by GNU Make could be very wasteful.

Caching macro values

Of course, GNU Make does provide a solution to this problem: use := intead of =. A macro defined using := gets its value set once and for all, the right-hand side is evaluated
once and the resulting value is set in the variable.  Although this is faster since the right-hand side is evaluated once there are problems which cause it to be rarely used.  It fixes the order of definition of variables in the Makefile.  For example,

FOO := $(BAR)

BAR := bar


BAR := bar

FOO := $(BAR)

result in FOO having two totally different values (in the first snipper FOO is empty and in the second FOO is bar).  Contrast that with the simplicity of writing

FOO = $(BAR)

BAR = bar

where FOO is bar.  Most Makefiles are written in this style and only very conscientious (and speed conscious) Makefile authors use :=.  See also my article Makefile Optimization: := and $(shell) go together ).

On the other hand, almost all

About the author

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.