GNU make 3.82 released
Wednesday, July 28th, 2010The next version of GNU make, 3.82, was released today. The build system that is used in all of Code Synthesis’ products relies heavily on GNU make so I have been contributing to this project for a couple of releases now. For this version I have implemented a few new features, fixed a number of bugs, and performed a number of optimizations. In this post I would like to discuss the most notable new additions (not necessarily made by me). For the complete list of user-visible changes refer to the NEWS file in the distribution.
Customizable recipe prefix
People who are new to make usually complain about the use of the tab character as a recipe prefix (the command part in the rule). Now it is possible to choose any symbol (one character) that you want with the .RECIPEPREFIX
special variable, for example:
.RECIPEPREFIX := : all: :echo all
If you decide to change the prefix, then using a colon is actually not a bad choice since this character is already used by make as a rule separator and is therefore unlikely to appear in target or variable names.
Define improvements
Prior to 3.82 the define
operator could only create recursively-expanding variables. It was also not possible to mark the variable as exported or overriding (export
and override
modifiers). In make 3.82 it is now possible to add a modifier as well as to specify the assignment type (simple, conditional, or appending). Here are a couple of examples:
override define foo one two endef define bar := $(foo) three endef
Now there is also the undefine
operator which allows you to completely erase a variable so that it appears as if it was never set. Before, the closest you could get to this behavior is to set the variable to an empty value. However, some GNU make functions, such as $(origin)
and $(flavor)
will still show the difference between a variable that was never defined and the one that contains an empty value.
Private variables
In GNU make it is possible to set a variable in a target-specific manner. Such a variable is only visible in the scope of this target, that is, in the rule recipes and when setting other target-specific variables. For example:
foo: x := bar foo: y := $x foo: @echo $x $y
One curious feature of target-specific variables in GNU make is the inheritance of such variables by the prerequisites of this target, provided that the making of the target triggered the making of the prerequisite. The following makefile fragment is the canonical motivating example for this feature:
debug: CFLAGS := -g debug: driver.o $(CC) $(CFLAGS) -o $@ $^ release: driver.o $(CC) $(CFLAGS) -o $@ $^ driver.o: driver.c $(CC) $(CFLAGS) -c -o $@ $<
Here, if we run make as make debug
, the debug target will trigger the update of driver.o
and as a result the debug
target’s CFLAGS
value will be inherited by this prerequisite.
While this feature could be useful, such uncontrolled inheritance can also cause problems. There is also the view that building the same prerequisite differently depending on which target triggered the rebuild is a bad idea (consider what will happen in the above example if we had an up-to-date driver.o
file that was created with the make release
invocation).
In GNU make 3.82 it is now possible to mark a target-specific variable as private which means that it will not be inherited by the prerequisites:
debug: private CFLAGS := -g
It is also possible to mark a global variable private. In this case the variable will not be visible to any targets and their recipes.
New pattern ordering
Before this release, GNU make would match pattern rules (and pattern-specific variables) in the order they were defined. The first rule that matches is then used. Consider the following example:
%.o: src/%.c $(CC) $(CFLAGS) -o $@ $^ pic/%.o: src/%.c $(CC) -fPIC $(CFLAGS) -o $@ $^ all: libfoo.so libfoo.a libfoo.a: foo.o libfoo.so: pic/foo.o
Here we want to use a special rule to compile position-independent code and the normal rule otherwise. The problem is that the normal rule will also match the position-independent files. It is easy to fix this makefile by simply reordering the rules. However, this approach may not scale to more complex, multi-makefile build systems. To address this issue, GNU make now tries the rules in the shortest stem first order which results in the more specific rules being preferred over the more generic ones.