外文文献—Linux编程指南.doc
附录 英文翻译第一部分 英文原文Linux_ProgrammingKurt WallCHAPTER 4 Project Management Using GNU makeIn this chapter, we take a long look at make, a tool to control the process of building (orrebuilding) software. make automates what software gets built, how it gets built, andwhen it gets built, freeing the programmer to concentrate on writing code.Why make?For all but the simplest software projects, make is essential. In the first place, projects composed of multiple source files typically require long, complex compiler invocations.make simplifies this by storing these difficult command lines in the makefile, which thenext section discusses.make also minimizes rebuild times because it is smart enough to determine which fileshave changed, and thus only rebuilds files whose components have changed. Finally,make maintains a database of dependency information for your projects and so can verifythat all of the files necessary for building a program are available each time you start abuild.Writing MakefilesSo, how does make accomplish these magical feats? By using a makefile. A makefile is a text file database containing rules that tell make what to build and how to build it. A rule consists of the following: A target, the “thing” make ultimately tries to create A list of one or more dependencies, usually files, required to build the target A list of commands to execute in order to create the target from the specified dependenciesWhen invoked, GNU make looks for a file named GNUmakefile, makefile, or Makefile,in that order. For some reason, most Linux programmers use the last form, Makefile.Makefile rules have the general form target : dependency dependency .commandcommand.The Linux Programming ToolkitPART Itarget is generally the file, such as a binary or object file, that you want created. Dependency is a list of one or more files required as input in order to create target. The commands are the steps, such as compiler invocations, necessary to create target. Unless specified otherwise, make does all of its work in the current working directory. If this is all too abstract for you, I will use Listing 4.1 as an example. It is the makefile for building a text editor imaginatively named editor.LISTING 4.1 SIMPLE MAKEFILE ILLUSTRATING TARGETS, DEPENDENCIES, AND COMMANDS1 editor : editor.o screen.o keyboard.o2 gcc -o editor editor.o screen.o keyboard.o34 editor.o : editor.c editor.h keyboard.h screen.h5 gcc -c editor.c67 screen.o : screen.c screen.h8 gcc -c screen.c910 keyboard.o : keyboard.c keyboard.h11 gcc -c keyboard.c1213 clean :14 rm editor *.oTo compile editor, you would simply type make in the directory where the makefile exists. Its that simple.This makefile has five rules. The first target, editor, is called the default targetthis is the file that make tries to create. editor has three dependencies, editor.o, screen.o, and keyboard.o; these three files must exist in order to build editor. Line 2 (the line numbers do not appear in the actual makefile; they are merely pedagogic tools) is the command that make will execute to create editor. As you recall from Chapter 3, “Using GNU cc,” this command builds an executable named editor from the three object files.The next three rules (lines 411) tell make how to build the individual object files.Project Management Using GNU makeUSING GNUMAKEThe first character in a command must be the tab character; eight spaces will not suffice. This often catches people unaware, and can be a problem if your preferred editor “helpfully” translates tabs to eight spaces. If you try to use spaces instead of a tab, make displays the message “Missing separator” and stops. Here is where makes value becomes evident: ordinarily, if you tried to build editorusing the command from line 2, gcc would complain loudly and ceremoniously quit if the dependencies did not exist. make, on the other hand, after seeing that editor requires these other files, verifies that they exist and, if they dont, executes the commands on lines 5, 8, and 11 first, then returns to line 2 to create the editor executable. Of course, if the dependencies for the components, such as keyboard.c or screen.h dont exist, make will also give up, because it lacks targets named, in this case, keyboard.c and screen.h.“All well and good,” youre probably thinking, “but how does make know when to rebuild a file?” The answer is stunningly simple: If a specified target does not exist in a place where make can find it, make (re)builds it. If the target does exist, make compares the timestamp on the target to the timestamp of the dependencies. If one or more of the dependencies is newer than the target, make rebuilds the target, assuming that the newer dependency implies some code change that must be incorporated into the target.More About RulesIn this section, I will go into more detail about writing makefile rules. In particular, I cover creating and using phony targets, makefile variables, using environment variables and makes predefined variables, implicit rules, and pattern rules.Phony TargetsIn addition to the normal file targets, make allows you to specify phony targets. Phony targets are so named because they do not correspond to actual files. The final target in Listing 4.1, clean, is a phony target. Phony targets exist to specify commands that make should execute. However, because clean does not have dependencies, its commands are not automatically executed. This follows from the explanation of how make works: upon encountering the clean target, make sees if the dependencies exist and, because clean has no dependencies, make assumes the target is up to date. In order to build this target, you have to type make clean. In our case, clean removes the editor executable and its constituent object files. You might create such a target if you wanted to create and distribute a source-code tarball to your users or to start a build with a clean build tree. If, however, a file named clean happened to exist, make would see it. Again, because it has no dependencies, make would assume that it is up to date and not execute the commands listed on line 14. To deal with this situation, use the special make target .PHONY.The Linux Programming ToolkitAny dependencies of the .PHONY target will be evaluated as usual, but make will disregard the presence of a file whose name matches one of .PHONYs dependencies and execute the corresponding commands anyway. Using .PHONY, our sample makefile would look like: 1 editor : editor.o screen.o keyboard.o2 gcc -o editor editor.o screen.o keyboard.o34 editor.o : editor.c editor.h keyboard.h screen.h5 gcc -c editor.c67 screen.o : screen.c screen.h8 gcc -c screen.c910 keyboard.o : keyboard.c keyboard.h11 gcc -c keyboard.c1213.PHONY : clean1415 clean :16 rm editor *.oVariablesTo simplify editing and maintaining makefiles, make allows you to create and use variables. A variable is simply a name defined in a makefile that represents a string of text; this text is called the variables value. Define variables using the general form: VARNAME = some_text .To obtain VARNAMEs value, enclose it in parentheses and prefix it with a $:$(VARNAME)VARNAME expands to the text on the right-hand side of the equation. Variables are usually defined at the top of a makefile. By convention, makefile variables are all uppercase, although this is not required. If the value changes, you only need to make one change instead of many, simplifying makefile maintenance. So, after modifying Listing 4.1 to use two variables, it looks like the following:LISTING 4.2 USING VARIABLES IN MAKEFILES1 OBJS = editor.o screen.o keyboard.o2 HDRS = editor.h screen.h keyboard.h3 editor : $(OBJS)Project Management Using GNU makeUSING GNUMAKEcontinuesLISTING 4.2 CONTINUED4 gcc -o editor $(OBJS)56 editor.o : editor.c $(HDRS)7 gcc -c editor.c89 screen.o : screen.c screen.h10 gcc -c screen.c1112 keyboard.o : keyboard.c keyboard.h13 gcc -c keyboard.c1415 .PHONY : clean1617 clean :18 rm editor $(OBJS)OBJS and HDRS will expand to their value each time they are referenced. make actually uses two kinds of variablesrecursively-expanded and simply expanded. Recursivelyexpanded variables are expanded verbatim as they are referenced; if the expansion contains another variable reference, it is also expanded. The expansion continues until no further variables exist to expand, hence the name, “recursively-expanded.” An example will make this clear. Consider the variables TOPDIR and SRCDIR defined as follows:TOPDIR = /home/kwall/myprojectSRCDIR = $(TOPDIR)/srcThus, SRCDIR will have the value /home/kwall/myproject/src. This works as expected and desired. However, consider the next variable definition:CC = gccCC = $(CC) -oClearly, what you want, ultimately, is “CC = gcc -o.” That is not what you will get, however. $(CC) is recursively-expanded when it is referenced, so you wind up with an infinite loop: $(CC) will keep expanding to $(CC), and you never pick up the -o option. Fortunately, make detects this and reports an error:* Recursive variable CC references itself (eventually). Stop.To avoid this difficulty, make uses simply expanded variables. Rather than being expanded when they are referenced, simply expanded variables are scanned once and for all when they are defined; all embedded variable references are resolved. The definition syntax is slightly different:CC := gcc -oCC += -O2The Linux Programming ToolkitThe first definition uses := to set CC equal to gcc -o and the second definition uses += to append -O2 to the first definition, so that CCs final value is gcc -o -O2. If you run into trouble when using make variables or get the “VARNAME references itself” error message, its time to use the simply expanded variables. Some programmers use only simplyexpanded variables to avoid unanticipated problems. Since this is Linux, you are free to choose for yourself!Environment, Automatic, and PredefinedVariablesIn addition to user-defined variables, make allows the use of environment variables and also provides “automatic” variables and predefined variables. Using environment variables is ridiculously simple. When it starts, make reads every variable defined in its environment and creates variables with the same name and value. However, similarly named variables in the makefile override the environment variables, so beware. make provides a long list of predefined and automatic variables, too. They are pretty cryptic looking, though. See Table 4.1 for a partial list of automatic variables.TABLE 4.1 AUTOMATIC VARIABLESVariable Description$ The filename of a rules target$< The name of the first dependency in a rule$ Space-delimited list of all the dependencies in a rule$? Space-delimited list of all the dependencies in a rule that are newer thanthe target$(D) The directory part of a target filename, if the target is in a subdirectory$(F) The filename part of a target filename, if the target is in a subdirectoryIn addition to the automatic variables listed in Table 4.1, make predefines a number of other variables that are used either as names of programs or to pass flags and arguments to these programs. See Table 4.2.TABLE 4.2 PREDEFINED VARIABLES FOR PROGRAM NAMES AND FLAGSVariable DescriptionAR Archive-maintenance programs; default value = arAS Program to do assembly; default value = asProject Management Using GNU make4USING GNUMAKEcontinuesTABLE 4.2 CONTINUEDVariable DescriptionCC Program for compiling C programs; default value = ccCPP C Preprocessor program; default value = cppRM Program to remove files; default value = “rm -f”ARFLAGS Flags for the archive-maintenance program; default = rvASFLAGS Flags for the assembler program; no defaultCFLAGS Flags for the C compiler; no defaultCPPFLAGS Flags for the C preprocessor; no defaultLDFLAGS Flags for the linker (ld); no defaultIf you want, you can redefine these variables in the makefile. In most cases, their default values are reasonable.Implicit RulesIn addition to the rules that you explicitly specify in a makefile, which are called explicit rules, make comes with a comprehensive set of implicit, or predefined, rules. Many of these are special-purpose and of limited usage, so we will only cover a few of the most commonly used implicit rules. Implicit rules simplify makefile maintenance.Suppose you have a makefile that looks like the following:1 OBJS = editor.o screen.o keyboard.o2 editor : $(OBJS)3 cc -o editor $(OBJS)45 .PHONY : clean67 clean :8 rm editor $(OBJS)The command for the default target, editor, mentions editor.o, screen.o, and keyboard. o, but the makefile lacks rules for building those targets. As a result, make will use an implicit rule that says, in essence, for each object file somefile.o, look for a corresponding source file somefile.c and build the object file with the command gcc c somefile.c -o somefile.o. So, make will look for C source files named editor.c, screen.c, and keyboard.c, compile them to object files (editor.o, screen.o, and keyboard. o), and finally, build the default editor target. The mechanism is actually more general than what I described. Object (.o) files can be created from C source, Pascal source, Fortran source, and so forth. make looks for theThe Linux Programming ToolkitPART I60dependency that can actually be satisfied. So, if you have files editor.p, screen.p, and keyboard.p, the Pascal compiler will be invoked rather than the C compiler (.p is the assumed extension of Pascal source files). The lesson here is that if, for some perverse reason, your project uses multiple languages, dont rely on the implicit rules because the results may not be what you expected.Pattern RulesPattern rules provide a way around the limitations of makes implicit rules by allowing you to define your own implicit rules. Pattern rules look like normal rules, except that the target contains exactly one character (%) that matches any nonempty string. The dependencies of such a rule also use % in order to match the target. So, for example, the rule %.o : %.ctells make to build any object file somename.o from a source file somename.c. Like implicit rules, make uses several predefined pattern rules: %.o : %.c$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $This is the same as the example. It defines a rule that makes any file x.o from x.c. This rule uses the automatic variables $< and $ to substitute the names of the first dependency and the target each time the rule is applied. The variables $(CC), $(CFLAGS), and $(CPPFLAGS) have the default values listed in Table 4.2.CommentsYou can insert comments in a makefile by preceding the comment with the h