Makefile Variables


Makefile Variables

GNU make provides support for a form of variable that closely resembles the variables provided in the standard UNIX shells . The variables allow a name to be associated with an arbitrarily long text string. The basic syntax to assign a value to a variable is:

 MY_VAR = A text string 

This results in the creation of a variable named MY_VAR with a value of A text string . The value of a variable can be retrieved in subsequent portions of the Makefile by using the following syntax: ${var-name} , where var-name is replaced with the name of the variable that is being retrieved. Listing 5.3 provides an example Makefile to illustrate the basic use of variables in a Makefile.

Listing 5.3: Simple Variable Makefile (on the CD-ROM at ./source/ch5/_Makefile.simpvar )
start example
  1:   2:  MY_VAR=file1.c file2.c      3:      4:     all:      5:     echo ${MY_VAR}  6:  
end example
 

Line 2 assigns the value file1.c file2.c to the MY_VAR variable. When the make utility is invoked, it will attempt to build the all target defined on line 4. The command on line 5 will be executed, and the output is illustrated in Listing 5.4.

Listing 5.4: Simple Variable Makefile Output
start example
  1:   2:  $ make      3:     echo file1.c file2.c      4:     file1.c file2.c  5:  
end example
 

Line 2 is the invocation of the make utility. Line 3 is output by the make utility when it runs the command on line 5 of Listing 5.3. Notice that the variable replacement has already occurred by this point in the execution. Line 4 is the actual output from the echo command that make invokes.

GNU make allows the value in a variable to be constructed incrementally by providing the ability to concatenate strings to the existing value of a variable. GNU make syntax uses the addition symbol to indicate a concatenation operation. Listing 5.5 illustrates this by modifying the simple Makefile in Listing 5.3 to use the concatenation operation when creating the value in the MY_VAR variable.

Listing 5.5: Variable Concatenation Makefile (on the CD-ROM at ./source/ch5/_Makefile.varconcat )
start example
  1:   2:  MY_VAR=file1.c      3:     MY_VAR+=file2.c      4:      5:     all:      6:     echo ${MY_VAR}  7:  
end example
 

Running make against the Makefile in Listing 5.5 should generate the exact same output, illustrated in Listing 5.4, as the Makefile in Listing 5.3.

GNU make provides a wide range of built-in functionality to operate on defined variables. Functions are provided for general string handling operations such as substitution, stripping, and tokenizing. A common use of variables in Makefiles is to store and manipulate filenames and paths that are involved in the make process. To facilitate this use of variables, GNU make provides specialized functions that operate on the contents of a variable as a path or filename. The contrived Makefile in Listing 5.6 illustrates the use of some of the functions provided by GNU make . Listing 5.7 illustrates the expected output from running the make utility on the Makefile in Listing 5.6.

Listing 5.6: Variable Manipulation Makefile (on the CD-ROM at ./source/ch5/_Makefile.varmanip )
start example
  1  :  2  :     SRC_VAR=My test string for variable manipulation.  3  :  4  :     TEST1_VAR=$(subst for,foo,${SRC_VAR})  5  :     TEST2_VAR=$(patsubst t%t,T%T, ${SRC_VAR})  6:  TEST3_VAR=$(filter %ing %able, ${SRC_VAR})  7:  TEST4_VAR=$(sort ${SRC_VAR})  8:  TEST5_VAR=$(words ${SRC_VAR})  9:  TEST6_VAR=$(word 2,${SRC_VAR})  10:  TEST7_VAR=$(wordlist 2, 3, ${SRC_VAR})  11:   12:  all:  13:  @echo original str: ${SRC_VAR}  14:  @echo substitution: ${TEST1_VAR}  15:  @echo pattern sub : ${TEST2_VAR}  16:  @echo filter   : ${TEST3_VAR}  17:  @echo sort    : ${TEST4_VAR}  18:  @echo word count : ${TEST5_VAR}  19:  @echo word 2   : ${TEST6_VAR}  20:  @echo word 2 thru 4: ${TEST7_VAR} 
end example
 

Line 2 sets up the source string that will be used to exercise the GNU make string manipulation functions. Lines 4 “10 illustrate the use of the Makefile functions: subst , patsubst , filter , sort , words , word , and wordlist . Notice that the make file syntax for a function call takes the general form of ${func arg1,arg2,...) . Lines 13 “20 output the results when the Makefile is evaluated. Notice the use of the @ before the echo commands in lines 13 “20, which tells the make utility to suppress the printing of the command line before it executes.

Listing 5.7: Output from the Makefile in Listing 5.6
start example
  1:   2:  original str: My test string for variable manipulation.  3:  substitution: My test string foo variable manipulation.  4:  pattern sub : My TesT string for variable manipulation.  5:  filter : string variable  6:  sort : My for manipulation. string test variable  7:  word count : 6  8:  word 2 : test  9:  word 2 thru 4: test string 
end example
 

Line 2 outputs the value of the original string that will be manipulated with the Makefile functions. Line 3 illustrates the output of the subst function, substituting the word for with the word foo . Line 4 illustrates the output of the patsubst function; the word test has been modified to TesT . Notice how the patsubst function uses the wildcard % to match one or more characters in a pattern. The result of the wildcard match can then be substituted back into the replacement string by using the % character. Line 5 illustrates the use of the filter function, which again makes use of the % wildcard character to match words ending in ing or able . Line 6 shows the output of the sort function that rearranges the input variables into lexical order. Line 7 illustrates the output of the words function that performs a word count operation on the input string. Line 8 illustrates the word function that allows the subsetting of a string by numerical index. In this case we have selected the second word, test . Notice that the indexes start at one rather than zero. Line 5 illustrates the wordlist function that allows a substring to be extracted based on word indexes. In the example, words 2 through 3 have been extracted, resulting in the substring test string .

The example in Listing 5.7 provides a taste of some of the string manipulation functions provided by GNU make . GNU make provides many others that can be found by consulting the GNU make documentation.

One of the primary uses of variables in a Makefile is to contain and manipulate the filename and path information associated with the build process. Take note of the use of variables in the next couple of sections, where they are employed in more realistic Makefile examples.

Pattern Matching Rules

The conversion of one type of file into another in a Makefile often follows a very specific pattern that varies only with the conversion and not the specific file. If this is the case, then GNU make provides a special type of rule that allows the target and dependencies to both be specified as patterns. Listing 5.8 contains a Makefile for the example project introduced at the beginning of this chapter. This example uses a pattern-matching rule in combination with the GNU make VPATH capability to simplify the Makefile. Still problematic is the header file dependencies that have been sequestered to the bottom of the new Makefile. The next section will introduce one mechanism for automating the processing of header dependencies.

Listing 5.8: More Realistic Makefile (on the CD-ROM at ./source/ch5/_Makefile.realistic)
start example
  1:   2:  SRC_FILES=main.c app.c bar.c lib.c  3:  OBJ_FILES=$(patsubst %.c, %.o, ${SRC_FILES})  4:   5:  VPATH = src  6:   7:  CFLAGS = -c -g  8:  LDFLAGS = -g  9:   10:  appexp: ${OBJ_FILES}  11:  gcc ${LDFLAGS} -o appexp ${OBJ_FILES}  12:   13:  %.o:%.c  14:  gcc ${CFLAGS} -o $@ :  16:  clean:  17:  rm *.o appexp  18:   19:  MAIN_HDRS=lib.h app.h  20:  LIB_HDRS=lib.h  21:   22:  main.o : $(addprefix src/, ${MAIN_HDRS})  23:  app.o : $(addprefix src/, ${MAIN_HDRS})  24:  bar.o : $(addprefix src/, ${LIB_HDRS})  25:  lib.o : $(addprefix src/, ${LIB_HDRS}) 
end example
 

This Makefile is quite different than the first one introduced in Listing 5.2, but it accomplishes the same basic task as the original Makefile. First you should notice the introduction of variables into the Makefile to allow the control parameters (compile flags, file lists, and so on) to be enumerated and set at the top of the Makefile. Lines 2 through 8 set up the variables that will control the build process. Line 3 illustrates the use of the pattern substitution function to generate a list of object files that the final application is dependent on. The pattern substitution will result in the OBJ_FILES variable being assigned the value main.o app.o bar.o lib.o . Therefore the OBJ_FILES variable now contains a list of the object files that will be needed to link the appexp executable. Line 10 is the rule that explicitly states this relationship; it uses the value of the OBJ_FILES variable as its dependency list. Lines 16 and 17 illustrate a target that is often found in standard Makefiles. The name of the target is clean , and its responsibility is to remove files that are generated by the make process. This provides a nice mechanism for a developer to clean up generated files so that a complete rebuild of the entire project can occur. Lines 15 through 25 represent the header file dependencies. It will be left to the reader to understand how this works, because in the next section a different mechanism will be introduced to handle include file dependencies automatically.

The most interesting part of Listing 5.8 is the addition on lines 5, 13, and 14. Line 13 introduces a pattern rule to indicate to the make utility how to transform an arbitrary file ending with a .c extension into a corresponding file ending in a .o extension. The transformation is accomplished by executing the commands associated with the pattern rule, in this case the command on line 14. Notice that the command on line 14 uses some special variable references to indicate the files that GCC should operate on. GNU make provides a large number of these special variables to allow the commands in a pattern rule to gain access to information about the matched files. In the specific case of line 14, the $@ variable contains the filename matched for the left side of the rule, and the $ variable contains the filename matched for the right side of the variable. GNU make provides a large number of these special variables for pattern rules that are documented in the GNU make manual. This one pattern rule replaces the four specific rules used in Listing 5.2 to build the object files.

The previous paragraph breezed over an important detail concerning the use of pattern matching rules. The pattern matching rules don t really take into account filename and path when performing comparisons. They assume that the left and right sides of the pattern rule both occur in the same directory. In the example provided in this chapter that is not the case, because the source files are one level removed from the location of the Makefile. The source files are all contained in the src directory. To resolve the situation, the VPATH feature of GNU make is used to provide the pattern matching rules with a list of search directories to use when the right side of a rule isn t found in the current directory. In line 5, the special VPATH variable is set to src so that the pattern rule on line 13 can find the source files it needs when trying to generate the object files.

So what have we gained between Listing 5.2 and Listing 5.8? The Makefile in Listing 5.8 scales much better. It attempts to make a distinction between the operations used to build an application and the files those operations are performed on. All of the variable aspects of the build process are controlled in the variables at the top of the Makefile, while the actions are contained in the rules lower in the file. Thus, to add or delete files from the build, one needs only to modify the variables at the top of the file. Listing 5.8 still has a problem with the include file tracking, but the next section illustrates how to resolve this situation.

Automatic Dependency Tracking

There are problems with including header file dependencies in a Makefile. For instance, keeping the Makefile current with the #include directives in the source files becomes problematic as the project grows. Since the preprocessor in the tool chain already has to resolve the #includes , most modern compilers provide a mechanism to output these rules automatically. The generated rules can then be used in the Makefile to track changes to the #include structure and rebuild the project appropriately. Listing 5.9 illustrates the Listing 5.8 Makefile, modified to use the automatic dependency tracking mechanism proposed in the GNU make manual.

Listing 5.9: Makefile with Dependency Tracking (on the CD-ROM at ./source/ch5/_Makefile.deptrack )
start example
  1:   2:  SRC_FILES=main.c app.c bar.c lib.c  3:  OBJ_FILES=$(patsubst %.c, %.o, ${SRC_FILES})  4:  DEP_FILES=$(patsubst %.c, %.dep, ${SRC_FILES})  5:   6:  VPATH = src  7:   8:  CFLAGS = -c -g  9:  LDFLAGS = -g  10:   11:  appexp: ${OBJ_FILES}  12:  gcc ${LDFLAGS} -o appexp ${OBJ_FILES}  13:   14:  %.o:%.c  15:  gcc ${CFLAGS} -o $@ $  16:   17:  clean:  18:  rm *.o appexp  19:   20:  include ${DEP_FILES}  21:   22:  %.dep: %.c  23:  @set -e; rm -f $@; \  24:  gcc -MM $(CFLAGS) $< > $@.$$$$; \  25:  sed 


GNU/Linux Application Programming
GNU/Linux Application Programming (Programming Series)
ISBN: 1584505680
EAN: 2147483647
Year: 2006
Pages: 203
Authors: M. Tim Jones

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