GNU make 3.82 released

The 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.

One Response to “GNU make 3.82 released”

  1. gavenkoa Says:

    “New pattern ordering” really nice feature.