UNIX Unleashed, Internet Edition
- 7 -The make Utilityby Sean Drew This chapter is intended to be an overview of the UNIX make facility. Most of the salient features of make are covered; however, you should consult your man page for additional information because versions of make tend to differ between different UNIX vendors. Following is a list of the major topics covered in this chapter.
Introduction to makeThe UNIX make utility was originally designed for maintaining C program files in order to prevent unnecessary recompilation. However, make is eminently useful for maintaining any set of files with interdependencies. For example, make can be used to maintain C++ or HTML source code. In fact, NIS (Network Information Service) uses make to maintain user information. The make utility provides a way of codifying the relationships between files as well as which commands need to be generated to bring files up to date when they are changed. The make utility provides a powerful, nonprocedural, template-based way to maintain files. The basic concept of make is akin to logic programming in languages such as Prolog. You tell make what needs to be done and supply some rules, and make figures out the rest. MakefilesA makefile is set of make commands. The makefile describes what set of files can be built and how to build those files. Four types of lines are allowable in a makefile: target lines, shell command lines, macro lines, and make directive lines (such as include). Comments in a makefile are denoted by the pound sign (#). When you invoke make, it looks for a file named makefile in your current working directory. If makefile does not exist, then make searches for a file named Makefile. Some UNIX versions also search for additional files, in the following order: s.makefile, SCCS/s.makefile, s.Makefile, and SCCS/s.Makefile. If you don't want to use one of the default names, other files can be used with the -f command-line option. (See the "Command-Line Options" section later in this chapter for more information.) The convention used to identify makefiles not named makefile or Makefile is to use the .mk suffix (for example, foo.mk). Target LinesTarget lines tell make what can be built. Target lines consist of a list of targets, followed by a colon (:), followed by a list of dependencies. Although the target list can contain multiple targets, typically only one target is listed. The target list cannot be empty; however, the list of dependencies can be empty. Following are some example target lines: singleTarget: dependency1 dependency2 #target with 2 dependencies target1 target2: dependency1 dependency2 #target list 2 dependencies target: #no dependencies The dependency list consists of targets that must be older than the current target after make successfully executes. In other words, the target must be newer than any of its dependent targets. If any of the dependent targets is newer than the current target or if the dependent target does not exist, the dependent targets must be made and then the current target must be made. If the list of dependencies is empty, the target is always made. Filename pattern matching can be used to automatically generate a dependency list for a target. The shell metacharacters asterisk (*), question mark (?), and braces ([]) can be used. For example, if parse.cc, main.cc, and io.cc were all the files ending with .cc in a directory with a makefile, then the following two target lines would be identical. main: parse.cc main.cc io.cc # list all the dependent files manually main: *.cc #use shell metacharacters to generate dependent list Typically, the list contains dependent items that are used in the construction of the target. For example, the dependent list may be comprised of object files that make up an executable program: part.o component.o module.o or header and source files that an object file depends on module.o: module.cc module.hh part.hh However, dependent targets do not have be components of the target. For example, the dependent targets might be actions you need to perform before a target is built, such as making a backup of the current target before it is rebuilt. Lines following a target line are usually the commands required to build the target. See the "Shell Command-Lines" section for more detail. Library TargetsLibrary targets are a special type of target. A special syntax is supported for library targets (Check the man page on ar for details on using UNIX libraries or to see if your UNIX system has ar.). Library targets allow for the addressing of individual modules within the library. If a target or dependency includes parentheses (()), then the target or dependency is considered to be a library. libfoo.a(foo.o): foo.cc foo.hh #the object file foo.o in library Some make variants allow multiple object files to be listed within the parentheses (see the following line of code). Some make variants, however, allow only one object file to be listed within the parentheses. libfoo.a: libfoo.a(foo.o bar.o) #libfoo.a depends Do not use any spaces between the parentheses, unless you can specify multiple object files within the library--in which case the spaces can only appear between the object files. Sometimes you wish to use different compile options among different dependencies of a library target. However, make only allows a target to be defined once with a single colon. Double colons enable you to define a target multiple times with different lists of dependencies. Suppose there was a particular troublesome module, buggy.o, that needed to be compiled with debugging information, while the more stable object files did not need debugging information. The target lines libfoo.a:: libfoo.a(foo.o bar.o) #target list one libfoo.a:: libfoo.a(buggy.o) #target list two would enable the building of foo.o and bar.o without debugging information (typically -g to most UNIX C/C++ compilers) and buggy.o with debugging information included. Rule TargetsOne of the more powerful features of the make utility is its capability to specify generic targets, also known as suffix rules, inference rules, or just simply rules. Rules are a convenient way to tell make only one time how to build certain types of targets. Consider the makefile excerpt foo.o: foo.cc
CC -c foo.cc -I. -I/usr/local/include -DDEBUG +g #shell command-line
bar.o: bar.cc
CC -c bar.cc -I. -I/usr/local/include -DDEBUG +g #shell command-line
main.o: main.cc
CC -c main.cc -I. -I/usr/local/include -DDEBUG +g #shell command-line
main: foo.o bar.o main.o
CC foo.o bar.o main.o
which has a great deal of redundancy. All of the shell command lines are identical, except for the file being compiled. This is a prime candidate for a rule. The following rule tells make how to transform a file ending in .cc to a file ending in .o. .cc.o:
CC -c $< -I. -I/usr/local/include -DDEBUG +g
The preceding rule makes use of a special macro, $<, which substitutes the current source file in the body of a rule (see the "Special Built-In Macros" section for more information). Applying the .cc.o rule to the previous makefile simplifies the makefile to .cc.o:
CC -c $< -I. -I/usr/local/include -DDEBUG +g
main: foo.o bar.o main.o
CC foo.o bar.o main.o
There are many default inference rules supplied by make. It is able to determine which rule to apply by applying the following algorithm: Search the list of rules--both default and user supplied--for a rule that will build the desired file type. File type is determined by the file extension. The file extension is the set of characters after a dot (.). If a file of the specified type exists, the rule is applied. For example, if a makefile specified only two rules in the following order, a .c.o rule and a .cc.o, and make was asked to create foo.o, the following set of events would occur:
Rules can be chained together by make in order to reach a target goal. (Some versions of make do not perform rule chaining.) For example, say you are working with a CORBA IDL (Common Object Request Broker Architecture Interface Definition Language) compiler. The IDL compiler takes interface definitions as input and creates C++ source as output. For example, if you ask make to create foo.o, given a makefile that has an .idl.cc and a .cc.o rule, make does the following:
This chaining of rules is a very powerful feature of make. Double Suffix RulesThe rules defined so far are known as double suffix rules because they contain double suffixes, such as .rtf.html. The .rtf.html rule can be used to convert a Rich Text Format file to a HyperText Markup Language File. Double suffix rules describe how to transform root.suffix1 to root.suffix2 (for example, index.rtf to index.html). Following is a list of the more commonly available double suffix rules supplied as defaults by make: .c.o .c~.o .c~.c .c.a .c~.a .C.o .C~.o .C~.C .C.a .C~.a .cc.o .cc~.o .cc~.cc .cc.a .cc~.a .h~.h .H~.H .s.o .s~.o .s~.a .p.o .p~.o .p~.p .p.a .p~.a .f.o .f~.o .f~.f .f.a .f~.a .r.o .r~.o .r~.r .r.a .r~.a .y.o .y~.o .y.c .y~.c .l.o .l~.o .l.c You may redefine any of the default rules supplied by make. The default rules take advantage of standard macros in order to make the default rules more generic. For example, the way a C or C++ file is compiled does not change much, other than some of the flags supplied to the compiler. The most commonly used of these macros are LDFLAGS, CFLAGS, and CXXFLAGS, which are used to parameterize the linker (ld), the C compiler (cc), and the C++ compiler (CC on HP-UX), respectively. The LIBS macro is commonly used but is not incorporated into the default rules. The LIBS macro is used to define which libraries other than the system default libraries are to be used at link time and in what order should the libraries be evaluated. The tildes (~) in the double suffix rules refer to an SCCS (Source Code Control System) file. SCCS files have a prefix prepended to a filename, which is in direct conflict with make because make bases all of its algorithms on suffixes. For example, the file foo.cc becomes s.foo.cc when using SCCS. The tilde signals make to treat the file as an SCCS file, so that .cc~.o can be used to transform s.foo.cc to foo.o with the command make foo.o, which is preferable to the command make s.foo.o && mv s.foo.o foo.o. Single Suffix RulesSingle suffix rules describe how to transform root.suffix1 to root (for example, cat.c to cat). The second suffix is in effect null in a single suffix rule. Single suffix rules are useful for creating programs that are composed of a single source file. In fact, if you have the CFLAGS and LDFLAGS environment variables defined, you don't need a makefile to effectively use the .c rule, as the .c rule is part of the default set of rules. Assuming that a Bourne-compatible shell and the source files cat.c, echo.c, cmp.c, and chown.c are in the current directory, the following commands build the targets cat, echo, cmp, and chown without a makefile: % export CFLAGS="-I. -DDEBUG +g" LDFLAGS="-lfoo -lbar" % make cat echo cmp chown Following is a list of the more commonly available single suffix rules supplied as defaults by make: .c .c~ .C .C~ .cc .cc~ .sh .sh~ .p .p~ .f .f~ .r .r~ Built-In TargetsMake supplies several built-in targets for modifying the behavior of make. Some of the built-in targets accept dependencies, but the dependencies are really arguments to the built-in target. For example, the arguments to .PRECIOUS are file suffixes. Table 7.1 lists the build-in targets. Table 7.1. Built-in targets for make.
Common TargetsBy convention, there are some common targets in makefiles. These common targets are usually not files, and are known as dummy targets. One of the most common of the dummy targets is clean. The command make clean generally removes all of the built files, which are typically programs and object files. Clobber is a more severe target, which removes all files and associated directories. The command make clobber is often used to uninstall software. For makefiles that build and install software, install is often a target. The command make install usually creates the programs, installs the man pages, and copies the program to its intended location. Another common target is all. When a makefile builds several targets, make all typically builds all the targets. Shell Command-LinesShell command-lines, also known more simply as commands, define the actions that are used to build a target. Any text following a semi-colon (;) on a target line is considered a command. All subsequent lines after a target that begin with a tab are also commands for the target. The comment character of a pound sign (#) is allowed within a target's command definition. For example, the following makefile excerpt shows a comment embedded in a command definition: foo.html: foo.rtf
rtftohtml -hx $<
#place current date in file, $$$$ expands to $$ in shell
sed s/__DATE__/"'date'"/ $@ > foo.$$$$ && mv foo.$$$$ $@
The first line that is not a comment or does not start with a tab ends the list of commands associated with the target. Long command-lines can be continued on the next line using the backslash (\) newline sequence. foo.html: foo.rtf
rtftohtml -hx $<
sed -e "s/PAGE_DATE/'date'/" \
-e "s/PAGE_TITLE/$(DOCTITLE)/" \
-e "s/PAGE_NAME/$(HOMETITLE)/" $@ \
> foo.$$$$ && mv foo.$$$$ $@
Any macros embedded in the command are evaluated, and the proper value is substituted by make; as a result, the shell sees only the values of the macros. Normally, the commands are echoed to the standard output, unless the command is preceded by the at sign (@). Use of the @ directive provides a finer grain of output control than the .SILENT target or the -s command-line option--both of which turn off all command output. The @ directive is particularly useful when issuing an echo command. The command echo Build complete at 'date' without the @ directive would produce the output echo Build complete at 'date' Build complete at Mon May 12 02:32:37 MST 1997 while using the @ results in the cleaner output of Build complete at Mon May 12 02:32:37 MST 1997 Note that the @ directive, the -s option, and the .SILENT target only suppress the echoing of the command; the output of the command is still shown. The output of the following makefile snippet target:
#echo this command to standard out
echo echoed to standard out
#do not echo this command to standard out
@echo not echoed to standard out
for target is % make target echo echoed to standard out echoed to standard out not echoed to standard out The comment character can appear after shell commands; however, the comment is not a make comment. The # sign and all the following text are passed to the shell. The good news in this case is that the # sign is a comment in just about any shell, and the net effect is the same. MacrosMacros serve the following four purposes in a makefile:
Macro definitions, in order of preference, can come from four places: make internal defaults, environment variables, the makefile(s), and the command-line. The precedence order can be changed via the -e make command-line option to have environment variables override makefile macro definitions. See the "Command-Line Options" section for a discussion of make command-line options. Macro SyntaxSee the "Command-Line Macro Definition" for information on how to define macros on the command-line. The basic syntax for defining macros within a makefile is name = valueList The name may consist of any combination of uppercase (A-Z) and lowercase (a-z) letters, digits (0-9), and underlines (_). Macro names are all uppercase by convention. Depending on your version of make, certain punctuation characters are allowed in a macro name, such as the caret (^) or at sign (@). Unless strange compulsions force you to name macros ^foo*@, such punctuation usage is strongly discouraged; it seldom helps readability or portability. The equal sign (=) can migrate rather freely about the macro assignment expression because blanks and tabs surrounding the equal sign are removed. As a result of the white space removal behavior, all of the following assignments produce the same result, the string VALUE is assigned to the name NAME: NAME=VALUE NAME = VALUE NAME= VALUE NAME =VALUE The valueList may contain zero, one, or more entries, as demonstrated in the following: BLANK = ONE_VALUE = one LIST_VALUE = one two three The valueList can be quite long and the backslash (\) newline escape may be used to continue a definition on another line. If the line is continued, the newline is translated to a space by make and all subsequent white space (blanks, tabs, and newlines) are removed. Thus, the makefile BAR=one\
\
space
X:
echo $(BAR)
would produce the following output if target X were made: echo one space one space Other than the white space translations mentioned previously, white space in a macro definition is preserved. Macro definitions can use other macros. Nested definitions cannot be recursive, or make will complain. RECURSIVE = $(BAD) #don't do this BAD = $(RECURSIVE) #don't do this FIRST_HALF = first SECOND_HALF = second NESTED = $(FIRST_HALF) $(SECOND_HALF) NESTED_AGAIN = zero.$(FIRST_HALF).$(SECOND_HALF) Ordering is not important when defining macros. In the preceding example, the macro NESTED could have been defined before FIRST_HALF and SECOND_HALF. A macro does need to be defined before it is used in any target line as a dependency. If a macro is defined multiple times, the last value is used. This means that a macro cannot have one value for part of the makefile and a different value for another part of the makefile. If the value of a macro needs to be changed, a recursive call to make is needed with the new value passed in the command-line, as in the following example: MACRO_NAME=oldValue
target:
$(MAKE) MACRO_NAME=newValue target
A macro is dereferenced by applying the dollar ($) operator and either parenthesis (()) or curly braces ({}). For example, the macro MAY could be dereferenced as $(MAY) or ${MAY}. However, in the case of single character macros, just the $ suffices, so the macro Z could be dereferenced as $Z, $(Z), or ${Z}. However, in the case of single character macros, the use of () or {} is encouraged. Single character names are not good to use in general; a more descriptive name will be appreciated by the next person to read the makefile. If a macro is undefined or is assigned a blank value, the null string is substituted for its value. The makefile BLANK= X:; echo foo$(BLANK)$(UNDEFINED)bar produces the following output for target X: echo foobar foobar If you need to use a dollar sign ($) in make, it needs to be escaped with another dollar sign. Multiple consecutive occurrences of the dollar sign are allowed: #echo environment variable $LOGNAME and process id $$
foo:
echo $$LOGNAME $$$$
Macro SubstitutionThe make utility supports a simple text substitution function for macros. The syntax is :oldString=newString, which is appended immediately following the macro name in macro reference. For example, if the macro OBJS were defined as OBJS = fuggles.o perle.o cascade.o saaz.o the .o extension could be replaced by the .cc extension by using the macro reference, $(OBJS:.o=.cc), which would evaluate to fuggles.cc perle.cc cascade.cc saaz.cc. The macro string substitution is somewhat limited in capability, but works well for maintaining files that differ only in suffix or trailing characters. Special Built-In MacrosThe make utility provides several special built-in macros in order to allow rules to be generic. If the rules were not generic, then the filenames would be hard coded into the rule, and thus, not really a rule, because one rule would be required for every filename. The built-in macros can be referenced without parenthesis. For example, the @ macro can be referred to as $@ instead of $(@). The built-in macros may not have a value, depending at what state make is in when the macro is evaluated. Some macros are only valid during suffix rule evaluation, while other macros are only valid during regular rule evaluation. Table 7.2 lists the built-in macros. Table 7.2. Built-in macros for make.
The preceding built-in macros can have special modifiers appended to the end of the macro to return the filename or directory name portion. Use F to retrieve the filename, and D to retrieve the directory name. Note that only uppercase F and D will work. The shortcut method without parenthesis may not be used when a modifier is applied. For example, if $< evaluated to /users/dylan/foo.cc, $(<F) would return foo.cc and $(<D) would return /users/dylan. Some versions of make return a trailing slash appended to directory names, so using the previous example, $(<D) would return /users/dylan/. If the macro evaluates to multiple values, as does the $? macro, the F or D modifier is applied to each of the multiple values in turn. (Some versions of make do not support the F and D modifiers.) In addition to the five macros previously discussed, there is the dynamic dependency macro $$@. The macro is called dynamic because it is evaluated at the time the dependency is processed. $$@ can only be used on dependency lines. The $$@ macro evaluates to the current target just as $@ does, but $$@ is allowed on the dependency line, whereas $@ is not. The $$@ macro is useful for building executables made up of only one source file, as the following makefile snippet demonstrates: COMMANDS = cat dog say sed test true false more ar less
$(COMMANDS) : $$@.c
$(CC) $? -o $@
The macros previously discussed have values that are supplied by make and are not modifiable by you. There are other macros that make uses but in which you can modify the default value supplied by make. The macros VPATH and SHELL fall into this category. Some versions of make have additional macros of this type; however, VPATH and SHELL are the most widely available. VPATH is a path where make can search for dependent files. The current directory is searched first, then each of the VPATH elements is searched. VPATH uses colons (:) to delimit the list elements. For example, if VPATH = source:../moreSource:/the/rest/of/the/source appeared in a makefile, make would first search for dependents in the current directory, then in a subdirectory named source, followed by a sibling directory named moreSource, and then the absolute directory of /the/rest/of/the/source. The SHELL macro tells make which shell to use when processing the command-line portions of a target. Most versions of make default to the Bourne or POSIX shell (/bin/sh). To maximize portability, it is best to write shell commands in the POSIX shell syntax and to set the SHELL variable to /bin/sh, for example, SHELL = /bin/sh. Some versions of make will only allow the use of Bourne shell syntax. make DirectivesA makefile is mostly composed of macro, command, and target lines. A fourth type of line found in makefiles is lines that are directives to make. make directives are one of the more nonstandardized areas of make. You are likely to find many incompatibilities in this area. If portability is of concern to you, you may want to avoid using make directive features. The most common of the make directives is the include directive. The include directive enables common definitions to be written once and included. The include directive must be the first item on a line followed by a filename, as in the following example. include /project/global.mk include /users/sdrew/myGlobal.mk #rest of makefile If your version of make does not have include directives, you can fake the same behavior using multiple -f options (see the "Command-Line Options" section for a description of the -f option). The following command effectively emulates the previous example makefile: % make -f /project/global.mk -f /users/sdrew/myGlobal.mk If you grow tired of typing the -f command-line option, some shell trickery should relieve the drudgery. You can write an alias or shell script to automatically supply the include file options to make.
The comment (#) is a directive to make to ignore the line if it is the first nonwhitespace character on a line. Comments can appear after other make lines was well, as shown in the following: foo=bar #assignment target:;echo $(FOO) #target #this whole line is a comment Note that the comment directive is supported by all versions of make. Command-Line ArgumentsWhile make has methods of configuration from within a makefile, the make command-line options provide a convenient way to configure make on-the-fly. The typical sequence of make command-line arguments is shown here, although arguments may appear in any order: make [-f makefile] [options] [macro definitions] [targets] Note that optional items are enclosed in braces ([]). Command-Line OptionsCommand-line options are indicated with a dash (-) and then the option, for example, make -e. If multiple options are needed, the options may be preceded by only one dash, make -kr, or by using a dash per option, make -k -r. Mixing option specification methods is allowed, make -e -kr. Table 7.3 lists the command-line options for make. Table 7.3. Command-line options for make.
Command-Line Macro DefinitionMacros can be defined on the command line using the name=value syntax. Zero or more macro definitions may be supplied on the command line. Command-line macros have the highest precedence and override macros defined internally by make, macros from the current environment, and macros specified in the makefile. Command-line macros provide a convenient way of temporarily overriding current settings without changing them in the environment or in the makefile. For scripting, command-line macros help ensure consistent execution from run to run. Command-Line Target SpecificationZero or more targets can be specified on the make command line. If no target is provided on the command line, make searches for the first nonrule target in the first makefile, and then each subsequent makefile, and tries to update the target if one is found. Targets specified on the command line should be listed in one of the makefiles currently being used by make. Each of the targets specified is updated by make in the order the arguments appeared on the command line. Different Make ProgramsWhile make is a very powerful tool, the "standard" versions of make have some rather gaping feature holes (for example, no conditional statements such as if). As a result, there are other versions of make available that try to fill some of the feature gaps. In addition to extra features, other make offerings offer a portability solution. You can either try to write a makefile that matches the lowest common denominator feature set while exercising the fewest bugs for various UNIX platforms, or use the same make offering on all platforms. If you are not distributing your makefile for public consumption, the latter choice is much more palatable. Some of the more commonly available make offerings are covered in this following sections. GNU makeIf you intend to use make extensively for software development, you need GNU's version of make. This is especially true if you develop software on multiple UNIX platforms. GNU processes "standard" makefiles better than most UNIX platforms "standard" offering. If after reading this section you feel you absolutely must have GNU make, then look up http://www.gnu.org in your WWW browser. You can also use your favorite Internet search engine and search for gmake or GNU make. ConditionalsGNU make provides a full complement of if statements for conditional processing within a makefile. Calling Shell Using $(shell)GNU make has the handy ability to substitute the output of any shell command as though it were a macro. When used in conjunction with if statements, $(shell) is very handy for parameterizing a makefile automatically. For example, HOSTTYPE = $(shell uname) ifeq "$(HOSTTYPE" "HP-UX" # config host environment endif Pattern RulesPattern rules are a powerful extension to suffix rules. The pattern rule has the form of targetPattern: dependencyPattern, which is the opposite order of a suffix rule. For example, .cc.o expressed as a pattern rule would be %.o: %.cc. The % in the pattern rule operates as the asterisk (*) wildcard operates in the shell, which allows more than just a suffix to specify a rule. For example, if you have a directory of .gif files that you wish to enlarge with a command-line utility for users with larger screens, the following makefile with a pattern rule would do the job nicely: %_big.gif: %.gif
giftran -x 125 $< > $*_big.gif
GIFS = $(shell ls *.gif)
BIG_GIFS: $(GIFS:.gif=_big.gif)
Other Nifty FeaturesGNU make is loaded with far too many nifty features to list here, but some of the more commonly used are: := operator, simplified library syntax - libfoo.a(one.o two.o), and extra text processing functions. imakeInclude Make, or imake, is a pre-processor for the make utility. The C pre-processor provides functionality that make does not offer: include directives, if directives, macro functions. imake is used in the X distribution. imake works by providing a template file that is then processed to create a file for use by make. imake can be a bit of a pain to use because the documentation is somewhat poor and the extra level of indirection can be cumbersome. Because of the template ability, large project trees can be generated automatically, which can offset some of the pain of use. If you want to get a copy of imake, try ftp://ftp.primate.wisc.edu/pub/imake-book/itools.tar.Z or ftp://ftp.primate.wisc.edu/pub/imake-book/itools.tar.gz. The tar file contains, among other files, the following: imake, makedepend, xmkmf, mkdirhier, imboot, msub, imdent. Another good place to look for imake is ftp://ftp.x.org which contains the X11 R5 distribution directory structure, so you can retrieve imake without having to pull the entire X11 distribution. You can also consult your favorite Internet search engine using the keyword imake. nmakeDeveloped by AT&T, nmake has been tailored to help meet the demands of large scale C development. nmake plugs many of the standard holes of make, and has a few new twists of its own. nmake is the only make that stores compile options for use in subsequent runs of make. That enables the ability to ask make to build any file that was not built with a certain macro definition or compiler switch. Another good feature of nmake is its capability to include multiple shell lines in a single shell without your bending over backward using semicolons and backslash newline. make UtilitiesSeveral utilities are available to enhance the usability of make. A few of the more common utilities are briefly covered in the following sections. makedependA makefile is intended to document the relationships between files as well as the rules for building those files. makedepend provides a way of automating the documentation of the file relationships by generating a dependency list for your source files. makedepend takes into account #if directives for proper dependency generation. mkmfmkmf is short for make makefile. mkmf examines all the source in the current directory, searches the source for dependencies, and then generate a makefile based on templates. SummaryBy now you should be familiar with the contents of a makefile and know how to use make to manage your source files. We covered how to specify targets for make and how to encode the instructions for building files into your makefile. You may want to consult the chapters on UNIX shells to help you with shell syntax. We also looked at efficiency of expression using make macros and shell metacharacters. You may wish to read Chapter 6, "The C and C++ Programming Languages" and see how make can help you manage your C and C++ source files. make is a powerful tool for maintaining sets of files with interdependencies. Whether you are writing software or maintaining Web pages, make can make your job easier (pun intended). Investing a little time learning make can save you a lot of work. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|