|
|
The basic operation of make is to update a target file by ensuring that all of the files on which the target file depends exist and are up to date. The target file is regenerated if it has not been modified since the dependents were modified. The make program builds and searches a graph of these dependencies. The operation of make depends on its ability to find the date and time that a file was last modified.
The make program operates using three sources of information:
To illustrate, consider a simple example in which a program named prog is made by compiling and loading three C language files x.c, y.c, and z.c with the math library, libm. By convention, the output of the C language compilations will be found in files named x.o, y.o, and z.o. Assume that the files x.c and y.c share some declarations in a file named defs.h, but that z.c does not. That is, x.c and y.c have the line
#include "defs.h"
The following specification describes the relationships and operations:
prog : x.o y.o z.o cc x.o y.o z.o -lm -o progIf this information were stored in a file named makefile, the commandx.o y.o : defs.h
$ makewould perform the operations needed to regenerate prog after any changes had been made to any of the four source files x.c, y.c, z.c, or defs.h. In the example above, the first line states that prog depends on three .o files. Once these object files are current, the second line describes how to combine them to create prog. The third line states that x.o and y.o depend on the file defs.h. From the file system, make discovers that there are three .c files corresponding to the needed .o files and uses built-in rules on how to generate an object from a C source file (that is, issue a cc -c command).
If make did not have the ability to determine automatically what needs to be done, the following longer description file would be necessary:
prog : x.o y.o z.o cc x.o y.o z.o -lm -o prog x.o : x.c defs.h cc -c x.c y.o : y.c defs.h cc -c y.c z.o : z.c cc -c z.cIf none of the source or object files have changed since the last time prog was made, and all of the files are current, the command make announces this fact and stops. If, however, the defs.h file has been edited, x.c and y.c (but not z.c) are recompiled; and then prog is created from the new x.o and y.o files, and the existing z.o file. If only the file y.c had changed, only it is recompiled; but it is still necessary to relink prog. If no target name is given on the make command line, the first target mentioned in the description is created; otherwise, the specified targets are made. The command
$ make x.owould regenerate x.o if x.c or defs.h had changed.
A method often useful to programmers is to include rules with mnemonic names and commands that do not actually produce a file with that name. These entries can take advantage of make's ability to generate files and substitute macros (for information about macros, see ``Description files and substitutions''.) Thus, an entry save might be included to copy a certain set of files, or an entry clean might be used to throw away unneeded intermediate files.
If a file exists after such commands are executed, the file's time of last modification is used in further decisions. If the file does not exist after the commands are executed, the current time is used in making further decisions.
You can maintain a zero-length file purely to keep track of the time at which certain actions were performed. This technique is useful for maintaining remote archives and listings.
A simple macro mechanism for substitution in dependency lines and command strings is used by make. Macros can either be defined by command-line arguments or included in the description file. In either case, a macro consists of a name followed by the symbol = followed by what the macro stands for. A macro is invoked by preceding the name by the symbol $. Macro names longer than one character must be parenthesized. The following are valid macro invocations:
$(CFLAGS) $2 $(xy) $Z $(Z)The last two are equivalent.
$, $@, $?, and $< are four special macros that change values during the execution of the command. (These four macros are described in ``Description files and substitutions''.) The following fragment shows assignment and use of some macros:
OBJECTS = x.o y.o z.o LIBES = -lm prog: $(OBJECTS) cc $(OBJECTS) $(LIBES) -o prog . . .
The command
$ make LIBES="-ll -lm"loads the three objects with both the lex (-ll) and the math (-lm) libraries, because macro definitions on the command line override definitions in the description file. (In SCO OpenServer system commands, arguments with embedded blanks must somehow be quoted.)
As an example of the use of make, a description file that might be used to maintain the make command itself is given. The code for make is spread over a number of C language source files and has a yacc grammar. The description file contains the following:
# Description file for the make commandThe make program prints out each command before issuing it.FILES = Makefile defs.h main.c doname.c misc.c \ files.c dosys.c gram.y OBJECTS = main.o doname.o misc.o files.o \ dosys.o gram.o LIBES = LINT = lint -p CFLAGS = -O LP = lp
make: $(OBJECTS) $(CC) $(CFLAGS) -o make $(OBJECTS) $(LIBES) @size make
$(OBJECTS): defs.h
cleanup: -rm .o gram.c -du
install: make @size make /usr/ccs/bin/make cp make /usr/ccs/bin/make && rm make
lint: dosys.c doname.c files.c main.c misc.c gram.c $(LINT) dosys.c doname.c files.c main.c misc.c \ gram.c
# print files that are out-of-date # with respect to "print" file.
print: $(FILES) pr $? | $(LP) touch print
The following output results from entering the command make in a directory containing only the source and description files:
cc -O -c main.c cc -O -c doname.c cc -O -c misc.c cc -O -c files.c cc -O -c dosys.c yacc gram.y mv y.tab.c gram.c cc -O -c gram.c cc -o make main.o doname.o misc.o files.o dosys.o gram.o 13188 + 3348 + 3044 = 19580The last line results from the size make command. The printing of the command line itself was suppressed by the symbol ``@'' in the description file.