Make - A Program for Maintaining Computer Programs S. I. Feldman Bell Laboratories Murray Hill, New Jersey 07974 _A_B_S_T_R_A_C_T In a programming project, it is easy to lose track of which files need to be reprocessed or recompiled after a change is made in some part of the source. _M_a_k_e provides a simple mechanism for maintaining up-to-date versions of programs that result from many operations on a number of files. It is possible to tell _M_a_k_e the sequence of com- mands that create certain files, and the list of files that require other files to be current before the operations can be done. Whenever a change is made in any part of the program, the _M_a_k_e command will create the proper files simply, correctly, and with a minimum amount of effort. The basic operation of _M_a_k_e is to find the name of a needed target in the description, ensure that all of the files on which it depends exist and are up to date, and then create the target if it has not been modified since its generators were. The description file really defines the graph of dependencies; _M_a_k_e does a depth-first search of this graph to determine what work is really necessary. _M_a_k_e also provides a simple macro substitu- tion facility and the ability to encapsulate com- mands in a single file for convenient administra- tion. Revised April, 1986 _I_n_t_r_o_d_u_c_t_i_o_n It is common practice to divide large programs into smaller, more manageable pieces. The pieces may require quite different treatments: some may need to be run through September 2, 1987 - 2 - a macro processor, some may need to be processed by a sophisticated program generator (e.g., Yacc[1] or Lex[2]). The outputs of these generators may then have to be compiled with special options and with certain definitions and declarations. The code resulting from these transformations may then need to be loaded together with certain libraries under the control of special options. Related maintenance activities involve running complicated test scripts and installing validated modules. Unfortunately, it is very easy for a programmer to forget which files depend on which others, which files have been modified recently, and the exact sequence of operations needed to make or exercise a new version of the program. After a long editing session, one may easily lose track of which files have been changed and which object modules are still valid, since a change to a declaration can obsolete a dozen other files. Forgetting to compile a routine that has been changed or that uses changed declarations will result in a program that will not work, and a bug that can be very hard to track down. On the other hand, recompiling everything in sight just to be safe is very wasteful. The program described in this report mechanizes many of the activities of program development and maintenance. If the information on inter-file dependences and command sequences is stored in a file, the simple command make is frequently sufficient to update the interesting files, regardless of the number that have been edited since the last ``make''. In most cases, the description file is easy to write and changes infrequently. It is usually easier to type the _m_a_k_e command than to issue even one of the needed operations, so the typical cycle of program development operations becomes think - edit - _m_a_k_e - test . . . _M_a_k_e is most useful for medium-sized programming pro- jects; it does not solve the problems of maintaining multi- ple source versions or of describing huge programs. _M_a_k_e was designed for use on Unix, but a version runs on GCOS. _B_a_s_i_c _F_e_a_t_u_r_e_s The basic operation of _m_a_k_e is to update a target file by ensuring that all of the files on which it depends exist and are up to date, then creating the target if it has not been modified since its dependents were. _M_a_k_e does a depth-first search of the graph of dependences. The opera- tion of the command depends on the ability to find the date and time that a file was last modified. September 2, 1987 - 3 - To illustrate, let us consider a simple example: A pro- gram named _p_r_o_g is made by compiling and loading three C- language files _x._c, _y._c, and _z._c with the _l_S library. By convention, the output of the C 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 _d_e_f_s, but that _z._c does not. That is, _x._c and _y._c have the line #include "defs" The following text describes the relationships and opera- tions: prog : x.o y.o z.o cc x.o y.o z.o -lS -o prog 9 x.o y.o : defs If this information were stored in a file named _m_a_k_e_f_i_l_e, the command make would perform the operations needed to recreate _p_r_o_g after any changes had been made to any of the four source files _x._c, _y._c, _z._c, or _d_e_f_s. _M_a_k_e operates using three sources of information: a user-supplied description file (as above), file names and ``last-modified'' times from the file system, and built-in rules to bridge some of the gaps. In our example, the first line says that _p_r_o_g depends on three ``._o'' files. Once these object files are current, the second line describes how to load them to create _p_r_o_g. The third line says that _x._o and _y._o depend on the file _d_e_f_s. From the file system, _m_a_k_e discovers that there are three ``._c'' files correspond- ing to the needed ``._o'' files, and uses built-in informa- tion on how to generate an object from a source file (_i._e., issue a ``cc -c'' command). The following long-winded description file is equivalent to the one above, but takes no advantage of _m_a_k_e's innate knowledge: prog : x.o y.o z.o cc x.o y.o z.o -lS -o prog 9 x.o : x.c defs cc -c x.c y.o : y.c defs cc -c y.c z.o : z.c cc -c z.c September 2, 1987 - 4 - If none of the source or object files had changed since the last time _p_r_o_g was made, all of the files would be current, and the command make would just announce this fact and stop. If, however, the _d_e_f_s file had been edited, _x._c and _y._c (but not _z._c) would be recompiled, and then _p_r_o_g would be created from the new ``._o'' files. If only the file _y._c had changed, only it would be recompiled, but it would still be necessary to reload _p_r_o_g. If no target name is given on the _m_a_k_e command line, the first target mentioned in the description is created; otherwise the specified targets are made. The command make x.o would recompile _x._o if _x._c or _d_e_f_s had changed. If the file exists after the commands are executed, its time of last modification is used in further decisions; oth- erwise the current time is used. It is often quite useful to include rules with mnemonic names and commands that do not actually produce a file with that name. These entries can take advantage of _m_a_k_e's ability to generate files and substitute macros. Thus, an entry ``save'' might be included to copy a certain set of files, or an entry ``cleanup'' might be used to throw away unneeded intermedi- ate files. In other cases one may maintain a zero-length file purely to keep track of the time at which certain actions were performed. This technique is useful for main- taining remote archives and listings. _M_a_k_e has a simple macro mechanism for substituting in dependency lines and command strings. Macros are defined by command arguments or description file lines with embedded equal signs. A macro is invoked by preceding the name by a dollar sign; macro names longer than one character must be parenthesized. The name of the macro is either the single character after the dollar sign or a name inside parentheses. The following are valid macro invocations: $(CFLAGS) $2 $(xy) $Z $(Z) The last two invocations are identical. $$ is a dollar sign. All of these macros are assigned values during input, as shown below. Four special macros change values during the execution of the command: $*, $@, $?, and $<. They will September 2, 1987 - 5 - be discussed later. The following fragment shows the use: OBJECTS = x.o y.o z.o LIBES = -lS prog: $(OBJECTS) cc $(OBJECTS) $(LIBES) -o prog . . . The command make loads the three object files with the _l_S library. The com- mand make "LIBES= -ll -lS" loads them with both the Lex (``-ll'') and the Standard (``-lS'') libraries, since macro definitions on the command line override definitions in the description. (It is neces- sary to quote arguments with embedded blanks in UNIX* com- mands.) The following sections detail the form of description files and the command line, and discuss options and built-in rules in more detail. _D_e_s_c_r_i_p_t_i_o_n _F_i_l_e_s _a_n_d _S_u_b_s_t_i_t_u_t_i_o_n_s A description file contains three types of information: macro definitions, dependency information, and executable commands. There is also a comment convention: all charac- ters after a sharp (#) are ignored, as is the sharp itself. Blank lines and lines beginning with a sharp are totally ignored. If a non-comment line is too long, it can be con- tinued using a backslash. If the last character of a line is a backslash, the backslash, newline, and following blanks and tabs are replaced by a single blank. A macro definition is a line containing an equal sign not preceded by a colon or a tab. The name (string of letters and digits) to the left of the equal sign (trailing blanks and tabs are stripped) is assigned the string of characters following the equal sign (leading blanks and tabs are stripped.) The following are valid macro definitions: 2 = xyz abc = -ll -ly -lS LIBES = The last definition assigns LIBES the null string. A macro __________________________ * UNIX is a Trademark of Bell Laboratories. September 2, 1987 - 6 - that is never explicitly defined has the null string as value. Macro definitions may also appear on the _m_a_k_e com- mand line (see below). Other lines give information about target files. The general form of an entry is: target1 [target2 . . .] :[:] [dependent1 . . .] [; commands] [# . . .] [(_t_a_b) commands] [# . . .] . . . Items inside brackets may be omitted. Targets and depen- dents are strings of letters, digits, periods, and slashes. (Shell metacharacters ``*'' and ``?'' are expanded.) A com- mand is any string of characters not including a sharp (except in quotes) or newline. Commands may appear either after a semicolon on a dependency line or on lines beginning with a tab immediately following a dependency line. A dependency line may have either a single or a double colon. A target name may appear on more than one dependency line, but all of those lines must be of the same (single or double colon) type. 1. For the usual single-colon case, at most one of these dependency lines may have a command sequence associated with it. If the target is out of date with any of the dependents on any of the lines, and a command sequence is specified (even a null one following a semicolon or tab), it is executed; otherwise a default creation rule may be invoked. 2. In the double-colon case, a command sequence may be associated with each dependency line; if the target is out of date with any of the files on a particular line, the associated commands are executed. A built-in rule may also be executed. This detailed form is of partic- ular value in updating archive-type files. If a target must be created, the sequence of commands is executed. Normally, each command line is printed and then passed to a separate invocation of the Shell after sub- stituting for macros. (The printing is suppressed in silent mode or if the command line begins with an @ sign). _M_a_k_e normally stops if any command signals an error by returning a non-zero error code. (Errors are ignored if the ``-i'' flags has been specified on the _m_a_k_e command line, if the fake target name ``.IGNORE'' appears in the description file, or if the command string in the description file begins with a hyphen. Some UNIX commands return meaningless status). Because each command line is passed to a separate invocation of the Shell, care must be taken with certain commands (e.g., _c_d and Shell control commands) that have meaning only within a single Shell process; the results are September 2, 1987 - 7 - forgotten before the next line is executed. Before issuing any command, certain macros are set. $@ is set to the name of the file to be ``made''. $? is set to the string of names that were found to be younger than the target. If the command was generated by an implicit rule (see below), $< is the name of the related file that caused the action, and $* is the prefix shared by the current and the dependent file names. If a file must be made but there are no explicit com- mands or relevant built-in rules, the commands associated with the name ``.DEFAULT'' are used. If there is no such name, _m_a_k_e prints a message and stops. _C_o_m_m_a_n_d _U_s_a_g_e The _m_a_k_e command takes four kinds of arguments: macro definitions, flags, description file names, and target file names. make [ flags ] [ macro definitions ] [ targets ] The following summary of the operation of the command explains how these arguments are interpreted. First, all macro definition arguments (arguments with embedded equal signs) are analyzed and the assignments made. Command-line macros override corresponding definitions found in the description files. Next, the flag arguments are examined. The permissible flags are -i Ignore error codes returned by invoked commands. This mode is entered if the fake target name ``.IGNORE'' appears in the description file. -s Silent mode. Do not print command lines before execut- ing. This mode is also entered if the fake target name ``.SILENT'' appears in the description file. -r Do not use the built-in rules. -n No execute mode. Print commands, but do not execute them. Even lines beginning with an ``@'' sign are printed. -t Touch the target files (causing them to be up to date) rather than issue the usual commands. -q Question. The _m_a_k_e command returns a zero or non-zero status code depending on whether the target file is or is not up to date. September 2, 1987 - 8 - -p Print out the complete set of macro definitions and target descriptions -d Debug mode. Print out detailed information on files and times examined. -f Description file name. The next argument is assumed to be the name of a description file. A file name of ``-'' denotes the standard input. If there are no ``-f'' arguments, the file named _m_a_k_e_f_i_l_e or _M_a_k_e_f_i_l_e in the current directory is read. The contents of the description files override the built-in rules if they are present). Finally, the remaining arguments are assumed to be the names of targets to be made; they are done in left to right order. If there are no such arguments, the first name in the description files that does not begin with a period is ``made''. _I_m_p_l_i_c_i_t _R_u_l_e_s The _m_a_k_e program uses a table of interesting suffixes and a set of transformation rules to supply default depen- dency information and implied commands. (The Appendix describes these tables and means of overriding them.) The default suffix list is: ._o Object file ._c C source file ._e Efl source file ._r Ratfor source file ._f Fortran source file ._s Assembler source file ._y Yacc-C source grammar ._y_r Yacc-Ratfor source grammar ._y_e Yacc-Efl source grammar ._l Lex source grammar The following diagram summarizes the default transformation paths. If there are two paths connecting a pair of suf- fixes, the longer one is used only if the intermediate file exists or is named in the description. ._o ._c ._r ._e ._f ._s ._y ._y_r ._y_e ._l ._d ._y ._l ._y_r ._y_e If the file _x._o were needed and there were an _x._c in September 2, 1987 - 9 - the description or directory, it would be compiled. If there were also an _x._l, that grammar would be run through Lex before compiling the result. However, if there were no _x._c but there were an _x._l, _m_a_k_e would discard the intermedi- ate C-language file and use the direct link in the graph above. It is possible to change the names of some of the com- pilers used in the default, or the flag arguments with which they are invoked by knowing the macro names used. The com- piler names are the macros AS, CC, RC, EC, YACC, YACCR, YACCE, and LEX. The command make CC=newcc will cause the ``newcc'' command to be used instead of the usual C compiler. The macros CFLAGS, RFLAGS, EFLAGS, YFLAGS, and LFLAGS may be set to cause these commands to be issued with optional flags. Thus, make "CFLAGS=-O" causes the optimizing C compiler to be used. Another special macro is `VPATH'. The ``VPATH'' macro should be set to a list of directories separated by colons. When _m_a_k_e searches for a file as a result of a dependency relation, it will first search the current directory and then each of the directories on the ``VPATH'' list. If the file is found, the actual path to the file will be used, rather than just the filename. If ``VPATH'' is not defined, then only the current directory is searched. Note that ``VPATH'' is intended to act like the System V ``VPATH'' support, but there is no guarantee that it functions identi- cally. One use for ``VPATH'' is when one has several programs that compile from the same source. The source can be kept in one directory and each set of object files (along with a separate would be in a separate subdirectory. The ``VPATH'' macro would point to the source directory in this case. _E_x_a_m_p_l_e As an example of the use of _m_a_k_e, we will present the description file used to maintain the _m_a_k_e command itself. The code for _m_a_k_e is spread over a number of C source files and a Yacc grammar. The description file contains: September 2, 1987 - 10 - # Description file for the Make command 9 P = und -3 | opr -r2 # send to GCOS to be printed FILES = Makefile version.c defs main.c doname.c misc.c files.c dosys.cgram.y lex.c gcos.c OBJECTS = version.o main.o doname.o misc.o files.o dosys.o gram.o LIBES= -lS LINT = lint -p CFLAGS = -O 9 make: $(OBJECTS) cc $(CFLAGS) $(OBJECTS) $(LIBES) -o make size make 9 $(OBJECTS): defs gram.o: lex.c 9 cleanup: -rm *.o gram.c -du 9 install: @size make /usr/bin/make cp make /usr/bin/make ; rm make 9 print: $(FILES)# print recently changed files pr $? | $P touch print 9 test: make -dp | grep -v TIME >1zap /usr/bin/make -dp | grep -v TIME >2zap diff 1zap 2zap rm 1zap 2zap 9 lint : dosys.c doname.c files.c main.c misc.c version.c gram.c $(LINT) dosys.c doname.c files.c main.c misc.c version.c gram.c rm gram.c 9 arch: ar uv /sys/source/s2/make.a $(FILES) _M_a_k_e usually prints out each command before issuing it. The following output results from typing the simple command make in a directory containing only the source and description file: 9 September 2, 1987 - 11 - cc -c version.c cc -c main.c cc -c doname.c cc -c misc.c cc -c files.c cc -c dosys.c yacc gram.y mv y.tab.c gram.c cc -c gram.c cc version.o main.o doname.o misc.o files.o dosys.o gram.o -lS -o make 13188+3348+3044 = 19580b = 046174b Although none of the source files or grammars were mentioned by name in the description file, _m_a_k_e found them using its suffix rules and issued the needed commands. The string of digits results from the ``size make'' command; the printing of the command line itself was suppressed by an @ sign. The @ sign on the _s_i_z_e command in the description file suppressed the printing of the command, so only the sizes are written. The last few entries in the description file are useful maintenance sequences. The ``print'' entry prints only the files that have been changed since the last ``make print'' command. A zero-length file _p_r_i_n_t is maintained to keep track of the time of the printing; the $? macro in the com- mand line then picks up only the names of the files changed since _p_r_i_n_t was touched. The printed output can be sent to a different printer or to a file by changing the definition of the _P macro: make print "P = opr -sp" _o_r make print "P= cat >zap" _S_u_g_g_e_s_t_i_o_n_s _a_n_d _W_a_r_n_i_n_g_s The most common difficulties arise from _m_a_k_e's specific meaning of dependency. If file _x._c has a ``#include "defs"'' line, then the object file _x._o depends on _d_e_f_s; the source file _x._c does not. (If _d_e_f_s is changed, it is not necessary to do anything to the file _x._c, while it is neces- sary to recreate _x._o.) To discover what _m_a_k_e would do, the ``-n'' option is very useful. The command make -n orders _m_a_k_e to print out the commands it would issue without actually taking the time to execute them. If a change to a file is absolutely certain to be benign (e.g., adding a new September 2, 1987 - 12 - definition to an include file), the ``-t'' (touch) option can save a lot of time: instead of issuing a large number of superfluous recompilations, _m_a_k_e updates the modification times on the affected file. Thus, the command make -ts (``touch silently'') causes the relevant files to appear up to date. Obvious care is necessary, since this mode of operation subverts the intention of _m_a_k_e and destroys all memory of the previous relationships. The debugging flag (``-d'') causes _m_a_k_e to print out a very detailed description of what it is doing, including the file times. The output is verbose, and recommended only as a last resort. _A_c_k_n_o_w_l_e_d_g_m_e_n_t_s I would like to thank S. C. Johnson for suggesting this approach to program maintenance control. I would like to thank S. C. Johnson and H. Gajewska for being the prime guinea pigs during development of _m_a_k_e. _R_e_f_e_r_e_n_c_e_s 1. S. C. Johnson, ``Yacc - Yet Another Compiler- Compiler'', Bell Laboratories Computing Science Techni- cal Report #32, July 1978. 2. M. E. Lesk, ``Lex - A Lexical Analyzer Generator'', Computing Science Technical Report #39, October 1975. September 2, 1987 - 13 - _A_p_p_e_n_d_i_x. _S_u_f_f_i_x_e_s _a_n_d _T_r_a_n_s_f_o_r_m_a_t_i_o_n _R_u_l_e_s The _m_a_k_e program itself does not know what file name suffixes are interesting or how to transform a file with one suffix into a file with another suffix. This information is stored in an internal table that has the form of a descrip- tion file. If the ``-r'' flag is used, this table is not used. The list of suffixes is actually the dependency list for the name ``.SUFFIXES''; _m_a_k_e looks for a file with any of the suffixes on the list. If such a file exists, and if there is a transformation rule for that combination, _m_a_k_e acts as described earlier. The transformation rule names are the concatenation of the two suffixes. The name of the rule to transform a ``._r'' file to a ``._o'' file is thus ``._r._o''. If the rule is present and no explicit command sequence has been given in the user's description files, the command sequence for the rule ``.r.o'' is used. If a com- mand is generated by using one of these suffixing rules, the macro $* is given the value of the stem (everything but the suffix) of the name of the file to be made, and the macro $< is the name of the dependent that caused the action. The order of the suffix list is significant, since it is scanned from left to right, and the first name that is formed that has both a file and a rule associated with it is used. If new names are to be appended, the user can just add an entry for ``.SUFFIXES'' in his own description file; the dependents will be added to the usual list. A ``.SUF- FIXES'' line without any dependents deletes the current list. (It is necessary to clear the current list if the order of names is to be changed). The following is an excerpt from the default rules file: September 2, 1987 - 14 - .SUFFIXES : .o .c .e .r .f .y .yr .ye .l .s YACC=yacc YACCR=yacc -r YACCE=yacc -e YFLAGS= LEX=lex LFLAGS= CC=cc AS=as - CFLAGS= RC=ec RFLAGS= EC=ec EFLAGS= FFLAGS= .c.o : $(CC) $(CFLAGS) -c $< .e.o .r.o .f.o : $(EC) $(RFLAGS) $(EFLAGS) $(FFLAGS) -c $< .s.o : $(AS) -o $@ $< .y.o : $(YACC) $(YFLAGS) $< $(CC) $(CFLAGS) -c y.tab.c rm y.tab.c mv y.tab.o $@ .y.c : $(YACC) $(YFLAGS) $< mv y.tab.c $@ September 2, 1987