Recent changes
Table of Contents

GNU Make Thunks

What are thunks? Thunks are things that facilitate lazy evaluation. What is lazy evaluation? Lazy evalution lets you delay performing work until you’re absolutely sure you need to.

Here’s a way to create thunks in GNU Make. You’ll need GNU Make 3.80 (or later).

Motivating Example

Here’s why you might want thunks in a Makefile.

Let’s say you keep all your build tools in a central location. To be able to build on multiple platforms, you have multiple versions of each tool stored in that central location.

Let’s say you have a tool named “bork”, with separate binaries for the different host platforms: “bork.OSF1.Alpha”, “bork.Linux.x86”, “bork.Linux.PPC”, etc. To choose between these binaries, you have a shell script (“detect.sh”) that detects the host system type and prints out the name of the appropriate binary.

BORK = $(shell detect.sh)

a.bork: a.txt
   $(BORK) -o a.bork a.txt

b.bork: b.txt
   $(BORK) -o b.bork b.txt

That code will work just fine. The problem is that the “detect.sh” script will be executed twice (once for each use of the $(BORK) variable). To get around this, you could use “:=” assignment.

BORK := $(shell detect.sh)

The problem with this is that the “detect.sh” script will be executed all the time, even when we don’t need to use the “$(BORK)” variable. For example, “detect.sh” will be run even for “make clean” or if we’re using the Makefile to build something totally unrelated.

What we want here is a thunk. The first time the “$(BORK)” variable is used, run the “detect.sh” script and save the result. Any subsequent accesses to “$(BORK)” should use the saved result. To do that, we have to abuse GNU Make’s “eval” function:

BORK_GEN = $(shell detect.sh)
BORK = $(eval BORK := $(BORK_GEN))$(BORK)

When “$(BORK)” is accessed for the first time, it will call the “$(BORK_GEN)” function and save the result in “$(BORK)”. Subsequent accesses will just return the saved value.

Generic Function

You can create a function to generate thunks:

THUNK_EXPR = $$(eval $(1) := $$($(1)_GEN))$$($(1))
DEF_THUNK = $(eval $(1) = $(call THUNK_EXPR,$(1)))

Now, creating a new thunk involves less work:

BORK_GEN = $(shell detect.sh)
$(call DEF_THUNK,BORK)

data/gnu_make_thunks.txt Last modified: 01.10.2008 00:37
Driven by DokuWiki