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