Previous Page
Next Page

19.5. Variables

All variables in make are of the same type: they contain sequences of characters, never numeric values. Whenever make applies a rule, it evaluates all the variables contained in the targets, prerequisites, and commands. Variables in GNU make come in two "flavors," called recursively expanded and simply expanded variables. Which flavor a given variable has is determined by the specific assignment operator used in its definition. In a recursively expanded variable, nested variable references are stored verbatim until the variable is evaluated. In a simply expanded variable, on the other hand, variable references in the value are expanded immediately on assignment, and their expanded values are stored, not their names.

Variable names can include any character except :, =, and #. However, for robust makefiles and compatibility with shell constraints, you should use only letters, digits, and the underscore character.

19.5.1. Assignment Operators

Which assignment operator you use in defining a variable determines whether it is a simply or a recursively expanded variable. The assignment operator = in the following example creates a recursively expanded variable:

DEBUGFLAGS = $(CFLAGS) -ggdb -DDEBUG -O0

make stores the character sequence to the right of the equals sign verbatim; the nested variable $(CFLAGS) is not expanded until $(DEBUGFLAGS) is used.

To create a simply expanded variable, use the assignment operator := as shown in the following example:

OBJ = circle.o circulararea.o
TESTOBJ := $(OBJ) profile.o

In this case make stores the character sequence circle.o circulararea.o profile.o as the value of $(TESTOBJ). If a subsequent assignment modifies the value of $(OBJ), $(TESTOBJ) is not affected.

You can define both recursively expanded and simply expanded variables not only in the makefile, but also on the make command line, as in the following example:

$ make CFLAGS=-ffinite-math-only circulararea.o

Each such assignment must be contained in a single command-line argument. If the assignment contains spaces, you must escape them or enclose the entire assignment in quotation marks. Any variable defined on the command line, or in the shell environment, can be cancelled out by an assignment in the makefile that starts with the optional override keyword, as this one does:

override CPPLFAGS = -DDEBUG

Use override assignments with caution, unless you want to confuse and frustrate future users of your makefile.

make also provides two more assignment operators. Here is the complete list:


=

Defines a recursively expanded variable.


:=

Defines a simply expanded variable.


+=

Also called the append operator. Appends more characters to the existing value of a variable. If the left operand is not yet defined, the assignment defines a recursively expanded variable. Or, to put it another way, the result of the append operator is a recursively expanded variable, unless its left operand already exists as a simply expanded variable.

This operator provides the only way to append characters to the value of a recursively expanded variable. The following assignment is wrong, as recursive expansion would cause an infinite loop:

OBJ = $(OBJ) profile.o

Here is the right way to do it:

OBJ += profile.o

The += operator automatically inserts a space before appending the new text to the variable's previous value.


?=

The conditional assignment operator. Assigns a value to a variable, but only if the variable has no value.

The conditional assignment operator can only define recursively expanded variables. If its left operand already exists, it remains unaffected, regardless of whether it is a simply expanded or a recursively expanded variable.

In addition to these operations, there are two more ways to define make variables. One is the define directive, used to create variables of multiple lines; we will discuss this in the section "Macros," later in this chapter. Another is by setting environment variables in the system shell before you invoke make. We will discuss make's use of environment variables later in the chapter as well.

19.5.2. Variables and Whitespace

In a variable assignment, make ignores any whitespace between the assignment operator and the first non-whitespace character of the value. However, trailing whitespace up to the end of the line containing the variable assignment, or up to a comment that follows on the same line, becomes part of the variable's value. Usually this behavior is unimportant, because most references to make variables are options in shell command lines, where additional whitespace has no effect. However, if you use variable references to construct file or directory names, unintended whitespace at the end of an assignment line can be fatal.

On the other hand, if you develop complex makefiles, you could sometimes need a literal space that make does not ignore or interpret as a list separator. The easiest way is to use a variable whose value is a single space character, but defining such a variable is tricky. Simply enclosing a space in quotation marks does not have the same effect as in C. Consider the following assignment:

ONESPACE := ' '
TEST = Does$(ONESPACE)this$(ONESPACE)work?

In this case, a reference to $(TEST) would expand to the following text:

Does' 'this' 'work?

Double quotation marks are no different: they also become part of the variable's value. To define a variable containing just the space and nothing else, you can use the following lines:

NOTHING :=
ONESPACE := $(NOTHING) # This comment terminates the variable's value.

The variable reference $(NOTHING) expands to zero characters, but it ends the leading whitespace that make trims off after the assignment operator. If you do not insert a comment after the space character that follows $(NOTHING), you may find it hard to tell when editing the makefile whether the single trailing space is present as desired.

19.5.3. Target-Specific Variable Assignments

You can make any of the assignment operations apply to only a specific target (or target pattern) by including a line in your makefile with the form:

target_list: [override] assignment

While make is building the given targetor its prerequisitesthe target-specific or pattern-specific variable supersedes any other definition of the same variable name elsewhere in the makefile.

Example 19-4 shows a sample makefile illustrating different kinds of assignments.

Example 19-4. Variable assignments
# Tools and options:
CC = gcc
CFLAGS = -c -Wall -std=c99 $(ASMFLAGS)
DEBUGCFLAGS = -ggdb -O0
RM = rm -f
MKDIR = mkdir -p
 
# Filenames:
OBJ = circle.o circulararea.o
SYMTABS = $(OBJ .o=.sym)
EXEC = circle
 
# The primary targets:
production: clean circle
 
testing: clean debug
 
symbols: $(SYMTABS)
 
clean:
        $(RM) $(OBJ) *.sym circle dcircle
 
# Rules to build prerequisites:
circle debug: $(OBJ) -lm
        $(CC) $(LDFLAGS) -o $(EXEC) $^
 
$(OBJ): %.o: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $<
 
$(SYMTABS): %.sym: %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -o $*.o $<
 
# Target-specific options:
debug: CPPFLAGS += -DDEBUG
debug: EXEC = circle-dbg
debug symbols: CFLAGS += $(DEBUGCFLAGS)
symbols: ASMFLAGS = -Wa,-as=$*.sym,-L

For the targets debug and symbols, this makefile uses the append operator to add the value of DEBUGCFLAGS to the value of CFLAGS, while conserving any compiler flags already defined.

The assignment to SYMTABS illustrates another feature of make variables: you can perform substitutions when referencing them. As Example 19-4 illustrates, a substitution reference has this form:

$(name: ending=new_ending)

When you reference a variable in this way, make expands it, then checks the end of each word in the value (where a word is a sequence of non-whitespace characters followed by a whitespace character, or by the end of the value) for the string ending. If the word ends with ending, make replaces that part with new_ending. In Example 19-4, the resulting value of $(SYMTABS) is circle.sym circulararea.sym.

The variable CFLAGS is defined near the top of the makefile, with an unconditional assignment. The expansion of the nested variable it contains, $(ASMFLAGS), is deferred until make expands $(CFLAGS) in order to execute the compiler command. The value of $(ASMFLAGS) for example may be -Wa,-as=circle.sym,-L, or it may be nothing. When make builds the target symbols, the compiler command expands recursively to:

gcc -c -Wall -std=c99 -Wa,-as=circle.sym,-L -ggdb -O0   -o circle.o circle.c
gcc -c -Wall -std=c99 -Wa,-as=circulararea.sym,-L -ggdb -O0   -o circulararea.o 
circulararea.c

As you can see, if there is no variable defined with the name CPPFLAGS at the time of variable expansion, make simply replaces $(CPPFLAGS) with nothing.

Unlike C, make doesn't balk at undefined variables. The only difference between an undefined variable and a variable whose value contains no characters is that a defined variable has a determined flavor: it is either simply expanded or recursively expanded, and cannot change its behavior, even if you assign it a new value.


Like many real-life makefiles, the one in Example 19-4 uses variables to store the names of common utilities like mkdir and rm together with the standard options that we want to use with them. This approach not only saves repetition in the makefile's command scripts, but also makes maintenance and porting easier.

19.5.4. The Automatic Variables

The command scripts in Example 19-4 also contain a number of single-character variables: $@, $<, $^, and $*. These are automatic variables, which make defines and expands itself in carrying out each rule. Here is a complete list of the automatic variables and their meanings in a given rule:


$@

The target filename.


$*

The stem of the target filenamethat is, the part represented by % in a pattern rule.


$<

The first prerequisite.


$^

The list of prerequisites, excluding duplicate elements.


$?

The list of prerequisites that are newer than the target.


$+

The full list of prerequisites, including duplicates.


$%

If the target is an archive member, the variable $% yields the member name without the archive filename, and $@ supplies the filename of the archive.

The last of these automatic variables brings up a special target case. Because most programs depend not only on source code, but also on library modules, make also provides a special notation for targets that are members of an archive:

archive_name(member_name): [prerequisites]
        [command_script]

The name of the archive member is enclosed in parentheses immediately after the filename of the archive itself. Here is an example:

AR = ar -rv
 
libcircularmath.a(circulararea.o): circulararea.o
      $(AR) $@ $%

This rule executes the following command to add or replace the object file in the archive:

ar -rv libcircularmath.a circulararea.o

In other make versions, these special variables also have long names that start with a dot, such as $(.TARGET) as a synonym for $@. Also, some make programs use the symbol $> for all prerequisites rather than GNU make's $^.

When an automatic variable expands to a list, such as a list of filenames, the elements are separated by spaces.

To separate filenames from directories, there are two more versions of each automatic variable in this list whose names are formed with the suffixes D and F. Because the resulting variable name is two characters, not one, parentheses are required. For example, $(@D) in any rule expands to the directory part of the target, without the actual filename, while $(@F) yields just the filename with no directory. (GNU make supports these forms for compatibility's sake, but provides more flexible handling of filenames by means of functions: see the section "Built-in Functions," later in this chapter.)

19.5.5. Other Built-in Variables

The variables that make uses internally are described in the following list. You can also use them in makefiles. Remember that you can find out the sources of all variables in the output of make -p.


MAKEFILES

A list of standard makefiles that make reads every time it starts.


MAKEFILE_LIST

A list of all the makefiles that the present invocation of make is using.


MAKE

This variable holds the name of the make executable. When you use $(MAKE) in a command, make automatically expands it to the full path name of the program file, so that all recursive instances of make are from the same executable.


MAKELEVEL

When make invokes itself recursively, this variable holds the degree of recursion of the present instance. In exporting this variable to the environment, make increments its value. Child instances of make print this number in square brackets after the program name in their console output.


MAKEFLAGS

This variable contains the command-line options with which make was invoked, with some exceptions. Each instance of make reads this variable from the environment on starting, and exports it to the environment before spawning a recursive instance. You can modify this variable in the environment or in a makefile.


MAKECMDGOALS

make stores any targets specified on the command line in this variable. You can modify this variable, but doing so doesn't change the targets make builds.


CURDIR

This variable holds the name of the current working directory, after make has processed its -C or --directory command-line options. You can modify this variable, but doing so doesn't change the working directory.


VPATH

The directory path that make uses to search for any files not found in the current working directory.


SHELL

The name of the shell that make invokes when it runs command scripts, usually /bin/sh. Unlike most variables, make doesn't read the value of SHELL from the environment (except on Windows), as users' shell preferences would make make's results less consistent. If you want make to run commands using a specific shell, you must set this variable in your makefile.


MAKESHELL

On Windows, this variable holds the name of the command interpreter for make to use in running command scripts. MAKESHELL overrides SHELL.


SUFFIXES

make's default list of known suffixes (see "Suffix Rules," earlier in this chapter). This variable contains the default list, which is not necessarily the list currently in effect; the value of this variable does not change when you clear the list or add your own known suffixes using the built-in target .SUFFIXES.


.LIBPATTERNS

A list of filename patterns that determines how make searches for libraries when a prerequisite starts with -l. The default value is lib%.so lib%.a. A prerequisite called -lm causes make to search for libm.so and libm.a, in that order.

19.5.6. Environment Variables

If you want, you can set environment variables in the shell before starting make, and then reference them in the makefile using the same syntax as for other make variables. Furthermore, you can use the export directive in the makefile to copy any or all of make's variables to the shell environment before invoking shell commands, as in the following example:

INCLUDE=/usr/include:/usr/local/include:~/include
export INCLUDE
export LIB := $(LIBS):/usr/lib:/usr/local/lib
 
%.o: %.c
        $(CC) $(CFLAGS) -o $@ -c $<

When the C compiler is invoked by the pattern rule in this example, it can obtain information defined in the makefile by reading the environment variables INCLUDE and LIB. Similarly, make automatically passes its command-line options to child instances by copying them to and then exporting the variable MAKEFLAGS. See the section "Recursive make Commands," later in this chapter, for other examples.

The shell environment is more restrictive than make with regard to the characters that are permitted in variable names and values. It might be possible to trick your shell into propagating environment variables containing illegal characters, but the easiest thing by far is just to avoid special characters in any variables you want to export.


Previous Page
Next Page