Previous Page
Next Page

19.3. Rules

Example 19-1 shows a makefile that might be used to build the program in Example 1-2.

Example 19-1. A basic makefile
# A basic makefile for "circle".
CC = gcc
CFLAGS = -Wall -g -std=c99
circle : circle.o circulararea.o
        $(CC) $(LDFLAGS) -o $@ $^
circle.o : circle.c
        $(CC) $(CFLAGS) -o $@ -c $<
circulararea.o: circulararea.c
        $(CC) $(CFLAGS) -o $@ -c $<

The line that begins with the character # is a comment, which make ignores. This makefile begins by defining some variables, which are used in the statements that follow. The rest of the file consists of rules, whose general form is:

target [target [...]] : [prerequisite[prerequisite[...]]]

The first target must be placed at the beginning of the line, with no whitespace to the left of it. Moreover, each command line must start with a tab character. (It would be simpler if all whitespace characters were permissible here, but that's not the case.)

Each rule in the makefile says, in effect: if any target is older than any prerequisite, then execute the command script. More importantly, make also checks whether the prerequisites have other prerequisites in turn before it starts executing commands.

Both the prerequisites and the command script are optional. A rule with no command script only tells make about a dependency relationship; and a rule with no prerequisites tells only how to build the target, not when to build it. You can also put the prerequisites for a given target in one rule, and the command script in another. For any target requested, whether on the make command line or as a prerequisite for another target, make collects all the pertinent information from all rules for that target before it acts on them.

Example 19-1 shows two different notations for variable references in the command script. Variable names that consist of more than one characterin this case, CC, CFLAGS, and LDFLAGSmust be prefixed with a dollar sign and enclosed in parentheses when referenced. Variables that consist of just one characterin our example, these happen to be the automatic variables ^, <, and @need just the dollar sign, not the parentheses. We discuss variables in detail in a separate section later in this chapter. The following program output shows how make expands both kinds of variables to generate compiler commands:

$ make -n -f Makefile19-1 circle
gcc -Wall -g -std=c99 -o circle.o -c circle.c
gcc -Wall -g -std=c99 -o circulararea.o -c circulararea.c
gcc -lm -o circle circle.o circulararea.o

The command-line option -n instructs make to print the commands it would otherwise execute to build the specified targets. This option is indispensable when testing makefiles. (A complete reference list of make options is included at the end of this chapter.) The final line of output corresponds to the first rule contained in Example 19-1. It shows that make expands the variable reference $(CC) to the text gcc and $(LDFLAGS) to -lm. The automatic variables $@ and $^ expand to the target circle and the prerequisite list circle.o circulararea.o. In the first two output lines, the automatic variable $< is expanded to just one prerequisite, which is the name of the C source file to be compiled.

19.3.1. The Command Script

The command script for a rule can consist of several lines, each of which must begin with a tab. Comments and blank lines are ignored, so that the command script ends with the next target line or variable definition.

Furthermore, the first line of the command script may be placed after a semicolon at the end of the dependency line, thus:

target_list : [prerequisite_list] ; [command

This variant is rarely used today, however.

The important thing to remember about the command part of a make rule is that it is not a shell script. When make invokes a rule to build its target, each line in the rule's command section is executed individually, in a separate shell instance. Thus you must make sure that no command depends on the side effects of a preceding line. For example, the following commands will not run etags in the src subdirectory:

        cd src/
        etags *.c

In trying to build TAGS, make runs the shell command cd src/ in the current directory. When that command exits, make runs etags *.c in a new shell, again in the current directory.

There are ways to cause several commands to run in the same shell: putting them on one line, separated by a semicolon, or adding a backslash to place them virtually on one line:

        cd src/    ;\
        etags *.c

Another reason for running multiple commands in the same shell could be to speed up processing, especially in large projects.

19.3.2. Pattern Rules

The last two rules in Example 19-1 show a repetitive pattern. Each of the two object files, circle.o and circulararea.o, depends on a source file with the same name and the suffix .c, and the commands to build them are the same. make lets you describe such cases economically using pattern rules . Here is a single rule that replaces the last two rules in Example 19-1:

circulararea.o circle.o: %.o: %.c
        $(CC) $(CFLAGS) -o $@ -c $<

The first line of this rule has three colon-separated parts rather than two. The first part is a list of the targets that the rule applies to. The rest of the line, %.o: %.c, is a pattern explaining how to derive a prerequisite name from each of the targets, using the percent sign (%) as a wildcard. When make matches each target in the list against the pattern %.o, the part of the target that corresponds to the wildcard % is called the stem. The stem is then substituted for the percent sign in %.c to yield the prerequisite.

The general syntax of such pattern rules is:

[target_list :] target_pattern : prerequisite_pattern

You must make sure that each target in the list matches the target pattern. Otherwise, make issues an error message.

If you include an explicit target list, the rule is a static pattern rule. If you omit the target list, the rule is called an implicit rule, and applies to any target whose name matches the target pattern. For example, if you expect to add more modules as the circle program grows and evolves, you can make a rule for all present and future object files in the project like this:

%.o: %.c
        $(CC) $(CFLAGS) -o $@ -c $<

And if a certain object needs to be handled differently for some reason, you can put a static pattern rule for that object file in the makefile as well. make then applies the static rule for targets explicitly named in it, and the implicit rule for all other .o files. Also, make refrains from announcing an error if any object file's implicit prerequisite does not exist.

The percent sign is usually used only once in each pattern. To represent a literal percent sign in a pattern, you must escape it with a backslash. For example, the filename app%3amodule.o matches the pattern app\%3a%.o, and the resulting stem is module. To use a literal backslash in a pattern without escaping a percent sign that happens to follow it, you need to escape the backslash itself. Thus the filename app\module.o would match the pattern app\\%.o, yielding the stem module.

19.3.3. Suffix Rules

The kind of pattern rule in which the percent sign represents all but the filename's suffix is the modern way of expressing a suffix rule. In older makefiles, you might see such a rule expressed in the following notation:

        $(CC) $(CFLAGS) ...

The "target" in this rule consists simply of the target and source filename suffixesand in the opposite order; that is, with the source suffix first, followed by the target suffix. This example with the target .c.o: is equivalent to a pattern rule beginning with %o: %c. If a suffix rule target contains only one suffix, then that is the suffix for source filenames, and target filenames under that rule are assumed to have no suffix.

GNU make also supports suffix rules , but that notation is considered obsolete. Pattern rules using the % wildcard character are more readable, and more versatile.

Every suffix used in the target of a suffix rule must be a "known suffix." make stores its list of known suffixes in the built-in variable SUFFIXES. You can add your own suffixes by declaring them as prerequisites of the built-in target .SUFFIXES (see the section "Special Targets Used as Runtime Options," near the end of this chapter, for more about his technique).

19.3.4. Built-in Rules

You don't have to tell make how to do standard operations like compiling an object file from C source; the program has a built-in default rule for that operation, and for many others. Example 19-2 shows a more elegant version of our sample makefile that takes advantage of built-in rules .

Example 19-2. A makefile using built-in rules
# A slightly more elegant makefile for "circle".
CC = gcc
CFLAGS = -Werror -std=c99
OBJS =  circle.o circulararea.o
circle: $(OBJS) -lm

This makefile does away with the rule for compiling source code into objects, depending instead on make's built-in pattern rule. Furthermore, the rule that says the executable circle depends on the two object files has no command script. This is because make also has a built-in rule to link objects to build an executable. We will look at those built-in rules in a moment. First, suppose we enter this command:

$ touch *.c ; make circle

This produces roughly the same output as before:

gcc -Werror -std=c99   -c -o circle.o circle.c
gcc -Werror -std=c99   -c -o circulararea.o circulararea.c
gcc circle.o circulararea.o  /usr/lib/  -o circle

None of these commands is visible in the new makefile in Example 19-2, even if individual arguments are recognizable in the variable assignments. To display make's built-in rules (as well as the variables at work), you can run the program with the command-line switch -p. The output is rather long. Here are the parts of it that are relevant to our example (including the comments that make generates to identify where each variable or rule definition originates):

# default
# default
# default
%: %.o
#  commands to execute (built-in):
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.c
#  commands to execute (built-in):
        $(COMPILE.c) $(OUTPUT_OPTION) $<

Note that the linking step was handled by a combination of two rules; make automatically applied the command defined by the built-in rule using the information about the prerequisites provided by the dependency rule in the makefile.

Finally, the makefile in Example 19-2, unlike Example 19-1, does not define a variable for linker options. Instead, it correctly lists the C math library as a prerequisite of the executable circle, using the same -lm notation as the compiler's command line. The output shown illustrates how make expands this notation to the full library filename.

19.3.5. Implicit Rule Chains

make tries to use implicit rules, whether built-in ones or pattern rules from the makefile, for any target that doesn't have an explicit rule with a command script. There may be many implicit rules that match a given target. For example, make has built-in rules to generate an object file (matching the pattern %.o) from source code in C (%.c) or C++ (%.cpp) or even assembler (%.s). Which rule does make use, then? It selects the first one in the list for which the prerequisites either are available or can be made by applying appropriate rules. In this way, make can automatically apply a chain of implicit rules to generate a target. If make generates any intermediate files that are not mentioned in the makefile, it deletes them once they have served their purpose. For example, suppose that the current directory contains only the file square.c, and the makefile contains the following:

%: %.o
        cc -o $@ $^
%.o : %.c
        cc -c -o $@ $<

To disable all the built-in rules and use only the two implicit rules we can see in the makefile, we'll run make with the -r option:

$ ls
Makefile  square.c
$ make -r square
cc -c -o square.o square.c
cc -o square square.o
rm square.o
$ ls
Makefile square  square.c

From the target, the two implicit rules in the makefile, and the available source file, make found the indirect way to build the target, and then automatically cleaned up the intermediate object file, because it isn't mentioned in the makefile or on the command line.

19.3.6. Double-Colon Rules

Before we move away from rules, another kind of rule that you should know about is the double-colon rule, so named because it has not one, but two colons between the targets and the prerequisites:

target :: prerequisites

Double-colon rules are the same as single-colon rules, unless your makefile contains multiple double-colon rules for the same target. In that case, make treats the rules as alternative rather than cumulative: instead of collating all the rules' prerequisites into a single set of dependencies for the target, make tests the target against each rule's prerequisites separately to decide whether to execute that rule's script. Example 19-3 shows a makefile that uses double-colon rules.

Example 19-3. Double-colon rules
# A makefile for "circle" to demonstrate double-colon rules.
CC = gcc
RM = rm -f
CFLAGS = -Wall -std=c99
DBGFLAGS = -ggdb -pg
DEBUGFILE = ./debug
SRC = circle.c circulararea.c
circle :: $(SRC)
        $(CC) $(CFLAGS) -o $@ -lm $^
circle :: $(DEBUGFILE)
        $(CC) $(CFLAGS) $(DBGFLAGS) -o $@ -lm $(SRC)
.PHONY : clean
clean  :
        $(RM) circle

The makefile in Example 19-3 builds the target circle in either of two ways, with or without debugging options in the compiler command line. In the first rule for circle, the target depends on the source files. make runs the command for this rule if the source files are newer than the executable. In the second rule, circle depends on a file named debug in the current directory. The command for that rule doesn't use the prerequisite debug at all. That file is empty; it just sits in the directory for the sake of its timestamp, which tells make whether to build a debugging version of the circle executable. The following sample session illustrates how make can alternate between the two rules:

$ make clean
rm -f circle
$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c circulararea.c
$ make circle
make: `circle' is up to date.
$ touch debug
$ make circle
gcc -Wall -std=c99 -ggdb -pg -o circle -lm circle.c circulararea.c
$ make circle
make: `circle' is up to date.
$ make clean
rm -f circle
$ make circle
gcc -Wall -std=c99 -o circle -lm circle.c circulararea.c

As the output shows, make applies only one rule or the other, depending on which rule's prerequisites are newer than the target. (If both rules' prerequisites are newer than the target, make applies the rule that appears first in the makefile.)

Previous Page
Next Page