


1 MAKE
 Utility to maintain file groups.

 Format:

 $ make [qualifier(s)] [target(s)]
2 Introduction
 Make is a program which reads a file of dependencies and executes commands
 when  one file is out of date with respect to one or more files upon which
 it depends.  For  instance,  an  executable  image  FOO.EXE  depends  upon
 FOO.OBJ,  which  in  turn  depends  upon  FOO.C  and  FOO.H.   If FOO.H is
 modified, then it is newer than FOO.OBJ and so FOO.OBJ needs to be remade.
 Because  FOO.OBJ  is  remade,  FOO.EXE will become out of date and must be
 remade subsequently.  The MAKE  program  reads  user-supplied  description
 files and executes any commands required to bring the target(s) up to date
 with respect to all dependents.

 Make runs in two phases, parsing and making.  During the parsing phase all
 applicable  description  files  are read and digested by MAKE according to
 the standard UNIX syntax.  The file interdependencies are  then  assembled
 into  a  tree  in  memory.  During the making phase, MAKE will recursively
 compare the modification time  (as  per  DIR/DAT=MOD)  for  the  tree  (or
 sub-tree)   whose  root  is  either  the  first  target  in  the  file  of
 descriptions or the target(s) specified  on  the  command  line.   If  any
 target is older than any of its dependencies, then the commands associated
 with the relationship in question are added to a command file.  To  'make'
 FOO.EXE,  not only must FOO.EXE be newer than FOO.OBJ, but it must also be
 newer than any file upon which FOO.OBJ depends.
2 Syntax
 The description file is called a 'MAKEFILE',  as  in  UNIX.   MAKE  has  a
 well-defined  syntax  for describing file relationships.  In the following
 notation, objects are inside angle brackets, optional groups are indicated
 by square brackets, and whitespace is indicated by a '+' to mean 'at least
 one whitespace' and '*' to mean 'any or no whitespace'.

 <target>[+<target>...]*:[+<dependent>[+<dependent>...]]*[<special_stuff1>]
      OR
 +<command line>*[<special_stuff2>]
      OR
 <symbol>*=<equivalence>

 In this notation, we can formulate our FOO makefile thus:

 ##################################################################
                                                                  #
 # <== This is a comment indicator                                #
                                                                  #
 foo.exe: foo.obj        # This is a target line                  #
         link foo        # This is a DCL command line             #
                                                                  #
 foo.obj: foo.c foo.h    ! <== This is also a comment indicator   #
         cc/lis foo                                               #
                                                                  #
 ##################################################################

 As a human would read, it says,

 "FOO.EXE depends upon FOO.OBJ.  If FOO.EXE is out of date or  FOO.OBJ  has
 been  'made',  then add the command 'LINK FOO' to a file of commands to be
 executed.  FOO.OBJ depends upon FOO.C and FOO.H.  If it is out of date, or
 either  of  its  dependents have been 'made', then add 'CC/LIS FOO' to the
 command file to be executed."

 A target is out of date if it is newer than a dependent, but obviously the
 more  general  case  has  a  target out of date if it does not even exist.
 Also, one  can  create  targets  that  have  no  dependents,  a  so-called
 'terminal  target'.   Terminal  targets exist or don't exist, but can't be
 out of date.  If a terminal target does not exist, it will be 'built' (the
 commands for the target will be added to the command file).  If it exists,
 fine.  If any dependent is built, then the target is built as well.  Since
 the  'making'  is recursive, the leaves of the tree are checked before the
 branches so that this forces 'building' to  propagate  back  to  the  root
 target.
2 Getting_Fancy
 MAKE is not constrained to deal only with  files.   It  may  operate  upon
 directories,  modules  in VAX/VMS libraries, and in general can accomodate
 any object with a well-defined creation/modification date which has a time
 dependence  on  other  such  objects.   For  instance, if one periodically
 wanted to make network distributions of a program, the operations could be
 described in a makefile in a very concise manner:

 ###################################################################
 # The distribution will go into a directory called [.export].     #
 # \ is a continuation character                                   #
                                                                   #
 # Making 'distribution' makes all its dependents. Since           #
 # 'distribution' doesn't exist, 'building' its dependents         #
 # will satisfy MAKE.                                              #
                                                                   #
 distribution: export.dir [.export]foo.bck send cleanup            #
                                                                   #
 export.dir:                                                       #
 # if the directory doesn't exist...                               #
         cre/dir [.export]                                         #
                                                                   #
 [.export]foo.bck: foo.exe                                         #
 # if the saveset isn't up to date...                              #
         back/ver/lis *.* [.export]foo.bck/sav                     #
                                                                   #
 foo.exe: foo.obj                                                  #
 # if foo.exe isn't up to date...                                  #
         link foo                                                  #
                                                                   #
 foo.obj: foo.c foo.h                                              #
 # if foo.obj isn't up to date...                                  #
         cc/lis foo                                                #
 # if foo.c or foo.h aren't up to date, buy an editor.             #
                                                                   #
 send:                                                             #
 # send is always out of date, since it doesn't exist,             #
 # so perform the commands unconditionally...                      #
         send/file/vmsdump [.export]foo.bck joeblow@somenode       #
                                                                   #
 cleanup:                                                          #
 # cleanup is always out of date...                                #
         purge [.export]                                           #
 ###################################################################

 To make the distribution, from whatever state in which the files currently
 exist,  the  DCL command 'make distribution' would suffice.  If everything
 is up to date, nothing will be done.  It  is  important  to  note  in  the
 makefile  above  that  the  order in which the relationships are described
 does not matter.  The entire makefile is parsed before any actual 'making'
 is performed.

 The elegance of MAKE can be  found  in  the  simplicity  with  which  such
 conditional  sequencing  can expressed.  Those familiar with PROLOG should
 feel quite at home with MAKE (in fact, writing MAKE in  PROLOG  should  be
 almost trivial!).  In DCL, the command procedure would be a mass of nested
 'IF ...  THEN' clauses to provide the same capability.
2 MAKEFILE
 MAKE tries to parse two makefiles.  The first is the  default  rules  file
 and  the  second  is  the  makefile  pertaining  to  the group of files in
 question.  The default rules file can be called MAKE.INI  in  the  current
 directory,  or  it  may  be  called  MAKE_DEFAULTS (which may be a logical
 name).  If it can't find the default rules either way, MAKE doesn't really
 care  and  will  go on to the main makefile, called MAKEFILE.  This, also,
 may be a logical name, if desired.
3 MAKEFILE_Detail
 A  makefile  consists  of  target  lines,   command   lines,   symbol
 definitions,  and  comment  lines.   It  is  important  to  note that
 comments and  continuation  characters  never  make  it  past  MAKE's
 gullet.   The  first  step  in parsing is to remove comments from the
 line.  If anything is left, the line is checked  for  a  continuation
 character,  in  which  case  the  next  line(s) will be joined to the
 current line.  A line may be continued with the  '\'  backslash,  and
 comments  follow  either  '#'  sharp  or '!' bang.  Whitespace is ' '
 space or '       ' tab.  Command lines apply only to the  targets  on
 the  line  immediately  preceding the start of the command lines, but
 target dependencies may be specified anywhere in the  makefile.   For
 example, a valid (partial) description of the FOO example might be

 #################
 foo.obj : foo.h #
                 #
 foo.obj : foo.c #
         cc foo  #
 #################

 If foo.obj is out of date, the way in which it is  built  *must  not*
 depend upon which dependents forced foo.obj to be built.
4 Target_Lines
 A target line has no whitespace at the beginning and no '=' equal  in
 the    middle.    A   target   line   consists   of   one   or   more
 whitespace-separated targets, a colon  followed  by  whitespace,  and
 zero  or more whitespace-separated dependents.  Up to sixteen targets
 may precede the colon.  The dependents need not all be  specified  on
 one  line.   Since  dependents  are added to the tree cumulatively as
 they are read, the same target may be specified on more than one line
 depending  upon  different  files  as  in the example above.  Command
 lines are also added cumulatively, as will be described shortly.  The
 command lines to describe how to build the target apply *only* to the
 set of targets in the last target line before the commands.
4 Command_Lines
 All lines that begin with whitespace are DCL commands to be  executed
 to  update  the  target.   When (if) the command file is constructed,
 dollar signs will be prepended to each command line in  the  makefile
 so that DCL will swallow them.

 On DCL lines, two special characters exist.  The hyphen  '-'  as  the
 last  non-white character on a DCL line prevents MAKE from prepending
 a '$ ' to the next DCL line.  The hyphen is left in the  line.   This
 allows  true DCL continuation lines.  The dollar sign '$' as the last
 non-white character on DCL lines will cause MAKE to interpret it as a
 data  line,  so  again no '$ ' will be prepended to the command line.
 In addition, the '$' will be removed from the line.

 ########################
 list:                  #
         mcr install    #
         /list/full $   # The '$' prevents one from being placed in the
                        # command file.
 ########################

4 Symbol_Lines
 Sometimes it is helpful to be able to substitute a short keyword  for
 a  string.   To  do  this,  a  symbol may be defined according to the
 stated syntax.  To use a symbol defined  earlier  in  the  file,  the
 expression  '$(<symbol  name>)'  will  translate  to the value of the
 symbol.  For instance...

 #######################
 CC = cc/lis/noobj

 foo.obj: foo.c foo.h
         $(CC) foo
 #######################

 In a software project of reasonable extent, it is helpful to be  able
 to  change  compiler switches occasionally.  Symbols provide a simple
 mechanism for this.

 Except for a  few  special  symbols,  all  replacement  is  performed
 immediately  during  the  parsing  phase.  A symbol reference with no
 definition is considered a fatal error.  Symbol names may consist  of
 any alphanumeric characters, with no length constraints.  Symbols may
 be indicated not only by '$()', but also by '${}'.  For single-letter
 symbols  such  as 'a', 'b', '1', '2', etc., the parentheses or braces
 may be omitted under some circumstances:

 ######################
 1 = one

 test: $1                       # no problem with this one, but...
       write sys$output "$(1)"  # to avoid misinterpretation

 ######################

 Note that the '$o' in 'sys$output' is not misinterpreted as a  symbol
 since the letter 'o' is followed by an alphanumeric character.
4 Directives
 The makefile may include several  directives,  which  tell  the  MAKE
 utility  additional  information  about processing the makefile.  The
 directive name must be ALL CAPS, preceeded by a '%', and begin at the
 first  column  of  the  makefile.   The  following list describes the
 directives:

     %INCLUDE <filename> - Read in and parse an additional makefile.

     %CMSLIB <directory> - Establish a default  CMS  library  for  CMS
     target.

     %CMSGEN <generation> - Select a specific CMS generation.

     %DEBUG - Turn on debugging (like MAKE/DEBUG).

     %NODEBUG - Turn off debugging.

     %SPAWN - Cause commands to be executed within a  spawned  process
     (link MAKE/SPAWN).

     %NOSPAWN - Cause commands  to  be  executed  within  the  current
     process

     %FIRST <command_line> - Specifies a DCL command  to  be  executed
     within  the  resultant make command file BEFORE any of the actual
     targets are constructed (useful for symbol definitions, etc.).

     %LAST <command_line> - Specifies a DCL  command  to  be  executed
     following the build of all targets.

 Any of the directives may be used singly or multiply at any point  in
 the makefile, and in any sequence.
3 Getting_More_Fancy
 When dealing with complex programs, it  is  not  reasonable  to  list
 explicitly  rules for compilation of every module.  Rather, one would
 like to be able to say "If X.Obj is out of date, go look for X.C  and
 compile  it, regardless of who X is." This feature is provided by the
 default rules mechanism:

 ####################
 *.obj : *.c        #
         cc $*      # '$*' is a symbol which means
                    # 'whatever matched the *'.
 ####################

 With the above makefile, we may compile any C program (FOO) by giving
 the  DCL  command  '$ make foo.obj'.  The default rule will match the
 '*' with 'foo' and will insert '$ cc foo' into the commands file.

 The default rules will be searched for a pattern match only if either
 there are no rules for the file in question or there are rules but no
 command lines.  If a match is found, the default rules will be  added
 just as though they were found explicitly in the makefile.

 Note that this default rules mechanism parallels the UNIX  'suffixes'
 mechanism,  but  the  syntax  is quite different.  It is the author's
 intention to add the UNIX syntax in the future.
3 Special_Symbols
 For each target definition in  the  makefile,  there  are  a  set  of
 special  symbols  that are defined while specifying command lines for
 that target:

 1.  $TARGET (or '$@') expands to the target name.

 2.  $TARGET_NAME (or '$*') expands to the root  name  of  the  target
     (file  name  specification  up  to,  but  not  including the file
     extension or library module specification).

 3.  $SOURCE (or '$<') expands to the primary source name  (the  first
     prerequisite listed).

 4.  $SOURCE_NAME expands to the root name of the primary source.

 5.  $TARGET_LIB_ELEMENT (or '$%') expands to the library module  name
     of the target.

 6.  $SOURCELIBELEMENT (or '$&') expands to the library module name of
     the primary source listed.

 7.  $TARGET_TYPE ($SOURCE_TYPE) expands  to  the  file  type  of  the
     appropriate specification.

 8.  $TARGET_DIR  ($SOURCE_DIR)  expands  to  the  directory  of   the
     appropriate specification.

 9.  $TARGET_DEV ($SOURCE_DEV) expands  to  the  device  name  of  the
     appropriate specification.

10.  $TARGET_NODE ($SOURCE_NODE) expands  to  the  node  name  of  the
     appropriate specification.

 For example:

 ####################################################
 *.obj : *.c                                        #
         cc $</obj=$@/list=${$TARGET_NAME}.lst      #
                                                    #
 ####################################################

 With the above makefile, we may compile any C program (FOO) by giving
 the  DCL  command  '$ make foo.obj'.  The default rule will match the
 '*' with 'foo' and will insert '$ cc  FOO.C/obj=FOO.OBJ/list=FOO.LST'
 into the commands file.

 If the target is a 'terminal target' (having no extension), then  the
 symbols  '$*' and '$@' will both be equal to the target name.  If the
 prerequisite has no extension, then the symbol '$<' will be equal  to
 the symbol '$*'.

 These symbols are useable in both the default  definitions  file  and
 the primary MAKEFILE.  being used.
3 Getting_Real_Fancy
 A special form of name is recognized.  A name like  'a.olb(b)'  means
 the  module named 'b' stored in the library named 'a.olb'.  This name
 is handled just like a  normal  file  name,  except  that  a  special
 routine is entered to read the modification time of the module in the
 library.  If the library doesn't exist, then it is made.  If there is
 a rule for creating the library, such as

 ##############
 a.olb :
         lib/cre a
 ##############

 it will be created.  Otherwise,  an  error  is  signalled  since  the
 library  couldn't  be found.  Note that you can use a default rule to
 create the library if it doesn't exist:

 ###################
 *.olb :
         lib/cre $*
 *.hlb :
         lib/help/cre $*
 *.tlb :
         lib/cre/text $*
 ###################

3 Default_Rules
 Default rules are typically placed  in  in  the  default  rules  file
 (MAKE.INI  or  MAKE_DEFAULTS)  just  to keep things neat and orderly.
 This file need not exist for MAKE to run.  The  first  possible  name
 for  which  both  a  file  and  a rule exist is inferred, in cases of
 multiple default rules for a file type.
3 More_On_Command_Lines
 Command lines are added to a command procedure file built during  the
 make processing.  Special lines are added at the beginning and end of
 the command file, depending upon the settings of some of the  command
 switches.

 Normal operation has the MAKE command file terminate if the  severity
 level   of  an  error  is  ERROR  or  FATAL.   The  command  file  is
 automatically deleted  after  processing  (even  aborted  processing)
 unless  -k  is  specified.   By  appropriate  use of command options,
 procedure verification may be turned on, errors may be  ignored,  and
 the command file may be retained.
2 Command_Options
 /INPUT=<file> -- Choose an alternate makefile.

 /OUTPUT=<file> -- Specify the name of the command file.  Use '/KEEP'  also
 if you actually wish for the file to remain.

 /SPAWN -- Don't wait for commands to complete.   Perform  a  SPAWN/NOWAIT.
 Default is /NOSPAWN.

 /IGNORE -- Ignore errors in the command file.  This is done by putting the
 line "$ Set NoOn" at the top of the command file.  Default is /NOIGNORE.

 /EXECUTE -- Execute the  commands  needed  to  update  the  targets.   The
 negation of this qualifier is useful in conjunction with '/KEEP' to create
 a static command file for later use.  Default is /EXECUTE.

 /DEFAULTS -- Read  the  default  rules  file  MAKE.INI  or  MAKE_DEFAULTS.
 Default is /DEFAULTS.

 /VERIFY  --  Echo  commands  as  they  execute  (procedure  verification).
 Default is /NOVERIFY.

 /DEBUG -- Print debugging info (for bug reports).  Default is /NODEBUG.
2 General_Advice
 The makefile that comes with MAKE/VMS is a very good example of  what  can
 be  done  with  the  system.   Also,  UNIX  makefiles are fairly useful to
 examine, but obviously the command lines will be different.   Also,  since
 it  is horribly inefficient in VMS to spawn a subprocess for each command,
 there is a fundamental difference between the operation on VMS  and  UNIX.
 UNIX  MAKE  spawns for each command, but VMS MAKE builds a command file to
 be executed one way or the other at the end.  I like my way  much  better,
 but I have the advantage of hindsight.
2 BUGS
 I'm sure there are plenty.  Report bugs to

                Todd Aven       (212)807-7800
                the Softwear Sweatshop
                % Datability Software Systems, Inc.
                322 Eight Avenue
                New York, NY 10001

 Net addresses
 =============

 Internet:       todd%dss@med.nyu.edu
 Bitnet:         todd%dss@nyumed

 ******** Please include /DEBUG output. *********
