home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.update.uu.se
/
ftp.update.uu.se.2014.03.zip
/
ftp.update.uu.se
/
pub
/
rainbow
/
msdos
/
misc
/
make.lzh
/
MAKE.MEM
< prev
Wrap
Text File
|
1986-01-19
|
30KB
|
728 lines
27-Jul-84 14:29:12,29553;000000000005
Return-Path: <@COLUMBIA-20.ARPA:SY.FDC@CU20B>
Received: from COLUMBIA-20.ARPA by DEC-MARLBORO.ARPA with TCP; Fri 27 Jul 84 14:27:57-EDT
Received: from CU20B by CUCS20 with DECnet; 27 Jul 84 14:21:45 EDT
Date: Thu 26 Jul 84 09:36:11-EDT
From: Frank da Cruz <SY.FDC%CU20B@COLUMBIA-20.ARPA>
Subject: [Alan Crosswell <alan at CUUTSA>:]
To: Eiben@DEC-MARLBORO.ARPA
Here's the MAKE manual...
---------------
Received: from CUVMA by CU20B with HASP; 26 Jul 84 00:23:24 EDT
Received: from CUVMB by CUVMA id 1352; Wed, 25 Jul 84 23:35:51 EDT
Received: by CUVMB id 0791; Wed, 25 Jul 84 23:35:20 EDT
From: Alan Crosswell <alan at CUUTSA>
Date: 25 Jul 1984 23:35:13-EDT
Sender: UNIXA at CUVMB
Message-id: UTSROUTE alan rmail:alan x
To: sy.fdc@cu20b
------------------------------- Page i -------------------------------
Make - A Program for
Maintaining Computer Programs
S. I. Feldman
Edited for UTS
------------------------------- Page ii -------------------------------
TABLE OF CONTENTS
1. Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 1
3. Basic Features . . . . . . . . . . . . . . . . . . . . . . . . 2
4. Description Files and Substitutions . . . . . . . . . . . . . . 5
5. Command Usage . . . . . . . . . . . . . . . . . . . . . . . . . 7
6. Implicit Rules . . . . . . . . . . . . . . . . . . . . . . . . 8
7. Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
8. Suggestions and Warnings . . . . . . . . . . . . . . . . . . . 11
9. SCCS Files . . . . . . . . . . . . . . . . . . . . . . . . . . 12
10. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . 13
11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Appendix A. Suffixes and Transformation Rules . . . . . . . . . . 14
Last Page 15
-------------------------------- Page 1 --------------------------------
1. ABSTRACT
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. Make provides a simple mechanism for maintaining up-to-date ver-
sions of programs that result from many operations on several files. It
is possible to tell make the sequence of commands 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 make command will create the proper files simply,
correctly, and with a minimum amount of effort.
The basic operation of make 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; Make does a depth-first search of this graph to deter-
mine what work is really necessary.
Make also provides a simple macro substitution facility and the ability
to encapsulate commands in a single file for convenient administration.
2. INTRODUCTION
It is common practice to divide large programs into smaller, more manage-
able pieces. The pieces may require different treatments: some may need
to be run through 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 vali-
dated modules. Unfortunately, it is 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 hard to track down. On the other hand,
recompiling everything in sight just to be safe is wasteful.
-------------------------------- Page 2 --------------------------------
The program described in this report mechanizes many of the activities of
program development and maintenance. If the information on interfile
dependences and command sequences is stored in a file, the simple command
make
is frequently enough to update the interesting files, regardless of the
number that have been edited since the last 'make'. The description file
is usually easy to write, and changes infrequently. It is usually easier
to type the make command than to issue even one of the needed operations,
so the typical cycle of program development operations becomes
think -- edit -- make -- test . . .
Make is most useful for medium-sized programming projects; it does not
solve the problems of maintaining multiple source versions or of describ-
ing huge programs.
3. BASIC FEATURES
The basic operation of make 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. Make does a depth-first search of the graph of dependences. The
operation of the command depends on the ability to find the date and time
that a file was last modified.
To illustrate, let us consider a simple example: A program named prog is
made by compiling and loading three C language files x.c, y.c, and z.c
with the lpw 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 defs that z.c does
not. That is, x.c and y.c have the line
#include "defs"
The following text describes the relationships and operations:
prog: x.o y.o z.o
cc x.o y.o z.o -lpw -o prog
x.o y.o: defs
-------------------------------- Page 3 --------------------------------
If this information were stored in a file named makefile, the command
make
would perform the operations needed to re-create prog after any changes
had been made to any of the four source files x.c, y.c, z.c, or defs.
Make 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 prog depends on three '.o' files. Once
these object files are current, the second line describes how to load
them to create prog. The third line says that x.o and y.o depend on the
file defs. From the file system, make discovers that there are three
'.c' files corresponding to the needed '.o' files, and uses built-in
information 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 make's innate knowledge:
prog: x.o y.o z.o
cc x.o y.o z.o -lpw -o prog
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
If no source or object file has changed since the last time prog was
made, all of the files would be current, and the command
make
would just announce this fact and stop. If, however, the defs file had
been edited, x.c and y.c (but not z.c) would be recompiled, and then prog
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 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.o
-------------------------------- Page 4 --------------------------------
would recompile x.o if x.c or defs had changed.
If the file exists after the commands are executed, its time of last
modification is used in further decisions; otherwise the current time is
used. It is often useful to include rules with mnemonic names and com-
mands that do not produce a file with that name. These entries can take
advantage of make'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 throw away unneeded intermediate files. In
other cases one may maintain a zero length file purely to keep track of
the time at which certain actions were taken. This technique is useful
for maintaining remote archives and listings.
Make has a simple macro mechanism for substituting in dependency lines
and command strings. Macros are defined by command arguments or descrip-
tion file lines with embedded equal signs. A macro is invoked by preced-
ing the name by a dollar sign; macro names longer than one character may
be parenthesized. The name of the macro is either the single character
after the dollar sign or a name, possibly parenthesized. The following
are valid macro invocations:
$(CFLAGS)
$CFLAGS
$2
$(xy)
$Z
$(Z)
The first two and the last two invocations show that parenthesis are
optional. Both the parenthesized and the non-parenthesized versions have
identical meanings. $$ 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 be discussed later. The following fragment shows the use of macros:
OBJECTS = x.o y.o z.o
LIBES = -lpw
prog: $(OBJECTS)
cc $(OBJECTS) $(LIBES) -o prog
...
The command
make
loads the three object files with the lpw library. The command
-------------------------------- Page 5 --------------------------------
make "LIBES = -ll -lpw"
loads them with both the lex ('-ll') and the PWB ('-lpw') libraries,
since macro definitions on the command line override definitions in the
description. (It is necessary to quote arguments with embedded blanks in
UTS commands.)
The following sections detail the form of description files and the com-
mand line, and discuss options and built-in rules in more detail.
4. DESCRIPTION FILES AND SUBSTITUTIONS
A description file contains three types of information: macro defini-
tions, dependency information, and executable commands. There is also a
comment convention: all characters after a sharp (#) are ignored, as is
the sharp itself. Blank lines and lines beginning with a sharp are
totally ignored. If a noncomment line is too long, it can be continued
using a backslash. If the last character of a line is a backslash, the
backslash, new-line, and following blanks and tabs are replaced by a sin-
gle 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 -lpw
LIBES =
The last definition assigns LIBES the null string. A macro that is never
explicitly defined has the null string as value. Macro definitions may
also appear on the make command line (see below).
Other lines give information about target files. The general form of an
entry is:
target1 [target2 ...] :[:] [dependent1 ...] [; commands] [# ...]
[<TAB> commands] [# ...]
...
Items inside brackets may be omitted. Targets and dependents are strings
of letters, digits, periods, and slashes. (Shell metacharacters '*' and
-------------------------------- Page 6 --------------------------------
'?' are expanded.) A command is any string of characters not including a
sharp (except in quotes) or new-line. Commands may appear either after a
semicolon on a dependency line or on lines beginning with a tab or a
blank 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 such dependency line
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 par-
ticular 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 substituting for macros. (The print-
ing is suppressed in silent mode or if the command line begins with
an @ sign.) Make normally stops if any command signals an error by
returning a nonzero error code. (Errors are ignored if the '-i'
flags has been specified on the make command line, if the fake tar-
get name '.IGNORE' appears in the description file, or if the com-
mand string in the description file begins with a hyphen. Some UTS
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., cd and shell control commands) that
have meaning only within a single shell process; the results are
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 commands or
relevant built-in rules, the commands associated with the name
'.DEFAULT' are used. If there is no such name, make prints a mes-
sage and stops.
-------------------------------- Page 7 --------------------------------
5. COMMAND USAGE
The make 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 over-
ride corresponding definitions found in the description files.
Next, the flag arguments are examined. The permissible flags are
-z Print a detailed trace of make's analysis of your description file.
-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 executing. 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 make command returns a zero or nonzero status code
depending on whether the target file is up to date.
-p Print out the complete set of macro definitions and target descrip-
tions
-d Debug mode. Print out detailed information on files and times exam-
ined.
-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 makefile or
Makefile in the current directory is read. The contents of the
description files override the built-in rules if they are present.
-------------------------------- Page 8 --------------------------------
-I file Include the file name specified along with the description
file.
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'.
6. IMPLICIT RULES
The make program uses a table of interesting suffixes and a set of
transformation rules to supply default dependency 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
.h header file
.f Fortran source file
.t test file
.s assembler source file
.y yacc/C source grammar
.l lex source grammar
.q quickscreen source file
.*+ Save files where * is q, y, l, c, s, h, or f.
The following diagram summarizes the default transformation paths. If
there are two paths connecting a pair of suffixes, the longer one is used
only if the intermediate file exists or is named in the description. An
exception is an SCCS transformation, such as .c->.c, .s->.s, .q->.q,
.y->.y or .l->.l.
.o
.c .s .y .l .h
y .l .q .c+ .s+ .y+ .l+ .h+
y+ .l+ .q+
If the file x.o was needed and there was an x.c in the description or
directory, it would be compiled. If the file x.o was needed and there
was an x.c+ in the description or directory, it would be restored and
-------------------------------- Page 9 --------------------------------
then 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, make would discard the intermediate C language
file and use the direct link in the graph above.
It is possible to change the names of some of the compilers used in the
default, or the flag arguments with which they are invoked by knowing the
macro names used. The compiler names are the macros AS, CC, F77, YACC,
QS, and LEX. The command
make CC=newcc
will cause the 'newcc' command to be used instead of the usual C com-
piler. The macros CFLAGS, FFLAGS, QFLAGS, 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.
7. EXAMPLE
As an example of the use of make, we will present the description file
that maintains the make command itself. The code for make is spread over
several C source files and a yacc grammar. The description file con-
tains:
-------------------------------- Page 10 --------------------------------
#
# Description file for the "make" command
#
OBJECTS = main.o doname.o misc.o files.o dosys.o gram.o
LIBES=
LINT = lint -pxa
CC = cc
CFLAGS= -O -n
I = /usr/include
nmake: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) $(LIBES) -o nmake
/bin/make: nmake
/etc/instcmd nmake /bin/make
rm $(OBJECTS)
doname.o: doname.c defs $I/stdio.h $I/ctype.h \
$I/sys/types.h
$(CC) $(CFLAGS) -c -TR2 doname.c
dosys.o: dosys.c defs $I/stdio.h $I/ctype.h \
$I/sys/types.h $I/signal.h $I/errno.h \
$I/sys/stat.h
files.o: files.c defs $I/stdio.h $I/ctype.h \
$I/sys/types.h $I/sys/stat.h \
$I/pwd.h $I/ar.h $I/a.out.h \
$I/sys/stat.h $I/dir.h
gram.o: gram.y defs $I/stdio.h $I/ctype.h \
$I/sys/types.h
misc.o: misc.c defs $I/stdio.h $I/ctype.h \
$I/sys/types.h
lint : dosys.c doname.c files.c main.c misc.c ident.c gram.c
$(LINT) dosys.c doname.c files.c main.c misc.c ident.c gram.c
rm gram.c
Make usually prints out each command before issuing it. The following
output results from typing the simple command
make
in a directory containing only the save/restore source and the descrip-
tion file:
rest main.c
cc -O -n -c main.c
rest doname.c
-------------------------------- Page 11 --------------------------------
cc -O -n -c -TR2 doname.c
rest misc.c
cc -O -n -c misc.c
rest files.c
cc -O -n -c files.c
rest dosys.c
cc -O -n -c dosys.c
rest gram.y
yacc gram.y
cc -O -n -c y.tab.c
rm y.tab.c
mv y.tab.o gram.o
cc -O -n main.o doname.o misc.o files.o dosys.o gram.o -o nmake
It is not necessary to include all the file names and explicit commands
as make can find them by using its suffix rules and then it will issue
the needed commands. However, it is a good idea to be as explicit as
possible with dependencies and commands.
The first few entries in the description file are useful maintenance
sequences. The 'nmake' entry is the default procedure and will create a
make program named nmake in the current directory (to avoid any con-
flicts). The '/bin/make' entry depends on the nmake entry and will cause
a new copy of make to be installed in the '/bin' directory. The latter
is done with the 'make /bin/make' command, the former with either 'make'
(with no arguments) or with 'make nmake'.
8. SUGGESTIONS AND WARNINGS
The most common difficulties arise from make's specific meaning of depen-
dency. If file x.c has a '#include "defs"' line, then the object file
x.o depends on defs; the source file x.c does not. (If defs is changed,
it is not necessary to do anything to the file x.c, while it is necessary
to re-create x.o.)
To discover what make would do, the '-n' option is useful. The command
make -n
orders make to print out the commands it would issue without taking the
time to execute them. If a change to a file is absolutely certain to be
benign (e.g., adding a new definition to an include file), the '-t'
(touch) option can save much time: instead of issuing a large number of
-------------------------------- Page 12 --------------------------------
superfluous recompilations, make updates the modification times on the
affected file. Thus, the command
make -ts
('touch silently') causes the relevant files to appear up to date. Obvi-
ous care is necessary, since this mode of operation subverts the inten-
tion of make and destroys all memory of the previous relationships.
The debugging flag ('-d') causes make to print out a detailed description
of what it is doing, including the file times. The output is verbose,
and recommended only as a last resort.
The trace flag ('-z'), causes make to print its analysis of the descrip-
tion file. It primarily notes implicit and explicit dependencies, nest-
ing, and implicit and explicit command executions.
9. SCCS FILES
When there exist dependencies on SCCS files, one would ideally like make
to do "gets", do the necessary compiles and other actions, and then
remove the "gotten" file. However, because of make's current prefix and
suffix limitations, such capabilities are not entirely available. Make's
SCCS capabilities are limited. It is recommended that dependencies be
kept simple; use of explicit commands is encouraged. One-step transfor-
mation path "gets" can be handled implicitly, however.
Specifically, try such constructions as:
frog.o: frog.c
frog.c: s.frog.c
The following will not work correctly:
frog.o: s.frog.c
or
frog.o: frog.c
where frog.c does not exist
and s.frog.c does
-------------------------------- Page 13 --------------------------------
10. ACKNOWLEDGMENTS
I would like to thank S. C. Johnson for suggesting this approach to pro-
gram maintenance control. I would like to thank S. C. Johnson and H.
Gajewska for being the prime guinea pigs during development of make.
11. REFERENCES
[1] S. C. Johnson, Yacc -- Yet Another Compiler-Compiler,
[2] M. E. Lesk, Lex -- A Lexical Analyzer Generator.
-------------------------------- Page 14 --------------------------------
APPENDIX A. SUFFIXES AND TRANSFORMATION RULES
The make 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 description file. If the '-r' flag is used, this table is
not used.
The list of suffixes is really the dependency list for the name '.SUF-
FIXES'; make 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 combi-
nation, make 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 command 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 '.SUFFIXES' 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:
.SUFFIXES : .o .q .q+ .y .y+ .l .l+ .f .f+ .c .c+ .s .s+ .h .h+ .t
YACC=yacc
YFLAGS=
LEX=lex
LFLAGS=
CC=cc
AS=as
CFLAGS=
F77=f77
FFLAGS=
.c.o :
$(CC) $(CFLAGS) -c $<
.s.o :
$(AS) -o $@ $<
.y.o :
$(YACC) $(YFLAGS) $<
$(CC) $(CFLAGS) -c y.tab.c
rm y.tab.c
-------------------------------- Page 15 --------------------------------
mv y.tab.o $@
.y.c :
$(YACC) $(YFLAGS) $<
mv y.tab.c $@
-------