2.4 Pattern Rules

     

The makefile examples we've been looking at are a bit verbose. For a small program of a dozen files or less we may not care, but for programs with hundreds or thousands of files, specifying each target, prerequisite, and command script becomes unworkable. Furthermore, the commands themselves represent duplicate code in our makefile . If the commands contain a bug or ever change, we would have to update all these rules. This can be a major maintenance problem and source of bugs .

Many programs that read one file type and output another conform to standard conventions. For instance, all C compilers assume that files that have a .c suffix contain C source code and that the object filename can be derived by replacing the .c suffix with .o (or .obj for some Windows compilers). In the previous chapter, we noticed that flex input files use the .l suffix and that flex generates .c files.

These conventions allow make to simplify rule creation by recognizing common filename patterns and providing built-in rules for processing them. For example, by using these built-in rules our 17-line makefile can be reduced to:

 VPATH    = src include CPPFLAGS = -I include count_words: counter.o lexer.o -lfl count_words.o: counter.h counter.o: counter.h lexer.h lexer.o: lexer.h 

The built-in rules are all instances of pattern rules. A pattern rule looks like the normal rules you have already seen except the stem of the file (the portion before the suffix) is represented by a % character. This makefile works because of three built-in rules. The first specifies how to compile a .o file from a .c file:

 %.o: %.c         $(COMPILE.c) $(OUTPUT_OPTION) $< 

The second specifies how to make a .c file from a .l file:

 %.c: %.l         @$(RM) $@         $(LEX.l) $< > $@ 

Finally, there is a special rule to generate a file with no suffix (always an executable) from a .c file:

 %: %.c         $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ 

We'll go into the details of this syntax in a bit, but first let's go over make 's output carefully and see how make applies these built-in rules.

When we run make on our two-line makefile , the output is:

 $  make  gcc  -I include  -c -o count_words.o src/count_words.c gcc  -I include  -c -o counter.o src/counter.c flex  -t src/lexer.l > lexer.c gcc  -I include  -c -o lexer.o lexer.c gcc   count_words.o counter.o lexer.o /lib/libfl.a   -o count_words rm lexer.c 

First, make reads the makefile and sets the default goal to count_words since there are no command-line targets specified. Looking at the default goal, make identifies four prerequisites: count_words.o (this prerequisite is missing from the makefile , but is provided by the implicit rule), counter.o , lexer.o , and -lfl . It then tries to update each prerequisite in turn .

When make examines the first prerequisite, count_words.o , make finds no explicit rule for it but discovers the implicit rule. Looking in the local directory, make cannot find the source, so it begins searching the VPATH and finds a matching source file in src . Since src/count_words.c has no prerequisites, make is free to update count_words.o so it runs the commands for the implicit rule. counter.o is similar. When make considers lexer.o , it cannot find a corresponding source file (even in src ) so it assumes this (nonexistent source) is an intermediate file and looks for a way to make lexer.c from some other source file. It discovers a rule to create a .c file from a .l file and notices that lexer.l exists. There is no action required to update lexer.l , so it moves on to the command for updating lexer.c , which yields the flex command line. Next make updates the object file from the C source. Using sequences of rules like this to update a target is called rule chaining .

Next, make examines the library specification -lfl . It searches the standard library directories for the system and discovers /lib/libfl.a .

Now make has all the prerequisites for updating count_words , so it executes the final gcc command. Lastly, make realizes it created an intermediate file that is not necessary to keep so it cleans it up.

As you can see, using rules in makefile s allows you to omit a lot of detail. Rules can have complex interactions that yield very powerful behaviors. In particular, having a built-in database of common rules makes many types of makefile specifications very simple.

The built-in rules can be customized by changing the values of the variables in the command scripts. A typical rule has a host of variables, beginning with the program to execute, and including variables to set major groupings of command-line options, such as the output file, optimization, debugging, etc. You can look at make 's default set of rules (and variables) by running make ”print-data-base .

2.4.1 The Patterns

The percent character in a pattern rule is roughly equivalent to * in a Unix shell. It represents any number of any characters . The percent character can be placed anywhere within the pattern but can occur only once. Here are some valid uses of percent:

 %,v s%.o wrapper_% 

Characters other than percent match literally within a filename. A pattern can contain a prefix or a suffix or both. When make searches for a pattern rule to apply, it first looks for a matching pattern rule target. The pattern rule target must start with the prefix and end with the suffix (if they exist). If a match is found, the characters between the prefix and suffix are taken as the stem of the name . Next make looks at the prerequisites of the pattern rule by substituting the stem into the prerequisite pattern. If the resulting filename exists or can be made by applying another rule, a match is made and the rule is applied. The stem word must contain at least one character.

It is also possible to have a pattern containing only a percent character. The most common use of this pattern is to build a Unix executable program. For instance, here are several pattern rules GNU make includes for building programs:

 %: %.mod         $(COMPILE.mod) -o $@ -e $@ $^ %: %.cpp         $(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@ %: %.sh         cat $< >$@         chmod a+x $@ 

These patterns will be used to generate an executable from a Modula source file, a preprocessed C source file, and a Bourne shell script, respectively. We will see many more implicit rules in Section 2.5.

2.4.2 Static Pattern Rules

A static pattern rule is one that applies only to a specific list of targets.

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

The only difference between this rule and an ordinary pattern rule is the initial $(OBJECTS) : specification. This limits the rule to the files listed in the $(OBJECTS) variable.

This is very similar to a pattern rule. Each object file in $(OBJECTS) is matched against the pattern %.o and its stem is extracted. The stem is then substituted into the pattern %.c to yield the target's prerequisite. If the target pattern does not exist, make issues a warning.

Use static pattern rules whenever it is easier to list the target files explicitly than to identify them by a suffix or other pattern.

2.4.3 Suffix Rules

Suffix rules are the original (and obsolete) way of defining implicit rules. Because other versions of make may not support GNU make 's pattern rule syntax, you will still see suffix rules in makefile s intended for a wide distribution so it is important to be able to read and understand the syntax. So, although compiling GNU make for the target system is the preferred method for makefile portability, you may still need to write suffix rules in rare circumstances.

Suffix rules consist of one or two suffixes concatenated and used as a target:

 .c.o:         $(COMPILE.c) $(OUTPUT_OPTION) $< 

This is a little confusing because the prerequisite suffix comes first and the target suffix second. This rule matches the same set of targets and prerequisites as:

 %.o: %.c         $(COMPILE.c) $(OUTPUT_OPTION) $< 

The suffix rule forms the stem of the file by removing the target suffix. It forms the prerequisite by replacing the target suffix with the prerequisite suffix. The suffix rule is recognized by make only if the two suffixes are in a list of known suffixes.

The above suffix rule is known as a double-suffix rule since it contains two suffixes. There are also single-suffix rules. As you might imagine a single-suffix rule contains only one suffix, the suffix of the source file. These rules are used to create executables since Unix executables do not have a suffix:

 .p:         $(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@ 

This rule produces an executable image from a Pascal source file. This is completely analogous to the pattern rule:

 %: %.p         $(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@ 

The known suffix list is the strangest part of the syntax. A special target, .SUFFIXES , is used to set the list of known suffixes. Here is the first part of the default .SUFFIXES definition:

 .SUFFIXES: .out .a .ln .o .c .cc .C .cpp .p .f .F .r .y .l 

You can add your own suffixes by simply adding a .SUFFIXES rule to your makefile :

 .SUFFIXES: .pdf .fo .html .xml 

If you want to delete all the known suffixes (because they are interfering with your special suffixes) simply specify no prerequisites:

 .SUFFIXES: 

You can also use the command-line option ”no-builtin-rules (or -r ).

We will not use this old syntax in the rest of this book because GNU make 's pattern rules are clearer and more general.



Managing Projects with GNU make
Managing Projects with GNU Make (Nutshell Handbooks)
ISBN: 0596006101
EAN: 2147483647
Year: 2003
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net