Now that GNU Make 3.81 is out and $(eval) works reliably it's time to look at how $(eval)
can be used to create useful side effects inside GNU Make macros. One of these side effects is a one-line caching function that speeds up long GNU Make macros without having to resort to := and a potentially complex revision to a Makefile.
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 http://www.gnu.org/software/make/manual/make.html#Eval-Function) for more details on the use of $(eval).
A simple example is
set = $(eval $1 := $2)
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 http://www.oreilly.com/catalog/make3/book/ch04.pdf.
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 http://gmsl.sf.net/).
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 of