M A K E

 Make helps you maintain, update, or regenerate sets of programs or files.
 It is a great time-saver during program development.  No Unix system could
 survive without make.  Software distributed to Unix systems invariably comes 
 packaged so that it can be installed by make.

 Introduction
 ------------

 Make "knows" how to generate simple types of programs, e.g. C or Fortran
 programs residing in a single source file which do not use libraries. 
 Consider the following example

     % ls -l    
     total 2
     -rw-r--r--  1 boisvert       61 Nov  7 14:46 daniel.f
     -rw-r--r--  1 boisvert       69 Nov  7 14:45 jack.c
     % make jack
     cc    -sun4 -o jack jack.c 
     % make daniel
     f77   -sun4 -o daniel daniel.f 
     % ls -l
     total 178
     -rwxr-xr-x  1 boisvert   147456 Nov  7 15:00 daniel
     -rw-r--r--  1 boisvert       61 Nov  7 14:46 daniel.f
     -rwxr-xr-x  1 boisvert    24576 Nov  7 15:00 jack
     -rw-r--r--  1 boisvert       69 Nov  7 14:45 jack.c

 Here asked make to generate the files jack and daniel.  It observed that
 there were files named jack.c and daniel.f in the current directory, and
 hence used the C and Fortran compilers, respectively, to generate the
 executables.  Make also knows how to make .o files from .c files or .f
 files (e.g., "make jack.o").

 Make does not like to do unnecessary work.  Continuing the above example,
 if we ask make to generate the files jack and daniel again, it balks.

     % make jack daniel
     `jack' is up to date.
     `daniel' is up to date.

 Consider the first case.  Make determines that the file jack depends upon 
 jack.c.  It then looks at the modification times of these two file (i.e.
 the date and times printed by ls -l).  It sees that jack.c has not been
 changed since jack was last generated.  It concludes that there is no
 reason to regenerate it and reports that jack is "up to date".

 The following terminology is used : the files that you wish to maintain
 are called targets. The files needed to generate them are called dependencies.  The Unix commands used to generate a target from its dependencies are called 
 rules.  We see here that make knows rules for generating targets based on
 simple dependencies.  

 
 Maintaining Sets of Programs
 ----------------------------

 In most cases the relationship between a target and its dependencies is
 more complex.  For example, you might have a main program and many
 subprograms, each of which occupies a separate file.  Cnsider the case of
 an executable, prime, which depends upon three files : prime.f, sieve.f, 
 and addlst.f.

     % ls -l
     total 4
     -rw-r--r--  1 boisvert      200 Nov  7 15:15 addlst.f
     -rw-r--r--  1 boisvert      570 Nov  7 15:16 prime.f
     -rw-r--r--  1 boisvert      437 Nov  7 15:15 sieve.f
     % make prime
     f77   -sun4 -o prime prime.f 
     ld: Undefined symbol 
        _addlst_ 
        _sieve_ 
     *** Error code 1
     make: Fatal error: Command failed for target `prime'

 Make simply has no way to know which .f files must be combined to get a
 complete program.  

 In cases like this you must teach make how to generate the target.  You do 
 this by providing a file named Makefile in the current directory.  For each
 target you want to maintain you place an entry of the form 

    TARGET : DEPENDENCIES
       RULES

 in this file.  Rule lines must start with a tab character.  If there is no
 entry for a target, then make applies its default rules (called implicit
 rules).  Here is a simple Makefile for the above example:

     prime : prime.f sieve.f addlst.f
        f77 -o prime prime.f sieve.f addlst.f

 Supplied with this Makefile make knows what to do.

     % make prime
     f77 -o prime prime.f sieve.f addlst.f

 Some Shortcuts
 --------------

 When trying to debug Makefiles one often uses the Unix touch command.
 "touch name" changes the modification time of the named file to be the
 current time.  This is a way to fool make into thinking that you have
 changed a file.  

 Another useful tool is the -n option on the make command.  With this 
 option, make prints all the commands it intends to execute, but doesn't
 actually execute them.  We will make use of these things in the examples 
 that follow.

 If you type "make", make will work on the first target in the Makefile.

 Dependency Trees
 ----------------

 The rules for generating prime in the above example were not very efficient.
 If a change is made to any of the .f files, then, using the rules we supplied
 in the Makefile, make will recompile ALL of them, even though object files
 are available for the unchanged source.

     % ls -l       
     total 160
     -rw-r--r--  1 boisvert       73 Nov  7 15:18 Makefile
     -rw-r--r--  1 boisvert      200 Nov  7 15:53 addlst.f
     -rw-r--r--  1 boisvert      452 Nov  7 15:53 addlst.o
     -rwxr-xr-x  1 boisvert   147456 Nov  7 15:53 prime
     -rw-r--r--  1 boisvert      570 Nov  7 15:16 prime.f
     -rw-r--r--  1 boisvert     1144 Nov  7 15:53 prime.o
     -rw-r--r--  1 boisvert      437 Nov  7 15:15 sieve.f
     -rw-r--r--  1 boisvert      404 Nov  7 15:53 sieve.o
     % touch addlst.f
     % ls -l addlst.f
     -rw-r--r--  1 boisvert      200 Nov  7 15:54 addlst.f
     % make -n prime
     f77 -o prime prime.f sieve.f addlst.f

 A more exact representation of the dependencies among these files is
 contained in the following Makefile:

          prime : prime.o sieve.o addlst.o
             f77 -o prime prime.o sieve.o addlst.o

          prime.o : prime.f
             f77 -c prime.f

          sieve.o : sieve.f
             f77 -c sieve.f

          addlst.o : addlst.f
             f77 -c addlst.f

 (Note that the entries for the last three targets could have been omitted
 from the Makefile since they correspond to make's default rules for making
 .o files from .f files.)

 Here prime depends upon prime.o, sieve.o and addlst.o, which in turn depend
 upon prime.f, sieve.f, and addlst.f, respectively.  We see that, in general,
 each target generates a tree of dependencies.  The dependency tree for
 prime is
                          .---- prime ----.
                         /        |        \
                     prime.o   sieve.o   addlst.o
                       |          |         |
                     prime.f   sieve.f   addlst.f

 When asked to make a target, make inspects the entire dependency tree. 
 Beginning at the leaves of the tree, it compares the dates of each
 target-dependency pair, regenerating out-of-date-targets according to the
 rules in the Makefile, until it reaches the root.  

 With this Makefile, the example at the beginning of this section becomes

     % make -n prime
     f77 -c addlst.f
     f77 -o prime prime.o sieve.o addlst.o

 Macros
 ------

 There is a very useful macro substitution facility in make.  One defines a 
 macro by a simple assignment statement:

     MACRONAME = string

 "string" may have embedded blanks.  A macro is substituted anywhere in the
 Makefile using the notation

     $(MACRONAME)

 We simplify our example using macros as follows:

     OBJECTS = prime.o sieve.o addlst.o

     prime : $(OBJECTS)
      f77 -o prime $(OBJECTS)

 There are many predefined macros.  These macros are used heavily in make's
 implicit rules.  One can use this fact to modify the behavior of make's
 implicit rules.  For example, the implicit rule used by make to generate 
 .o files from .f files is something like
eted.  

 More Information
 ----------------

 We have only scratched the surface of make.  The man page for make contains
 alot more details, although it may be difficult to digest.  Books have been
 published which provide a more gentle introduction to make.  Among them are

   Steve Talbot, Managing Projects with Make, O'Reilly & Associates,
       (632 Petaluma Ave, Sebatopol, CA, 95472), 1990.
   Stephen G. Kochan and Patrick H. Wood, Topics in C Programming, Hayden
       Books, (4300 West 62nd St. ,Indianapolis, IN 46268), 1987, Chapter 7.

 - Ron Boisvert
   NIST, Center for Computing and Applied Mathematics
   23 Nov 1990