








                       PPMMaakkee ---- AA TTuuttoorriiaall

                           _A_d_a_m _d_e _B_o_o_r
                        Berkeley Softworks
                   2150 Shattuck Ave, Penthouse
                        Berkeley, CA 94704
                         adam@bsw.uu.net
                        ...!uunet!bsw!adam



   11..  IInnttrroodduuccttiioonn
   PMake  is a program for creating other programs, or anything
   else you can think of for it to do.  The basic  idea  behind
   PMake  is  that,  for any given system, be it a program or a
   document or whatever, there will be some files  that  depend
   on  the  state  of other files (on when they were last modi-
   fied). PMake takes these dependencies, which you must  spec-
   ify,  and  uses  them to build whatever it is you want it to
   build.
   PMake is almost fully-compatible with Make, with  which  you
   may  already  be familiar. PMake's most important feature is
   its ability to run several different jobs  at  once,  making
   the  creation  of systems considerably faster. It also has a
   great deal more  functionality  than  Make.  Throughout  the
   text,  whenever  something is mentioned that is an important
   difference between PMake and Make (i.e.  something that will
   cause  a  makefile  to  fail if you don't do something about
   it), or is simply important, it will be flagged with a  lit-
----tle sign in the left margin, like this:
|    Th|is  tutorial  is  divided  into three main sections corre-
| NOTEsp|onding to basic, intermediate and advanced PMake usage. If
|    yo|u already know Make well, you will only need to skim chap-
----ter 2 (there are some aspects of PMake that I consider basic
   to  its use that didn't exist in Make).  Things in chapter 3
   make life much easier, while those in chapter 4 are strictly
   for  those who know what they are doing. Chapter 5 has defi-
   nitions for the jargon I use and chapter 6 contains possible
   solutions to the problems presented throughout the tutorial.


   -----------
   Permission  to  use,  copy, modify, and distribute
   this software and its documentation for  any  pur-
   pose  and  without fee is hereby granted, provided
   that the above copyright  notice  appears  in  all
   copies.   The  University  of California, Berkeley
   Softworks, and Adam de Boor  make  no  representa-
   tions  about  the suitability of this software for
   any purpose.   It  is  provided  "as  is"  without
   express or implied warranty.









   PSD:12-2                                 PMake -- A Tutorial


   22..  TThhee BBaassiiccss ooff PPMMaakkee
   PMake takes as input a file that tells a) which files depend
   on  which other files to be complete and b) what to do about
   files that are ``out-of-date.'' This  file  is  known  as  a
   ``makefile''  and  is usually kept in the top-most directory
   of the system to be built. While you can call  the  makefile
   anything you want, PMake will look for MMaakkeeffiillee and mmaakkeeffiillee
   (in that order) in the current directory if you  don't  tell
   it  otherwise.   To specify a different makefile, use the --ff
   flag (e.g.  ``ppmmaakkee --ff pprrooggrraamm..mmkk'').
   A makefile has four different types of lines in it:
        +o File dependency specifications
        +o Creation commands
        +o Variable assignments
        +o Comments, include statements and  conditional  direc-
          tives
   Any  line  may be continued over multiple lines by ending it
   with a backslash.  The backslash, following newline and  any
   initial whitespace on the following line are compressed into
   a single space before the input line is examined by PMake.

   22..11..  DDeeppeennddeennccyy LLiinneess
   As mentioned in the introduction, in any system,  there  are
   dependencies between the files that make up the system.  For
   instance, in a program made up of several C source files and
   one  header  file,  the  C files will need to be re-compiled
   should the header file be changed. For a document of several
   chapters  and  one  macro file, the chapters will need to be
   reprocessed if any of the macros changes.  These are  depen-
   dencies  and  are  specified by means of dependency lines in
   the makefile.
   On a dependency line, there are targets and  sources,  sepa-
   rated  by  a  one-  or  two-character operator.  The targets
   ``depend'' on the sources and are usually created from them.
   Any  number  of  targets  and  sources may be specified on a
   dependency line.  All the targets in the line  are  made  to
   depend  on all the sources.  Targets and sources need not be
   actual files, but every source must be either an actual file
   or  another target in the makefile.  If you run out of room,
   use a backslash at the end of the line to continue onto  the
   next one.
   Any  file  may be a target and any file may be a source, but
   the relationship between the two (or however many) is deter-
   mined  by the ``operator'' that separates them.  Three types
   of operators exist: one specifies that the  datedness  of  a
   target  is  determined  by  the  state of its sources, while
   another specifies other files (the sources) that need to  be
   dealt  with  before  the target can be re-created. The third
   operator is very similar to the first, with  the  additional
   condition  that  the  target  is  out-of-date  if  it has no
   sources. These operations are represented by the colon,  the
   exclamation  point  and  the double-colon, respectively, and
   are mutually exclusive. Their exact semantics  are  as  fol-
   lows:









   PMake -- A Tutorial                                 PSD:12-3


   :    If  a colon is used, a target on the line is considered
        to be ``out-of-date'' (and in need of creation) if
        +o any of the sources has been  modified  more  recently
          than the target, or
        +o the target doesn't exist.
        Under  this operation, steps will be taken to re-create
        the target only if it is found  to  be  out-of-date  by
        using these two rules.
   !    If an exclamation point is used, the target will always
        be re-created, but this will not happen  until  all  of
        its  sources have been examined and re-created, if nec-
        essary.
   ::   If a double-colon is used, a target is out-of-date if:
        +o any of the sources has been  modified  more  recently
          than the target, or
        +o the target doesn't exist, or
        +o the target has no sources.
        If  the target is out-of-date according to these rules,
        it will be re-created.  This operator also  does  some-
        thing else to the targets, but I'll go into that in the
        next section (``Shell Commands'').
   Enough words, now for an example. Take that C program I men-
   tioned  earlier.  Say  there are three C files (aa..cc, bb..cc and
   cc..cc) each of which includes the file ddeeffss..hh.  The  dependen-
   cies between the files could then be expressed as follows:

        pprrooggrraamm         :: aa..oo bb..oo cc..oo
        aa..oo bb..oo cc..oo     :: ddeeffss..hh
        aa..oo             :: aa..cc
        bb..oo             :: bb..cc
        cc..oo             :: cc..cc

   You  may  be wondering at this point, where aa..oo, bb..oo and cc..oo
   came in and why _t_h_e_y depend on ddeeffss..hh and the C files don't.
   The  reason is quite simple: pprrooggrraamm cannot be made by link-
   ing together .c files -- it must  be  made  from  .o  files.
   Likewise,  if  you change ddeeffss..hh, it isn't the .c files that
   need to be re-created, it's the .o files.  If you  think  of
   dependencies in these terms -- which files (targets) need to
   be created from which files (sources) -- you should have  no
   problems.
   An  important  thing  to  notice about the above example, is
   that all the .o files appear as targets  on  more  than  one
   line.  This  is  perfectly  all right: the target is made to
   depend on all the sources mentioned on  all  the  dependency
----lines. E.g.  aa..oo depends on both ddeeffss..hh and aa..cc.
|    Th|e  order of the dependency lines in the makefile is impor-
| NOTEta|nt: the first target on the first dependency line  in  the
|    ma|kefile  will  be  the  one that gets made if you don't say
----otherwise.  That's why pprrooggrraamm comes first  in  the  example
   makefile, above.
   Both  targets  and  sources may contain the standard C-Shell
   wildcard characters ({{, }}, **, ??, [[, and  ]]),  but  the  non-
   curly-brace ones may only appear in the final component (the









   PSD:12-4                                 PMake -- A Tutorial


   file portion) of the target or source. The  characters  mean
   the following things:
   {{}}   These  enclose  a  comma-separated  list of options and
        cause the pattern to be expanded once for each  element
        of  the  list. Each expansion contains a different ele-
        ment. For example, ssrrcc//{{wwhhiiffffllee,,bbeeeepp,,ffiisshh}}..cc expands to
        the   three   words   ssrrcc//wwhhiiffffllee..cc,   ssrrcc//bbeeeepp..cc,  and
        ssrrcc//ffiisshh..cc.  These braces may be nested and, unlike the
        other wildcard characters, the resulting words need not
        be actual files.  All  other  wildcard  characters  are
        expanded  using  the  files  that  exist  when PMake is
        started.
   **    This matches zero  or  more  characters  of  any  sort.
        ssrrcc//**..cc will expand to the same three words as above as
        long as ssrrcc contains those three files  (and  no  other
        files that end in ..cc).
   ??    Matches any single character.
   [[]]   This  is known as a character class and contains either
        a list of single characters, or a series  of  character
        ranges (aa--zz, for example means all characters between a
        and z), or both. It matches any single  character  con-
        tained  in the list. E.g.  [[AA--ZZaa--zz]] will match all let-
        ters, while [[00112233445566778899]] will match all numbers.

   22..22..  SShheellll CCoommmmaannddss
   ``Isn't that nice,'' you say  to  yourself,  ``but  how  are
   files actually `re-created,' as he likes to spell it?''  The
   re-creation is accomplished by commands  you  place  in  the
   makefile.   These  commands  are  passed to the Bourne shell
   (better  known  as  ``/bin/sh'')  to  be  executed  and  are
   expected  to  do  what's necessary to update the target file
   (PMake doesn't actually check to see if the target was  cre-
   ated. It just assumes it's there).
   Shell  commands in a makefile look a lot like shell commands
   you would type at a terminal, with one important  exception:
   each  command in a makefile _m_u_s_t be preceded by at least one
   tab.
   Each target has associated with it a shell script made up of
   one or more of these shell commands. The creation script for
   a target should immediately follow the dependency  line  for
   that  target. While any given target may appear on more than
   one dependency line, only one of these dependency lines  may
   be  followed  by a creation script, unless the `::' operator
----was used on the dependency line.
|    If|the double-colon was used, each dependency line  for  the
| NOTEta|rget  may  be followed by a shell script. That script will
|    on|ly be executed if the target on the associated  dependency
----line  is  out-of-date  with  respect  to the sources on that
   line, according to the rules I gave earlier.  I'll give  you
   a good example of this later on.
   To expand on the earlier makefile, you might add commands as
   follows:











   PMake -- A Tutorial                                 PSD:12-5


        pprrooggrraamm         :: aa..oo bb..oo cc..oo
                cccc aa..oo bb..oo cc..oo --oo pprrooggrraamm
        aa..oo bb..oo cc..oo     :: ddeeffss..hh
        aa..oo             :: aa..cc
                cccc --cc aa..cc
        bb..oo             :: bb..cc
                cccc --cc bb..cc
        cc..oo             :: cc..cc
                cccc --cc cc..cc

   Something you should remember when writing  a  makefile  is,
   the  commands  will  be executed if the _t_a_r_g_e_t on the depen-
   dency line is out-of-date, not the sources.  In  this  exam-
   ple,  the  command  ``cccc --cc aa..cc'' will be executed if aa..oo is
   out-of-date. Because of the `:' operator,  this  means  that
   should  aa..cc  _o_r ddeeffss..hh have been modified more recently than
   aa..oo, the command will be executed (aa..oo  will  be  considered
   out-of-date).
   Remember  how  I said the only difference between a makefile
   shell command and a regular shell command  was  the  leading
   tab? I lied. There is another way in which makefile commands
   differ from regular ones.  The first  two  characters  after
   the  initial  whitespace are treated specially.  If they are
   any combination of `@' and `-', they cause PMake to do  dif-
   ferent things.
   In  most  cases,  shell  commands are printed before they're
   actually executed. This is to keep you  informed  of  what's
   going  on.  If an `@' appears, however, this echoing is sup-
   pressed. In the case of an eecchhoo command, say ``eecchhoo  LLiinnkkiinngg
   iinnddeexx,'' it would be rather silly to see

        eecchhoo LLiinnkkiinngg iinnddeexx
        LLiinnkkiinngg iinnddeexx

   so  PMake  allows  you  to  place  an `@' before the command
   (``@@eecchhoo LLiinnkkiinngg iinnddeexx'') to prevent the command from  being
   printed.
   The  other  special character is the `-'. In case you didn't
   know, shell commands finish with a certain ``exit  status.''
   This  status  is  made  available by the operating system to
   whatever program invoked the command. Normally  this  status
   will  be  0  if everything went ok and non-zero if something
   went wrong. For this reason, PMake will consider an error to
   have occurred if one of the shells it invokes returns a non-
   zero status. When it detects an error, PMake's usual  action
   is  to  abort  whatever  it's doing and exit with a non-zero
   status itself (any other targets  that  were  being  created
   will  continue  being made, but nothing new will be started.
   PMake will exit after the last job finishes).  This behavior
   can  be altered, however, by placing a `-' at the front of a
   command  (``--mmvv  iinnddeexx  iinnddeexx..oolldd''),  certain  command-line
   arguments,  or  doing other things, to be detailed later. In
   such a case, the non-zero status is simply ignored and PMake
   keeps chugging along.









   PSD:12-6                                 PMake -- A Tutorial


----Because all the commands are given to a single shell to exe-
|    cu|te, such  things  as  setting  shell  variables,  changing
| NOTEdi|rectories, etc., last beyond the command in which they are
|    fo|und. This also allows shell compound  commands  (like  ffoorr
----loops)  to be entered in a natural manner.  Since this could
   cause problems for some makefiles that depend on  each  com-
   mand  being  executed by a single shell, PMake has a --BB flag
   (it stands for backwards-compatible) that forces  each  com-
   mand  to  be given to a separate shell. It also does several
   other things, all of which I discourage since they  are  now
----old-fashioned....
|    A |target's  shell  script  is  fed to the shell on its (the
| NOTEsh|ell's) input stream.  This means that any  commands,  such
|    as| ccii  that  need to get input from the terminal won't work
----right -- they'll get the shell's input, something they prob-
   ably won't find to their liking. A simple way around this is
   to give a command like this:

        ccii $$((SSRRCCSS)) << //ddeevv//ttttyy

   This would force the program's input to come from the termi-
   nal.  If  you can't do this for some reason, your only other
   alternative is to use PMake  in  its  fullest  compatibility
   mode. See CCoommppaattiibbiilliittyy in chapter 4.

   22..33..  VVaarriiaabblleess
   PMake,  like Make before it, has the ability to save text in
   variables to be recalled later at  your  convenience.  Vari-
   ables  in  PMake  are  used much like variables in the shell
   and, by tradition, consist of all  upper-case  letters  (you
   don't  _h_a_v_e  to use all upper-case letters.  In fact there's
   nothing to stop you from calling a  variable  @@^^&&$$%%$$.   Just
   tradition).  Variables  are  assigned-to  using lines of the
   form

        VVAARRIIAABBLLEE == vvaalluuee

   appended-to by

        VVAARRIIAABBLLEE ++== vvaalluuee

   conditionally assigned-to (if  the  variable  isn't  already
   defined) by

        VVAARRIIAABBLLEE ??== vvaalluuee

   and  assigned-to  with expansion (i.e. the value is expanded
   (see below) before being assigned  to  the  variable--useful
   for placing a value at the beginning of a variable, or other
   things) by

        VVAARRIIAABBLLEE ::== vvaalluuee











   PMake -- A Tutorial                                 PSD:12-7


   Any whitespace before _v_a_l_u_e is stripped off. When appending,
   a  space is placed between the old value and the stuff being
   appended.
   The final way a variable may be assigned to is using

        VVAARRIIAABBLLEE !!== sshheellll--ccoommmmaanndd

   In this case, _s_h_e_l_l_-_c_o_m_m_a_n_d has all its  variables  expanded
   (see  below)  and  is  passed off to a shell to execute. The
   output of the shell is then placed in the variable. Any new-
   lines  (other  than  the  final  one) are replaced by spaces
   before the assignment is made. This  is  typically  used  to
   find the current directory via a line like:

        CCWWDD             !!== ppwwdd

   NNoottee::  this  is intended to be used to execute commands that
   produce small amounts of output (e.g. ``pwd'').  The  imple-
   mentation is less than intelligent and will likely freeze if
   you execute something that produces thousands  of  bytes  of
   output (8 Kb is the limit on many UNIX systems).
   The  value  of  a variable may be retrieved by enclosing the
   variable name in parentheses or curly braces and  preceeding
   the whole thing with a dollar sign.
   For  example,  to  set  the  variable  CFLAGS  to the string
   ``--II//sspprriittee//ssrrcc//lliibb//lliibbcc --OO,'' you would place a line

        CCFFLLAAGGSS == --II//sspprriittee//ssrrcc//lliibb//lliibbcc --OO

   in the makefile and use  the  word  $$((CCFFLLAAGGSS))  wherever  you
   would  like  the string --II//sspprriittee//ssrrcc//lliibb//lliibbcc --OO to appear.
----This is called variable expansion.
|    Un|like Make, PMake will not  expand  a  variable  unless  it
| NOTEkn|ows  the  variable  exists.  E.g.  if you have a $${{ii}} in a
|    sh|ell command and you have not assigned a value to the vari-
----able ii (the empty string is considered a value, by the way),
   where Make would have substituted the  empty  string,  PMake
   will  leave the $${{ii}} alone.  To keep PMake from substituting
   for a variable  it  knows,  precede  the  dollar  sign  with
   another  dollar  sign.   (e.g. to pass $${{HHOOMMEE}} to the shell,
   use $$$${{HHOOMMEE}}).  This causes PMake, in effect, to expand  the
   $$  macro,  which  expands to a single $$.  For compatibility,
   Make's style of variable  expansion  will  be  used  if  you
   invoke  PMake with any of the compatibility flags (--VV, --BB or
   --MM.  The --VV flag alters just the variable expansion).
   There are two different times at  which  variable  expansion
   occurs: When parsing a dependency line, the expansion occurs
   immediately upon reading the line. If any variable used on a
   dependency line is undefined, PMake will print a message and
   exit.  Variables in shell commands  are  expanded  when  the
   command is executed.  Variables used inside another variable
   are expanded whenever the outer variable  is  expanded  (the
   expansion  of  an  inner variable has no effect on the outer
   variable. I.e. if the outer variable is used on a dependency









   PSD:12-8                                 PMake -- A Tutorial


   line  and in a shell command, and the inner variable changes
   value between when the dependency line is read and the shell
   command  is  executed,  two different values will be substi-
   tuted for the outer variable).
   Variables come in four flavors, though they are all expanded
   the  same and all look about the same. They are (in order of
   expanding scope):
        +o Local variables.
        +o Command-line variables.
        +o Global variables.
        +o Environment variables.
   The classification of variables doesn't matter much,  except
   that  the  classes  are searched from the top (local) to the
   bottom (environment) when looking up a variable.  The  first
   one found wins.

   22..33..11..  LLooccaall VVaarriiaabblleess
   Each target can have as many as seven local variables. These
   are variables that are only ``visible'' within that target's
   shell  script  and contain such things as the target's name,
   all of its sources (from all its  dependency  lines),  those
   sources  that  were  out-of-date, etc.  Four local variables
   are defined for all targets. They are:
        .TARGET
             The name of the target.
        .OODATE
             The list of the sources for the target  that  were
             considered  out-of-date.  The order in the list is
             not guaranteed to be the  same  as  the  order  in
             which the dependencies were given.
        .ALLSRC
             The  list  of  all  sources for this target in the
             order in which they were given.
        .PREFIX
             The target without  its  suffix  and  without  any
             leading     path.     E.g.    for    the    target
             ....//....//lliibb//ccoommppaatt//ffssRReeaadd..cc,  this  variable   would
             contain ffssRReeaadd.
   Three other local variables are set only for certain targets
   under special  circumstances.  These  are  the  ``.IMPSRC,''
   ``.ARCHIVE,''  and  ``.MEMBER'' variables. When they are set
   and how they are used is described later.
   Four of these variables may be used in sources as well as in
   shell   scripts.    These   are   ``.TARGET'',  ``.PREFIX'',
   ``.ARCHIVE'' and ``.MEMBER''. The variables in  the  sources
   are  expanded  once  for each target on the dependency line,
   providing what is known as a  ``dynamic  source,''  allowing
   you  to  specify several dependency lines at once. For exam-
   ple,

        $$((OOBBJJSS))         :: $$((..PPRREEFFIIXX))..cc

   will create a dependency between each object  file  and  its
   corresponding C source file.









   PMake -- A Tutorial                                 PSD:12-9


   22..33..22..  CCoommmmaanndd--lliinnee VVaarriiaabblleess
   Command-line  variables  are set when PMake is first invoked
   by giving a variable assignment as one of the arguments. For
   example,

        ppmmaakkee ""CCFFLLAAGGSS == --II//sspprriittee//ssrrcc//lliibb//lliibbcc --OO""

   would  make CCFFLLAAGGSS be a command-line variable with the given
   value. Any assignments to CCFFLLAAGGSS in the makefile  will  have
   no effect, because once it is set, there is (almost) nothing
   you can do to change a  command-line  variable  (the  search
   order, you see). Command-line variables may be set using any
   of the four assignment  operators,  though  only  ==  and  ??==
   behave  as  you would expect them to, mostly because assign-
   ments to command-line variables  are  performed  before  the
   makefile  is  read,  thus the values set in the makefile are
   unavailable at the time.  ++== is the same as ==,  because  the
   old  value  of  the  variable is sought only in the scope in
   which the assignment is taking place (for reasons  of  effi-
   ciency  that I won't get into here).  ::== and ??== will work if
   the only variables used are in the environment.  !!== is  sort
   of  pointless  to  use from the command line, since the same
   effect can no doubt be accomplished using  the  shell's  own
   command substitution mechanisms (backquotes and all that).

   22..33..33..  GGlloobbaall VVaarriiaabblleess
   Global  variables  are those set or appended-to in the make-
   file.  There are two classes of global variables: those  you
   set  and  those  PMake sets.  As I said before, the ones you
   set can have any name you want them to have, except they may
   not  contain a colon or an exclamation point.  The variables
   PMake sets (almost) always begin with a  period  and  always
   contain  upper-case letters, only. The variables are as fol-
   lows:
        .PMAKE
             The name by which PMake was invoked is  stored  in
             this variable. For compatibility, the name is also
             stored in the MAKE variable.
        .MAKEFLAGS
             All  the  relevant  flags  with  which  PMake  was
             invoked.  This  does not include such things as --ff
             or variable assignments. Again for  compatibility,
             this  value  is  stored  in the MFLAGS variable as
             well.
   Two other variables, ``.INCLUDES'' and ``.LIBS,''  are  cov-
   ered in the section on special targets in chapter 3.
   Global variables may be deleted using lines of the form:

        ##uunnddeeff _v_a_r_i_a_b_l_e

   The  `##'  must be the first character on the line. Note that
   this may only be done on global variables.











   PSD:12-10                                PMake -- A Tutorial


   22..33..44..  EEnnvviirroonnmmeenntt VVaarriiaabblleess
   Environment variables are passed by the shell  that  invoked
   PMake  and are given by PMake to each shell it invokes. They
   are expanded like any other variable,  but  they  cannot  be
   altered in any way.
   One  special  environment  variable,  PPMMAAKKEE,  is examined by
   PMake for command-line flags, variable assignments, etc., it
   should  always  use.  This  variable  is examined before the
   actual arguments to PMake are. In addition, all flags  given
   to  PMake,  either through the PPMMAAKKEE variable or on the com-
   mand line, are  placed  in  this  environment  variable  and
   exported  to each shell PMake executes. Thus recursive invo-
   cations of PMake automatically receive the same flags as the
   top-most one.
   Using all these variables, you can compress the sample make-
   file even more:

        OOBBJJSS            == aa..oo bb..oo cc..oo
        pprrooggrraamm         :: $$((OOBBJJSS))
                cccc $$((..AALLLLSSRRCC)) --oo $$((..TTAARRGGEETT))
        $$((OOBBJJSS))         :: ddeeffss..hh
        aa..oo             :: aa..cc
                cccc --cc aa..cc
        bb..oo             :: bb..cc
                cccc --cc bb..cc
        cc..oo             :: cc..cc
                cccc --cc cc..cc


   22..44..  CCoommmmeennttss
   Comments in a makefile start with a `#' character and extend
   to  the  end  of the line. They may appear anywhere you want
   them, except in a shell command (though the shell will treat
   it  as a comment, too). If, for some reason, you need to use
   the `#' in a variable or on a dependency line, put  a  back-
   slash  in  front  of it.  PMake will compress the two into a
   single `#' (Note: this isn't true if PMake is  operating  in
   full-compatibility mode).

----22..55..  PPaarraalllleelliissmm
|    PM|ake was specifically designed to re-create several targets
| NOTEat|once, when possible. You do not have to do anything  spe-
|    ci|al to cause this to happen (unless PMake was configured to
----not act in parallel, in which case you will have to make use
   of  the  --LL and --JJ flags (see below)), but you do have to be
   careful at times.
   There are several problems you are likely to encounter.  One
   is  that some makefiles (and programs) are written in such a
   way that it is impossible for two  targets  to  be  made  at
   once.  The  program  xxssttrr,  for example, always modifies the
   files ssttrriinnggss and xx..cc.  There is no way to change  it.  Thus
   you  cannot  run two of them at once without something being
   trashed. Similarly, if you have  commands  in  the  makefile
   that  always  send  output to the same file, you will not be









   PMake -- A Tutorial                                PSD:12-11


   able to make more than one target at once unless you  change
   the  file  you use. You can, for instance, add a $$$$$$$$ to the
   end of the file name to tack on the process ID of the  shell
   executing  the  command (each $$$$ expands to a single $$, thus
   giving you the shell variable $$$$).  Since only one shell  is
   used for all the commands, you'll get the same file name for
   each command in the script.
   The other problem comes from improperly-specified  dependen-
   cies  that  worked in Make because of its sequential, depth-
   first way of examining them. While I don't want to  go  into
   depth on how PMake works (look in chapter 4 if you're inter-
   ested), I will warn you that files in two  different  ``lev-
   els''  of the dependency tree may be examined in a different
   order in PMake than they were in Make.  For  example,  given
   the makefile

        aa               :: bb cc
        bb               :: dd

   PMake  will examine the targets in the order cc, dd, bb, aa.  If
   the makefile's author expected PMake to abort before  making
   cc  if  an  error  occurred while making bb, or if bb needed to
   exist before cc was made, s/he will be  sorely  disappointed.
   The  dependencies are incomplete, since in both these cases,
   cc would depend on bb.  So watch out.
   Another problem you may face is that, while PMake is set  up
   to  handle the output from multiple jobs in a graceful fash-
   ion, the same is not so for input.  It has no way  to  regu-
   late  input to different jobs, so if you use the redirection
   from //ddeevv//ttttyy I mentioned earlier, you must be  careful  not
   to run two of the jobs at once.

   22..66..  WWrriittiinngg aanndd DDeebbuuggggiinngg aa MMaakkeeffiillee
   Now  you  know  most of what's in a makefile, what do you do
   next? There are two choices: (1) use one of the  uncommonly-
   available makefile generators or (2) write your own makefile
   (I leave out the third choice of ignoring  PMake  and  doing
   everything  by  hand  as  being  beyond the bounds of common
   sense).
   When faced with the writing of a  makefile,  it  is  usually
   best  to start from first principles: just what _a_r_e you try-
   ing to do? What do you want the makefile finally to produce?
   To  begin with a somewhat traditional example, let's say you
   need to write a makefile to create  a  program,  eexxpprr,  that
   takes standard infix expressions and converts them to prefix
   form (for no readily  apparent  reason).  You've  got  three
   source  files,  in  C,  that  make  up  the program: mmaaiinn..cc,
   ppaarrssee..cc, and oouuttppuutt..cc.  Harking  back  to  my  pithy  advice
   about  dependency  lines,  you  write  the first line of the
   file:

        eexxpprr            :: mmaaiinn..oo ppaarrssee..oo oouuttppuutt..oo

   because you remember eexxpprr is made  from  ..oo  files,  not  ..cc









   PSD:12-12                                PMake -- A Tutorial


   files. Similarly for the ..oo files you produce the lines:

        mmaaiinn..oo          :: mmaaiinn..cc
        ppaarrssee..oo         :: ppaarrssee..cc
        oouuttppuutt..oo        :: oouuttppuutt..cc
        mmaaiinn..oo ppaarrssee..oo oouuttppuutt..oo :: ddeeffss..hh

   Great.  You've  now got the dependencies specified. What you
   need now is commands. These commands, remember, must produce
   the  target  on  the  dependency  line, usually by using the
   sources you've listed.  You remember about local  variables?
   Good, so it should come to you as no surprise when you write

        eexxpprr            :: mmaaiinn..oo ppaarrssee..oo oouuttppuutt..oo
                cccc --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))

   Why use the variables? If  your  program  grows  to  produce
   postfix  expressions  too (which, of course, requires a name
   change or two), it is one fewer place you have to change the
   file.  You  cannot  do  this  for the object files, however,
   because they depend on their corresponding source files  _a_n_d
   ddeeffss..hh, thus if you said

             cccc --cc $$((..AALLLLSSRRCC))

   you'd get (for mmaaiinn..oo):

             cccc --cc mmaaiinn..cc ddeeffss..hh

   which  is  wrong.  So  you round out the makefile with these
   lines:

        mmaaiinn..oo          :: mmaaiinn..cc
                cccc --cc mmaaiinn..cc
        ppaarrssee..oo         :: ppaarrssee..cc
                cccc --cc ppaarrssee..cc
        oouuttppuutt..oo        :: oouuttppuutt..cc
                cccc --cc oouuttppuutt..cc

   The makefile is now complete and will, in fact,  create  the
   program  you  want it to without unnecessary compilations or
   excessive typing on your part. There are  two  things  wrong
   with  it,  however (aside from it being altogether too long,
   something I'll address in chapter 3):
   1)   The string  ``mmaaiinn..oo  ppaarrssee..oo  oouuttppuutt..oo''  is  repeated
        twice,  necessitating  two changes when you add postfix
        (you were planning on that, weren't you?). This  is  in
        direct  violation  of  de  Boor's First Rule of writing
        makefiles:
        _A_n_y_t_h_i_n_g _t_h_a_t _n_e_e_d_s _t_o _b_e _w_r_i_t_t_e_n _m_o_r_e  _t_h_a_n  _o_n_c_e
        _s_h_o_u_l_d _b_e _p_l_a_c_e_d _i_n _a _v_a_r_i_a_b_l_e_.
        I  cannot emphasize this enough as being very important
        to the maintenance of a makefile and its program.










   PMake -- A Tutorial                                PSD:12-13


   2)   There is no way to alter the way compilations are  per-
        formed  short  of  editing  the makefile and making the
        change in all places. This  is  evil  and  violates  de
        Boor's  Second  Rule,  which  follows directly from the
        first:
        _A_n_y _f_l_a_g_s  _o_r  _p_r_o_g_r_a_m_s  _u_s_e_d  _i_n_s_i_d_e  _a  _m_a_k_e_f_i_l_e
        _s_h_o_u_l_d  _b_e  _p_l_a_c_e_d  _i_n  _a  _v_a_r_i_a_b_l_e _s_o _t_h_e_y _m_a_y _b_e
        _c_h_a_n_g_e_d_,  _t_e_m_p_o_r_a_r_i_l_y  _o_r  _p_e_r_m_a_n_e_n_t_l_y_,  _w_i_t_h  _t_h_e
        _g_r_e_a_t_e_s_t _e_a_s_e_.
   The makefile should more properly read:

        OOBBJJSS            == mmaaiinn..oo ppaarrssee..oo oouuttppuutt..oo
        eexxpprr            :: $$((OOBBJJSS))
                $$((CCCC)) $$((CCFFLLAAGGSS)) --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
        mmaaiinn..oo          :: mmaaiinn..cc
                $$((CCCC)) $$((CCFFLLAAGGSS)) --cc mmaaiinn..cc
        ppaarrssee..oo         :: ppaarrssee..cc
                $$((CCCC)) $$((CCFFLLAAGGSS)) --cc ppaarrssee..cc
        oouuttppuutt..oo        :: oouuttppuutt..cc
                $$((CCCC)) $$((CCFFLLAAGGSS)) --cc oouuttppuutt..cc
        $$((OOBBJJSS))         :: ddeeffss..hh

   Alternatively,  if you like the idea of dynamic sources men-
   tioned in section 2.3.1, you could write it like this:

        OOBBJJSS            == mmaaiinn..oo ppaarrssee..oo oouuttppuutt..oo
        eexxpprr            :: $$((OOBBJJSS))
                $$((CCCC)) $$((CCFFLLAAGGSS)) --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
        $$((OOBBJJSS))         :: $$((..PPRREEFFIIXX))..cc ddeeffss..hh
                $$((CCCC)) $$((CCFFLLAAGGSS)) --cc $$((..PPRREEFFIIXX))..cc

   These two rules and examples lead to de Boor's First  Corol-
   lary:
        _V_a_r_i_a_b_l_e_s _a_r_e _y_o_u_r _f_r_i_e_n_d_s_.
   Once  you've  written  the  makefile  comes  the  sometimes-
   difficult task of making sure the  darn  thing  works.  Your
   most helpful tool to make sure the makefile is at least syn-
   tactically correct is the --nn flag, which allows you  to  see
   if PMake will choke on the makefile. The second thing the --nn
   flag lets you do is see what PMake would do without it actu-
   ally  doing  it,  thus  you can make sure the right commands
   would be executed were you to give PMake its head.
   When you find your makefile isn't behaving as you hoped, the
   first  question that comes to mind (after ``What time is it,
   anyway?'') is ``Why not?'' In answering this, two flags will
   serve  you  well:  ``--dd  mm'' and ``--pp 22.''  The first causes
   PMake to tell you as it examines each target in the makefile
   and indicate why it is deciding whatever it is deciding. You
   can then use the information printed for  other  targets  to
   see  where  you  went  wrong.  The ``--pp 22'' flag makes PMake
   print out its internal state when it is done,  allowing  you
   to  see  that  you forgot to make that one chapter depend on
   that file of macros you just got a new version of. The  out-
   put  from  ``--pp  22''  is intended to resemble closely a real









   PSD:12-14                                PMake -- A Tutorial


   makefile, but with additional information provided and  with
   variables  expanded in those commands PMake actually printed
   or executed.
   Something to be especially careful about is circular  depen-
   dencies.  E.g.

        aa         :: bb
        bb         :: cc dd
        dd         :: aa

   In  this  case,  because  of  how PMake works, cc is the only
   thing PMake will examine, because dd and aa  will  effectively
   fall  off  the edge of the universe, making it impossible to
   examine bb (or them, for that matter).  PMake will  tell  you
   (if  run in its normal mode) all the targets involved in any
   cycle it looked at (i.e. if you have two cycles in the graph
   (naughty,  naughty), but only try to make a target in one of
   them, PMake will only tell you about that one.  You'll  have
   to try to make the other to find the second cycle). When run
   as Make, it will only print the first target in the cycle.

   22..77..  IInnvvookkiinngg PPMMaakkee
   PMake comes with a wide variety of  flags  to  choose  from.
   They may appear in any order, interspersed with command-line
   variable assignments and targets to create.  The  flags  are
   as follows:
   --dd _w_h_a_t
        This  causes  PMake  to  spew out debugging information
        that may prove useful to you. If you can't  figure  out
        why PMake is doing what it's doing, you might try using
        this flag. The _w_h_a_t parameter is  a  string  of  single
        characters  that tell PMake what aspects you are inter-
        ested in. Most of what  I  describe  will  make  little
        sense  to  you,  unless  you've dealt with Make before.
        Just remember where this table is and come back  to  it
        as  you  read  on.   The characters and the information
        they produce are as follows:
        a    Archive searching and caching.
        c    Conditional evaluation.
        d    The searching and caching of directories.
        j    Various snippets of  information  related  to  the
             running  of  the multiple shells. Not particularly
             interesting.
        m    The making of each target: what  target  is  being
             examined; when it was last modified; whether it is
             out-of-date; etc.
        p    Makefile parsing.
        r    Remote execution.
        s    The application  of  suffix-transformation  rules.
             (See chapter 3)
        t    The maintenance of the list of targets.
        v    Variable assignment.
        Of  these  all, the mm and ss letters will be most useful
        to you.  If  the  --dd  is  the  final  argument  or  the









   PMake -- A Tutorial                                PSD:12-15


        argument from which it would get these key letters (see
        below for a note about which argument  would  be  used)
        begins  with  a --, all of these debugging flags will be
        set, resulting in massive amounts of output.
   --ff _m_a_k_e_f_i_l_e
        Specify a makefile to read different from the  standard
        makefiles  (MMaakkeeffiillee  or  mmaakkeeffiillee).   If  _m_a_k_e_f_i_l_e  is
        ``-'', PMake uses the standard input.  This  is  useful
        for making quick and dirty makefiles...
   --hh   Prints  out  a  summary  of  the  various  flags  PMake
        accepts. It can also be used to find out what level  of
        concurrency  was compiled into the version of PMake you
        are using (look at --JJ and --LL) and various other  infor-
        mation on how PMake was configured.
   --ii   If  you give this flag, PMake will ignore non-zero sta-
        tus returned by any of its shells. It's like placing  a
        `-' before all the commands in the makefile.
   --kk   This  is  similar to --ii in that it allows PMake to con-
        tinue when it sees an error, but unlike --ii, where PMake
        continues  blithely as if nothing went wrong, --kk causes
        it to recognize the error and  only  continue  work  on
        those  things  that  don't depend on the target, either
        directly or indirectly (through depending on  something
        that depends on it), whose creation returned the error.
        The `k' is for ``keep going''...
   --ll   PMake has the ability to lock a directory against other
        people  executing it in the same directory (by means of
        a file called ``LOCK.make'' that it creates and  checks
        for in the directory). This is a Good Thing because two
        people doing the same thing in the same  place  can  be
        disastrous  for  the  final product (too many cooks and
        all that).  Whether this locking is the default  is  up
        to your system administrator. If locking is on, --ll will
        turn it off, and vice versa.  Note  that  this  locking
        will  not  prevent _y_o_u from invoking PMake twice in the
        same place -- if you own the lock file, PMake will warn
        you about it but continue to execute.
   --nn   This  flag  tells  PMake  not  to  execute the commands
        needed to update the out-of-date targets in  the  make-
        file.  Rather,  PMake will simply print the commands it
        would have executed and exit. This is particularly use-
        ful  for  checking  the  correctness  of a makefile. If
        PMake doesn't do what you expect it  to,  it's  a  good
        chance the makefile is wrong.
   --pp _n_u_m_b_e_r
        This  causes  PMake  to print its input in a reasonable
        form, though not necessarily one that would make  imme-
        diate  sense to anyone but me. The _n_u_m_b_e_r is a bitwise-
        or of 1 and 2 where 1 means it should print  the  input
        before  doing any processing and 2 says it should print
        it after everything has  been  re-created.  Thus  --pp  33
        would  print  it twice--once before processing and once
        after (you might find the difference  between  the  two
        interesting).  This is mostly useful to me, but you may









   PSD:12-16                                PMake -- A Tutorial


        find it informative in some bizarre circumstances.
   --qq   If you give PMake this flag, it will  not  try  to  re-
        create  anything.  It will just see if anything is out-
        of-date and exit non-zero if so.
   --rr   When PMake starts up, it reads a default makefile  that
        tells  it what sort of system it's on and gives it some
        idea of what to do if you don't tell it anything.  I'll
        tell  you about it in chapter 3. If you give this flag,
        PMake won't read the default makefile.
   --ss   This causes PMake to not print commands before  they're
        executed. It is the equivalent of putting an `@' before
        every command in the makefile.
   --tt   Rather than try to re-create a target, PMake will  sim-
        ply ``touch'' it so as to make it appear up-to-date. If
        the target didn't exist before, it will when PMake fin-
        ishes,  but  if the target did exist, it will appear to
        have been updated.
   --vv   This is a mixed-compatibility flag  intended  to  mimic
        the  System V version of Make. It is the same as giving
        --BB, and --VV as well as turning  off  directory  locking.
        Targets can still be created in parallel, however. This
        is the mode PMake will enter if it is invoked either as
        ``ssmmaakkee'' or ``vvmmaakkee''.
   --xx   This  tells  PMake  it's  ok  to  export  jobs to other
        machines, if they're available. It is used when running
        in  Make  mode, as exporting in this mode tends to make
        things run slower than if the commands were  just  exe-
        cuted locally.
   --BB   Forces PMake to be as backwards-compatible with Make as
        possible while still being itself.  This includes:
        +o Executing one shell per shell command
        +o Expanding anything that looks  even  vaguely  like  a
          variable,  with  the empty string replacing any vari-
          able PMake doesn't know.
        +o Refusing to allow you to escape a `#'  with  a  back-
          slash.
        +o Permitting  undefined  variables  on dependency lines
          and conditionals (see below).  Normally  this  causes
          PMake to abort.
   --CC   This nullifies any and all compatibility mode flags you
        may have given or implied up to  the  time  the  --CC  is
        encountered. It is useful mostly in a makefile that you
        wrote for PMake to  avoid  bad  things  happening  when
        someone runs PMake as ``mmaakkee'' or has things set in the
        environment that tell it to be compatible.  --CC  is  _n_o_t
        placed  in the PPMMAAKKEE environment variable or the ..MMAAKKEE--
        FFLLAAGGSS or MMFFLLAAGGSS global variables.
   --DD _v_a_r_i_a_b_l_e
        Allows you to define a variable to have  ``11''  as  its
        value.   The  variable is a global variable, not a com-
        mand-line variable. This is useful  mostly  for  people
        who  are  used  to  the  C compiler arguments and those
        using conditionals, which I'll get into in section 4.3










   PMake -- A Tutorial                                PSD:12-17


   --II _d_i_r_e_c_t_o_r_y
        Tells PMake another place to search for included  make-
        files.  Yet  another thing to be explained in chapter 3
        (section 3.2, to be precise).
   --JJ _n_u_m_b_e_r
        Gives the absolute maximum number of targets to  create
        at once on both local and remote machines.
   --LL _n_u_m_b_e_r
        This  specifies the maximum number of targets to create
        on the local machine at once. This may be 0, though you
        should be wary of doing this, as PMake may hang until a
        remote machine becomes available, if one is not  avail-
        able when it is started.
   --MM   This is the flag that provides absolute, complete, full
        compatibility with Make. It still allows you to use all
        but  a  few  of  the  features of PMake, but it is non-
        parallel. This is the mode PMake enters if you call  it
        ``mmaakkee.''
   --PP   When  creating  targets in parallel, several shells are
        executing at once, each wanting to write  its  own  two
        cent's-worth  to  the screen.  This output must be cap-
        tured by PMake in some way  in  order  to  prevent  the
        screen from being filled with garbage even more indeci-
        pherable than you usually see. PMake has  two  ways  of
        doing this, one of which provides for much cleaner out-
        put and a clear separation between the output  of  dif-
        ferent jobs, the other of which provides a more immedi-
        ate response so one can tell what is really happpening.
        The  former  is done by notifying you when the creation
        of a target starts, capturing the output and  transfer-
        ring  it  to  the  screen all at once when the job fin-
        ishes. The latter is done by catching the output of the
        shell  (and  its  children)  and  buffering it until an
        entire line is received, then printing that  line  pre-
        ceded  by  an indication of which job produced the out-
        put. Since I prefer this second method, it is  the  one
        used  by  default. The first method will be used if you
        give the --PP flag to PMake.
   --VV   As mentioned before, the --VV flag  tells  PMake  to  use
        Make's  style  of expanding variables, substituting the
        empty string for any variable it doesn't know.
   --WW   There are several times when PMake will print a message
        at  you that is only a warning, i.e. it can continue to
        work in spite of your having done something silly (such
        as  forgotten a leading tab for a shell command). Some-
        times you are well aware of silly things you have  done
        and  would  like PMake to stop bothering you. This flag
        tells it to shut up about anything non-fatal.
   --XX   This flag causes PMake to not  attempt  to  export  any
        jobs to another machine.
   Several  flags  may  follow  a  single `-'. Those flags that
   require arguments take them from successive parameters. E.g.











   PSD:12-18                                PMake -- A Tutorial


        ppmmaakkee --ffDDnnII sseerrvveerr..mmkk DDEEBBUUGG //cchhiipp22//XX//sseerrvveerr//iinncclluuddee

   will  cause  PMake  to read sseerrvveerr..mmkk as the input makefile,
   define the variable DDEEBBUUGG as a global variable and look  for
   included makefiles in the directory //cchhiipp22//XX//sseerrvveerr//iinncclluuddee.

   22..88..  SSuummmmaarryy
   A makefile is made of four types of lines:
        +o Dependency lines
        +o Creation commands
        +o Variable assignments
        +o Comments, include statements and  conditional  direc-
          tives
   A dependency line is a list of one or more targets, an oper-
   ator (`::', `::::', or  `!!'),  and  a  list  of  zero  or  more
   sources.  Sources  may  contain  wildcards and certain local
   variables.
   A creation command is a regular shell command preceded by  a
   tab.  In addition, if the first two characters after the tab
   (and other whitespace) are a  combination  of  `@@'  or  `--',
   PMake will cause the command to not be printed (if the char-
   acter is `@@') or errors from it to be ignored (if  `--').   A
   blank  line,  dependency  line or variable assignment termi-
   nates a creation script. There  may  be  only  one  creation
   script for each target with a `::' or `!!'  operator.
   Variables are places to store text. They may be uncondition-
   ally assigned-to using the `==' operator,  appended-to  using
   the  `++=='  operator, conditionally (if the variable is unde-
   fined) assigned-to with the `??==' operator,  and  assigned-to
   with  variable  expansion with the `::==' operator. The output
   of a shell command may be assigned to a variable  using  the
   `!!=='  operator.   Variables  may  be  expanded  (their value
   inserted) by enclosing their name in  parentheses  or  curly
   braces,  prceeded  by  a  dollar sign.  A dollar sign may be
   escaped with another dollar sign. Variables are not expanded
   if  PMake  doesn't  know  about  them. There are seven local
   variables:  ..TTAARRGGEETT,  ..AALLLLSSRRCC,  ..OOOODDAATTEE,  ..PPRREEFFIIXX,  ..IIMMPPSSRRCC,
   ..AARRCCHHIIVVEE,  and  ..MMEEMMBBEERR.   Four  of  them (..TTAARRGGEETT, ..PPRREEFFIIXX,
   ..AARRCCHHIIVVEE, and ..MMEEMMBBEERR) may  be  used  to  specify  ``dynamic
   sources.''   Variables  are good. Know them. Love them. Live
   them.
   Debugging of makefiles is best accomplished using the --nn, --dd
   mm, and --pp 22 flags.

   22..99..  EExxeerrcciisseess
                               TTBBAA

   33..  SShhoorrtt--ccuuttss aanndd OOtthheerr NNiiccee TThhiinnggss
   Based  on what I've told you so far, you may have gotten the
   impression that PMake is just a way of storing away commands
   and making sure you don't forget to compile something. Good.
   That's just what it is.  However, the  ways  I've  described
   have  been  inelegant, at best, and painful, at worst.  This
   chapter contains things that make the writing  of  makefiles









   PMake -- A Tutorial                                PSD:12-19


   easier  and  the  makefiles themselves shorter and easier to
   modify (and, occasionally,  simpler).  In  this  chapter,  I
   assume  you are somewhat more familiar with Sprite (or UNIX,
   if that's what you're using) than I did in chapter  2,  just
   so you're on your toes.  So without further ado...

   33..11..  TTrraannssffoorrmmaattiioonn RRuulleess
   As  you  know,  a  file's name consists of two parts: a base
   name, which gives some hint as to the contents of the  file,
   and  a  suffix,  which  usually  indicates the format of the
   file.  Over the years, as UNIX(R) has developed, naming con-
   ventions,  with regard to suffixes, have also developed that
   have become almost as incontrovertible as Law. E.g.  a  file
   ending in ..cc is assumed to contain C source code; one with a
   ..oo suffix is assumed to be a  compiled,  relocatable  object
   file  that may be linked into any program; a file with a ..mmss
   suffix is usually a text file to be processed by Troff  with
   the  -ms  macro package, and so on.  One of the best aspects
   of both Make and PMake comes from their understanding of how
   the  suffix  of  a  file  pertains to its contents and their
   ability to do things with a file based soley on its  suffix.
   This  ability comes from something known as a transformation
   rule. A transformation rule specifies how to change  a  file
   with one suffix into a file with another suffix.
   A  transformation  rule  looks  much like a dependency line,
   except the target  is  made  of  two  known  suffixes  stuck
   together.  Suffixes  are made known to PMake by placing them
   as sources on a dependency line whose target is the  special
   target ..SSUUFFFFIIXXEESS.  E.g.

        ..SSUUFFFFIIXXEESS       :: ..oo ..cc
        ..cc..oo            ::
                $$((CCCC)) $$((CCFFLLAAGGSS)) --cc $$((..IIMMPPSSRRCC))

   The creation script attached to the target is used to trans-
   form a file with the first suffix (in this case, ..cc) into  a
   file  with  the  second suffix (here, ..oo).  In addition, the
   target inherits whatever attributes have been applied to the
   transformation  rule.  The simple rule given above says that
   to transform a C source file into an object file,  you  com-
   pile  it  using  cccc  with  the  --cc flag.  This rule is taken
   straight from the system makefile. Many transformation rules
   (and  suffixes) are defined there, and I refer you to it for
   more examples (type ``ppmmaakkee --hh'' to find out where it is).
   There are several things to note  about  the  transformation
   rule given above:
        1)   The ..IIMMPPSSRRCC variable.  This variable is set to the
             ``implied source'' (the file from which the target
             is  being created; the one with the first suffix),
             which, in this case, is the .c file.
        2)   The CCFFLLAAGGSS variable. Almost all of the transforma-
             tion rules in the system makefile are set up using
             variables that you can alter in your  makefile  to
             tailor  the  rule  to your needs. In this case, if









   PSD:12-20                                PMake -- A Tutorial


             you want all your C files to be compiled with  the
             --gg flag, to provide information for ddbbxx, you would
             set the CCFFLLAAGGSS variable to contain --gg (``CCFFLLAAGGSS  ==
             --gg'') and PMake would take care of the rest.
   To  give you a quick example, the makefile in 2.3.4 could be
   changed to this:

        OOBBJJSS            == aa..oo bb..oo cc..oo
        pprrooggrraamm         :: $$((OOBBJJSS))
                $$((CCCC)) --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
        $$((OOBBJJSS))         :: ddeeffss..hh

   The transformation rule I gave above takes the place of  the
   6 lines1

        aa..oo             :: aa..cc
                cccc --cc aa..cc
        bb..oo             :: bb..cc
                cccc --cc bb..cc
        cc..oo             :: cc..cc
                cccc --cc cc..cc

   Now you may be wondering about the dependency between the ..oo
   and ..cc files -- it's not mentioned anywhere in the new make-
   file. This is because it isn't needed: one of the effects of
   applying a transformation rule is the target comes to depend
   on the implied source. That's why it's  called  the  implied
   _s_o_u_r_c_e.
   For  a  more  detailed example. Say you have a makefile like
   this:

        aa..oouutt           :: aa..oo bb..oo
                $$((CCCC)) $$((..AALLLLSSRRCC))

   and a directory set up like this:

        ttoottaall 44
        --rrww--rrww--rr----  11 ddeebboooorr         3344 SSeepp  77 0000::4433 MMaakkeeffiillee
        --rrww--rrww--rr----  11 ddeebboooorr        111199 OOcctt  33 1199::3399 aa..cc
        --rrww--rrww--rr----  11 ddeebboooorr        220011 SSeepp  77 0000::4433 aa..oo
        --rrww--rrww--rr----  11 ddeebboooorr         6699 SSeepp  77 0000::4433 bb..cc

   While just typing ``ppmmaakkee'' will do the  right  thing,  it's
   much  more  informative  to  type ``ppmmaakkee --dd ss''.  This will
   show you what PMake is up to as it processes the  files.  In
   this case, PMake prints the following:





   -----------
     1 This  is  also somewhat cleaner, I think, than
   the dynamic source solution presented in 2.6









   PMake -- A Tutorial                                PSD:12-21


        SSuuffff__FFiinnddDDeeppss ((aa..oouutt))
             uussiinngg eexxiissttiinngg ssoouurrccee aa..oo
             aappppllyyiinngg ..oo -->> ..oouutt ttoo ""aa..oo""
        SSuuffff__FFiinnddDDeeppss ((aa..oo))
             ttrryyiinngg aa..cc......ggoott iitt
             aappppllyyiinngg ..cc -->> ..oo ttoo ""aa..cc""
        SSuuffff__FFiinnddDDeeppss ((bb..oo))
             ttrryyiinngg bb..cc......ggoott iitt
             aappppllyyiinngg ..cc -->> ..oo ttoo ""bb..cc""
        SSuuffff__FFiinnddDDeeppss ((aa..cc))
             ttrryyiinngg aa..yy......nnoott tthheerree
             ttrryyiinngg aa..ll......nnoott tthheerree
             ttrryyiinngg aa..cc,,vv......nnoott tthheerree
             ttrryyiinngg aa..yy,,vv......nnoott tthheerree
             ttrryyiinngg aa..ll,,vv......nnoott tthheerree
        SSuuffff__FFiinnddDDeeppss ((bb..cc))
             ttrryyiinngg bb..yy......nnoott tthheerree
             ttrryyiinngg bb..ll......nnoott tthheerree
             ttrryyiinngg bb..cc,,vv......nnoott tthheerree
             ttrryyiinngg bb..yy,,vv......nnoott tthheerree
             ttrryyiinngg bb..ll,,vv......nnoott tthheerree
        ------ aa..oo ------
        cccc  --cc aa..cc
        ------ bb..oo ------
        cccc  --cc bb..cc
        ------ aa..oouutt ------
        cccc aa..oo bb..oo

   SSuuffff__FFiinnddDDeeppss  is  the  name  of a function in PMake that is
   called to check for  implied  sources  for  a  target  using
   transformation  rules.   The  transformations  it tries are,
   naturally enough, limited to the ones that have been defined
   (a transformation may be defined multiple times, by the way,
   but only the most recent one will be used). You will notice,
   however, that there is a definite order to the suffixes that
   are tried. This order is set by the  relative  positions  of
   the  suffixes  on the ..SSUUFFFFIIXXEESS line -- the earlier a suffix
   appears, the earlier it is checked as the source of a trans-
   formation.  Once  a suffix has been defined, the only way to
   change its position in the pecking order is  to  remove  all
   the  suffixes (by having a ..SSUUFFFFIIXXEESS dependency line with no
   sources) and redefine them in the order  you  want.  (Previ-
   ously-defined  transformation  rules  will  be automatically
   redefined as the suffixes they involve are re-entered.)
   Another way to affect the search order is to make the depen-
   dency  explicit.  In the above example, aa..oouutt depends on aa..oo
   and bb..oo.  Since a transformation exists  from  ..oo  to  ..oouutt,
   PMake uses that, as indicated by the ``uussiinngg eexxiissttiinngg ssoouurrccee
   aa..oo'' message.
   The search for a transformation starts from  the  suffix  of
   the target and continues through all the defined transforma-
   tions, in the order dictated by the suffix ranking, until an
   existing  file with the same base (the target name minus the
   suffix and any leading directories) is found. At that point,









   PSD:12-22                                PMake -- A Tutorial


   one  or  more  transformation  rules will have been found to
   change the one existing file into the target.
   For example, ignoring what's in the system makefile for now,
   say you have a makefile like this:

        ..SSUUFFFFIIXXEESS       :: ..oouutt ..oo ..cc ..yy ..ll
        ..ll..cc            ::
                lleexx $$((..IIMMPPSSRRCC))
                mmvv lleexx..yyyy..cc $$((..TTAARRGGEETT))
        ..yy..cc            ::
                yyaacccc $$((..IIMMPPSSRRCC))
                mmvv yy..ttaabb..cc $$((..TTAARRGGEETT))
        ..cc..oo            ::
                cccc --cc $$((..IIMMPPSSRRCC))
        ..oo..oouutt          ::
                cccc --oo $$((..TTAARRGGEETT)) $$((..IIMMPPSSRRCC))

   and the single file jjiivvee..ll.  If you were to type ``ppmmaakkee --rrdd
   mmss jjiivvee..oouutt,''  you  would  get  the  following  output  for
   jjiivvee..oouutt:

        SSuuffff__FFiinnddDDeeppss ((jjiivvee..oouutt))
             ttrryyiinngg jjiivvee..oo......nnoott tthheerree
             ttrryyiinngg jjiivvee..cc......nnoott tthheerree
             ttrryyiinngg jjiivvee..yy......nnoott tthheerree
             ttrryyiinngg jjiivvee..ll......ggoott iitt
             aappppllyyiinngg ..ll -->> ..cc ttoo ""jjiivvee..ll""
             aappppllyyiinngg ..cc -->> ..oo ttoo ""jjiivvee..cc""
             aappppllyyiinngg ..oo -->> ..oouutt ttoo ""jjiivvee..oo""

   and this is why: PMake starts with the target jjiivvee..oouutt, fig-
   ures out its suffix (..oouutt)  and  looks  for  things  it  can
   transform to a ..oouutt file. In this case, it only finds ..oo, so
   it looks for the file jjiivvee..oo.  It fails to find  it,  so  it
   looks  for transformations into a ..oo file. Again it has only
   one choice: ..cc.  So it looks for jjiivvee..cc and,  as  you  know,
   fails  to  find it. At this point it has two choices: it can
   create the ..cc file from either a ..yy file or a ..ll file. Since
   ..yy  came  first  on the ..SSUUFFFFIIXXEESS line, it checks for jjiivvee..yy
   first, but can't find it, so it looks for jjiivvee..ll and, lo and
   behold, there it is.  At this point, it has defined a trans-
   formation path as follows: ..ll  ->  ..cc  ->  ..oo  ->  ..oouutt  and
   applies  the transformation rules accordingly. For complete-
   ness, and to give you a better idea of what  PMake  actually
   did  with this three-step transformation, this is what PMake
   printed for the rest of the process:

















   PMake -- A Tutorial                                PSD:12-23


        SSuuffff__FFiinnddDDeeppss ((jjiivvee..oo))
             uussiinngg eexxiissttiinngg ssoouurrccee jjiivvee..cc
             aappppllyyiinngg ..cc -->> ..oo ttoo ""jjiivvee..cc""
        SSuuffff__FFiinnddDDeeppss ((jjiivvee..cc))
             uussiinngg eexxiissttiinngg ssoouurrccee jjiivvee..ll
             aappppllyyiinngg ..ll -->> ..cc ttoo ""jjiivvee..ll""
        SSuuffff__FFiinnddDDeeppss ((jjiivvee..ll))
        EExxaammiinniinngg jjiivvee..ll......mmooddiiffiieedd 1177::1166::0011 OOcctt 44,, 11998877......uupp--ttoo--ddaattee
        EExxaammiinniinngg jjiivvee..cc......nnoonn--eexxiisstteenntt......oouutt--ooff--ddaattee
        ------ jjiivvee..cc ------
        lleexx jjiivvee..ll
        ...... mmeeaanniinngglleessss lleexx oouuttppuutt ddeelleetteedd ......
        mmvv lleexx..yyyy..cc jjiivvee..cc
        EExxaammiinniinngg jjiivvee..oo......nnoonn--eexxiisstteenntt......oouutt--ooff--ddaattee
        ------ jjiivvee..oo ------
        cccc --cc jjiivvee..cc
        EExxaammiinniinngg jjiivvee..oouutt......nnoonn--eexxiisstteenntt......oouutt--ooff--ddaattee
        ------ jjiivvee..oouutt ------
        cccc --oo jjiivvee..oouutt jjiivvee..oo

   One final question remains: what does PMake do with  targets
   that have no known suffix? PMake simply pretends it actually
   has a known suffix and searches for transformations  accord-
   ingly.   The  suffix  it chooses is the source for the ..NNUULLLL
   target mentioned later. In the system makefile, ..oouutt is cho-
   sen  as the ``null suffix'' because most people use PMake to
   create programs. You  are,  however,  free  and  welcome  to
   change it to a suffix of your own choosing.  The null suffix
   is ignored, however, when PMake  is  in  compatibility  mode
   (see chapter 4).

   33..22..  IInncclluuddiinngg OOtthheerr MMaakkeeffiilleess
   Just  as for programs, it is often useful to extract certain
   parts of a makefile into another file and just include it in
   other  makefiles somehow. Many compilers allow you say some-
   thing like

        ##iinncclluuddee ""ddeeffss..hh""

   to include the contents of ddeeffss..hh in the source file.  PMake
   allows  you  to  do  the  same thing for makefiles, with the
   added ability to use variables in the filenames.  An include
   directive in a makefile looks either like this:

        ##iinncclluuddee <<ffiillee>>

   or this

        ##iinncclluuddee ""ffiillee""

   The  difference  between the two is where PMake searches for
   the file: the first way, PMake will look for the  file  only
   in  the  system  makefile  directory  (to find out what that
   directory is, give PMake the --hh flag).  For files in double-









   PSD:12-24                                PMake -- A Tutorial


   quotes, the search is more complex:
        1)   The directory of the makefile that's including the
             file.
        2)   The  current  directory  (the  one  in  which  you
             invoked PMake).
        3)   The  directories  given  by you using --II flags, in
             the order in which you gave them.
        4)   Directories given by ..PPAATTHH dependency  lines  (see
             chapter 4).
        5)   The system makefile directory.
   in that order.
   You  are  free to use PMake variables in the filename--PMake
   will expand them before searching for  the  file.  You  must
   specify  the  searching method with either angle brackets or
   double-quotes _o_u_t_s_i_d_e of a variable expansion. I.e. the fol-
   lowing

        SSYYSSTTEEMM    == <<ccoommmmaanndd..mmkk>>

        ##iinncclluuddee $$((SSYYSSTTEEMM))

   won't work.

   33..33..  SSaavviinngg CCoommmmaannddss
   There  may  come  a  time when you will want to save certain
   commands to be executed when everything else  is  done.  For
   instance:  you're  making several different libraries at one
   time and you want to create the members in parallel. Problem
   is,  rraannlliibb  is  another one of those programs that can't be
   run more than once in the same directory at  the  same  time
   (each  one  creates  a  file  called ____..SSYYMMDDEEFF into which it
   stuffs information for the linker to use. Two of  them  run-
   ning at once will overwrite each other's file and the result
   will be garbage for both parties). You might want a  way  to
   save  the ranlib commands til the end so they can be run one
   after the  other,  thus  keeping  them  from  trashing  each
   other's  file.  PMake  allows you to do this by inserting an
   ellipsis (``...'') as a command between commands to  be  run
   at once and those to be run later.
   So for the rraannlliibb case above, you might do this:

        lliibb11..aa          :: $$((LLIIBB11OOBBJJSS))
                rrmm --ff $$((..TTAARRGGEETT))
                aarr ccrr $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
                ......
                rraannlliibb $$((..TTAARRGGEETT))

        lliibb22..aa          :: $$((LLIIBB22OOBBJJSS))
                rrmm --ff $$((..TTAARRGGEETT))
                aarr ccrr $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
                ......
                rraannlliibb $$((..TTAARRGGEETT))

   This would save both









   PMake -- A Tutorial                                PSD:12-25


        rraannlliibb $$((..TTAARRGGEETT))

   commands  until  the  end, when they would run one after the
   other (using the correct value for the ..TTAARRGGEETT variable,  of
   course).
   Commands  saved  in  this  manner are only executed if PMake
   manages to re-create everything without an error.

   33..44..  TTaarrggeett AAttttrriibbuutteess
   PMake allows you to give attributes to targets by  means  of
   special  sources.  Like  everything  else  PMake uses, these
   sources begin with a period and are made up  of  all  upper-
   case  letters. There are various reasons for using them, and
   I will try to give examples for most of them. Others  you'll
   have to find uses for yourself. Think of it as ``an exercise
   for the reader.'' By placing one (or more)  of  these  as  a
   source on a dependency line, you are ``marking the target(s)
   with that attribute.'' That's just the way I phrase  it,  so
   you know.
   Any  attributes  given  as sources for a transformation rule
   are applied to the target of the  transformation  rule  when
   the rule is applied.
   .DONTCARE   If  a  target  is marked with this attribute and
               PMake can't figure out how to create it, it will
               ignore  this  fact  and  assume  the  file isn't
               really needed or actually exists and PMake  just
               can't  find  it.  This  may prove wrong, but the
               error will be noted later  on,  not  when  PMake
               tries  to  create  the  target  so  marked. This
               attribute also prevents PMake from attempting to
               touch the target if it is given the --tt flag.
   .EXEC       This  attribute  causes  its  shell script to be
               executed while having no effect on targets  that
               depend  on it. This makes the target into a sort
               of subroutine.  An example. Say  you  have  some
               LISP  files  that need to be compiled and loaded
               into a LISP process. To do this, you  echo  LISP
               commands  into  a  file  and execute a LISP with
               this file as its input when  everything's  done.
               Say  also that you have to load other files from
               another system before you can compile your files
               and  further,  that you don't want to go through
               the loading and dumping unless one of _y_o_u_r files
               has  changed.  Your makefile might look a little
               bit like this (remember, this is an  educational
               example, and don't worry about the CCOOMMPPIILLEE rule,
               all will soon become clear, grasshopper):
















   PSD:12-26                                PMake -- A Tutorial


                    ssyysstteemm          :: iinniitt aa..ffaassll bb..ffaassll cc..ffaassll
                            ffoorr ii iinn $$((..AALLLLSSRRCC));;
                            ddoo
                                    eecchhoo --nn ''((llooaadd ""'' >>>> iinnppuutt
                                    eecchhoo --nn $${{ii}} >>>> iinnppuutt
                                    eecchhoo ''""))'' >>>> iinnppuutt
                            ddoonnee
                            eecchhoo ''((dduummpp ""$$((..TTAARRGGEETT))""))'' >>>> iinnppuutt
                            lliisspp << iinnppuutt

                    aa..ffaassll          :: aa..ll iinniitt CCOOMMPPIILLEE
                    bb..ffaassll          :: bb..ll iinniitt CCOOMMPPIILLEE
                    cc..ffaassll          :: cc..ll iinniitt CCOOMMPPIILLEE
                    CCOOMMPPIILLEE         :: ..UUSSEE
                            eecchhoo ''((ccoommppiillee ""$$((..AALLLLSSRRCC))""))'' >>>> iinnppuutt
                    iinniitt            :: ..EEXXEECC
                            eecchhoo ''((llooaadd--ssyysstteemm))'' >> iinnppuutt

               ..EEXXEECC sources, don't appear in the  local  vari-
               ables  of  targets  that depend on them (nor are
               they touched if PMake is  given  the  --tt  flag).
               Note  that all the rules, not just that for ssyyss--
               tteemm, include iinniitt as a source. This  is  because
               none of the other targets can be made until iinniitt
               has been made, thus they depend on it.
   .EXPORT     This is used to mark those  targets  whose  cre-
               ation  should  be  sent to another machine if at
               all possible. This may be used by some  exporta-
               tion  schemes  if  the exportation is expensive.
               You should ask your system administrator  if  it
               is necessary.
   .EXPORTSAME Tells  the  export system that the job should be
               exported to a machine of the  same  architecture
               as  the  current  one.  Certain operations (e.g.
               running text through nnrrooffff) can be performed the
               same on any architecture (CPU and operating sys-
               tem type), while others (e.g. compiling  a  pro-
               gram  with  cccc)  must  be performed on a machine
               with the same architecture. Not all export  sys-
               tems will support this attribute.
   .IGNORE     Giving  a  target  the  ..IIGGNNOORREE attribute causes
               PMake to ignore errors from any of the  target's
               commands, as if they all had `-' before them.
   .INVISIBLE  This  allows  you  to  specify  one  target as a
               source for another without the one affecting the
               other's  local  variables.  Useful  if, say, you
               have a makefile that creates two  programs,  one
               of which is used to create the other, so it must
               exist before the other is created. You could say

                    pprroogg11           :: $$((PPRROOGG11OOBBJJSS)) pprroogg22 MMAAKKEEIINNSSTTAALLLL
                    pprroogg22           :: $$((PPRROOGG22OOBBJJSS)) ..IINNVVIISSIIBBLLEE MMAAKKEEIINNSSTTAALLLL

               where MMAAKKEEIINNSSTTAALLLL is some complex .USE rule (see









   PMake -- A Tutorial                                PSD:12-27


               below) that depends on the ..AALLLLSSRRCC variable con-
               taining the right things. Without the ..IINNVVIISSIIBBLLEE
               attribute  for  pprroogg22,  the   MMAAKKEEIINNSSTTAALLLL   rule
               couldn't be applied. This is not as useful as it
               should be, and the semantics may change (or  the
               whole  thing  go  away)  in  the not-too-distant
               future.
   .JOIN       This is another way  to  avoid  performing  some
               operations  in  parallel while permitting every-
               thing else to be done so. Specifically it forces
               the target's shell script to be executed only if
               one or more of the sources was  out-of-date.  In
               addition, the target's name, in both its ..TTAARRGGEETT
               variable and all the local variables of any tar-
               get that depends on it, is replaced by the value
               of its ..AALLLLSSRRCC variable.  As an example, suppose
               you  have a program that has four libraries that
               compile in the same directory along with, and at
               the  same  time  as, the program. You again have
               the problem with rraannlliibb that  I  mentioned  ear-
               lier, only this time it's more severe: you can't
               just put the ranlib off to  the  end  since  the
               program  will need those libraries before it can
               be re-created. You can do something like this:

                    pprrooggrraamm         :: $$((OOBBJJSS)) lliibbrraarriieess
                            cccc --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))

                    lliibbrraarriieess       :: lliibb11..aa lliibb22..aa lliibb33..aa lliibb44..aa ..JJOOIINN
                            rraannlliibb $$((..OOOODDAATTEE))

               In this case, PMake will re-create  the  $$((OOBBJJSS))
               as  necessary, along with lliibb11..aa, lliibb22..aa, lliibb33..aa
               and lliibb44..aa.  It will then execute rraannlliibb on  any
               library that was changed and set pprrooggrraamm's ..AALLLL--
               SSRRCC variable to contain what's in  $$((OOBBJJSS))  fol-
               lowed  by  ``lliibb11..aa  lliibb22..aa lliibb33..aa lliibb44..aa.''  In
               case you're wondering, it's called ..JJOOIINN because
               it  joins  together  different  threads  of  the
               ``input graph'' at the target  marked  with  the
               attribute.    Another   aspect   of   the  .JOIN
               attribute is it keeps the target from being cre-
               ated if the --tt flag was given.
   .MAKE       The  ..MMAAKKEE attribute marks its target as being a
               recursive  invocation  of  PMake.   This  forces
               PMake  to execute the script associated with the
               target (if it's out-of-date) even  if  you  gave
               the  --nn or --tt flag. By doing this, you can start
               at the top of a system and type

                    ppmmaakkee --nn

               and have it descend the directory tree (if  your
               makefiles  are  set up correctly), printing what









   PSD:12-28                                PMake -- A Tutorial


               it would have executed if  you  hadn't  included
               the --nn flag.
   .NOEXPORT   If  possible,  PMake  will attempt to export the
               creation of all targets to another machine (this
               depends on how PMake was configured). Sometimes,
               the creation is so simple, it  is  pointless  to
               send it to another machine. If you give the tar-
               get the ..NNOOEEXXPPOORRTT  attribute,  it  will  be  run
               locally,  even  if  you've  given PMake the --LL 00
               flag.
   .NOTMAIN    Normally, if you do not specify a target to make
               in any other way, PMake will take the first tar-
               get on the first dependency line of  a  makefile
               as the target to create. That target is known as
               the ``Main Target'' and is labeled  as  such  if
               you  print  the  dependencies  out  using the --pp
               flag.  Giving  a  target  this  attribute  tells
               PMake that the target is definitely _n_o_t the Main
               Target.  This allows you to place targets in  an
               included  makefile  and  have PMake create some-
               thing else by default.
   .PRECIOUS   When PMake is interrupted (you type control-C at
               the keyboard), it will attempt to clean up after
               itself by removing any half-made targets.  If  a
               target  has  the  ..PPRREECCIIOOUUSS  attribute, however,
               PMake will leave it alone.  An  additional  side
               effect  of the `::' operator is to mark the tar-
               gets as ..PPRREECCIIOOUUSS.
   .SILENT     Marking a target with this attribute  keeps  its
               commands  from  being  printed when they're exe-
               cuted, just as if they had an `@'  in  front  of
               them.
   .USE        By  giving  a target this attribute, you turn it
               into PMake's equivalent of  a  macro.  When  the
               target  is  used as a source for another target,
               the other target acquires the commands,  sources
               and  attributes (except ..UUSSEE) of the source.  If
               the target already has commands, the  ..UUSSEE  tar-
               get's  commands  are  added  to the end. If more
               than one .USE-marked source is given to  a  tar-
               get, the rules are applied sequentially.
               The  typical .USE rule (as I call them) will use
               the sources of the target to which it is applied
               (as  stored in the ..AALLLLSSRRCC variable for the tar-
               get) as its ``arguments,''  if  you  will.   For
               example,  you probably noticed that the commands
               for creating lliibb11..aa and lliibb22..aa in the example in
               section  3.3  were exactly the same. You can use
               the ..UUSSEE attribute to eliminate the  repetition,
               like so:













   PMake -- A Tutorial                                PSD:12-29


                    lliibb11..aa          :: $$((LLIIBB11OOBBJJSS)) MMAAKKEELLIIBB
                    lliibb22..aa          :: $$((LLIIBB22OOBBJJSS)) MMAAKKEELLIIBB

                    MMAAKKEELLIIBB         :: ..UUSSEE
                            rrmm --ff $$((..TTAARRGGEETT))
                            aarr ccrr $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))
                            ......
                            rraannlliibb $$((..TTAARRGGEETT))

               Several  system  makefiles  (not  to be confused
               with The System  Makefile)  make  use  of  these
               .USE  rules to make your life easier (they're in
               the default, system makefile directory...take  a
               look).   Note  that  the .USE rule source itself
               (MMAAKKEELLIIBB) does not appear in  any  of  the  tar-
               gets's  local  variables.   There is no limit to
               the number of times  I  could  use  the  MMAAKKEELLIIBB
               rule. If there were more libraries, I could con-
               tinue with ``lliibb33..aa :: $$((LLIIBB33OOBBJJSS)) MMAAKKEELLIIBB''  and
               so on and so forth.

   33..55..  SSppeecciiaall TTaarrggeettss
   As  there  were  in  Make, so there are certain targets that
   have special meaning to PMake. When you use one on a  depen-
   dency  line,  it  is  the only target that may appear on the
   left-hand-side of the operator.  As for the  attributes  and
   variables,  all  the special targets begin with a period and
   consist of upper-case letters only.  I won't  describe  them
   all  in  detail  because some of them are rather complex and
   I'll describe them in more detail than you'll want in  chap-
   ter 4.  The targets are as follows:
   .BEGIN    Any  commands attached to this target are executed
             before anything else is done. You can use  it  for
             any initialization that needs doing.
   .DEFAULT  This  is  sort of a .USE rule for any target (that
             was used only as a source) that PMake can't figure
             out any other way to create. It's only ``sort of''
             a .USE rule because only the shell script attached
             to  the ..DDEEFFAAUULLTT target is used. The ..IIMMPPSSRRCC vari-
             able of a target that inherits ..DDEEFFAAUULLTT's commands
             is set to the target's own name.
   .END      This  serves a function similar to ..BBEEGGIINN, in that
             commands attached to it are executed  once  every-
             thing  has  been  re-created (so long as no errors
             occurred). It also serves the  extra  function  of
             being a place on which PMake can hang commands you
             put off to the end. Thus the script for this  tar-
             get  will  be  executed before any of the commands
             you save with the ``...''.
   .EXPORT   The sources for this  target  are  passed  to  the
             exportation  system compiled into PMake. Some sys-
             tems will use these  sources  to  configure  them-
             selves.  You  should ask your system administrator
             about this.









   PSD:12-30                                PMake -- A Tutorial


   .IGNORE   This target marks each of  its  sources  with  the
             ..IIGGNNOORREE  attribute.  If  you  don't  give  it  any
             sources, then it is like giving the --ii  flag  when
             you  invoke  PMake  --  errors are ignored for all
             commands.
   .INCLUDES The sources for this target are taken to  be  suf-
             fixes that indicate a file that can be included in
             a program  source  file.   The  suffix  must  have
             already  been declared with ..SSUUFFFFIIXXEESS (see below).
             Any suffix so marked will have the directories  on
             its  search  path (see ..PPAATTHH, below) placed in the
             ..IINNCCLLUUDDEESS variable, each preceded by  a  --II  flag.
             This  variable can then be used as an argument for
             the compiler in the normal fashion. The ..hh  suffix
             is  already marked in this way in the system make-
             file.  E.g. if you have

                  ..SSUUFFFFIIXXEESS       :: ..bbiittmmaapp
                  ..PPAATTHH..bbiittmmaapp    :: //uussrr//llooccaall//XX//lliibb//bbiittmmaappss
                  ..IINNCCLLUUDDEESS       :: ..bbiittmmaapp

             PMake will place ``--II//uussrr//llooccaall//XX//lliibb//bbiittmmaappss'' in
             the ..IINNCCLLUUDDEESS variable and you can then say

                  cccc $$((..IINNCCLLUUDDEESS)) --cc xxpprrooggrraamm..cc

             (Note:  the  ..IINNCCLLUUDDEESS  variable  is  not actually
             filled in  until  the  entire  makefile  has  been
             read.)
   .INTERRUPT
             When  PMake  is  interrupted,  it will execute the
             commands in the script  for  this  target,  if  it
             exists.
   .LIBS     This  does  for  libraries what ..IINNCCLLUUDDEESS does for
             include files, except the  flag  used  is  --LL,  as
             required  by  those linkers that allow you to tell
             them where to find libraries. The variable used is
             ..LLIIBBSS.  Be forewarned that PMake may not have been
             compiled to do this if the linker on  your  system
             doesn't accept the --LL flag, though the ..LLIIBBSS vari-
             able will always be defined once the makefile  has
             been read.
   .MAIN     If you didn't give a target (or targets) to create
             when you invoked PMake, it will take  the  sources
             of this target as the targets to create.
   .MAKEFLAGS
             This target provides a way for you to always spec-
             ify flags for PMake when the makefile is used. The
             flags are just as they would be typed to the shell
             (except  you  can't  use  shell  variables  unless
             they're  in the environment), though the --ff and --rr
             flags have no effect.
   .NULL     This allows  you  to  specify  what  suffix  PMake
             should  pretend  a file has if, in fact, it has no









   PMake -- A Tutorial                                PSD:12-31


             known suffix. Only one suffix  may  be  so  desig-
             nated.  The  last source on the dependency line is
             the suffix that is used (you should, however, only
             give one suffix...).
   .PATH     If  you  give  sources for this target, PMake will
             take them as directories in which  to  search  for
             files  it cannot find in the current directory. If
             you give no sources, it will clear out any  direc-
             tories  added to the search path before. Since the
             effects of this all get very complex,  I'll  leave
             it  til chapter four to give you a complete expla-
             nation.
   .PATH_s_u_f_f_i_x
             This does a similar thing to ..PPAATTHH, but it does it
             only  for  files with the given suffix. The suffix
             must have been defined  already.  Look  at  SSeeaarrcchh
             PPaatthhss (section 4.1) for more information.
   .PRECIOUS Similar  to  ..IIGGNNOORREE,  this  gives  the  ..PPRREECCIIOOUUSS
             attribute to each source on the  dependency  line,
             unless  there  are  no  sources, in which case the
             ..PPRREECCIIOOUUSS attribute is given to  every  target  in
             the file.
   .RECURSIVE
             This target applies the ..MMAAKKEE attribute to all its
             sources. It does nothing if you don't give it  any
             sources.
   .SHELL    PMake  is not constrained to only using the Bourne
             shell to execute the commands you put in the make-
             file. You can tell it some other shell to use with
             this target. Check out AA SShheellll iiss  aa  SShheellll  iiss  aa
             SShheellll (section 4.4) for more information.
   .SILENT   When  you  use ..SSIILLEENNTT as a target, it applies the
             ..SSIILLEENNTT attribute to each of its sources. If there
             are  no sources on the dependency line, then it is
             as if you gave PMake the --ss flag and  no  commands
             will be echoed.
   .SUFFIXES This  is  used to give new file suffixes for PMake
             to handle. Each source is a  suffix  PMake  should
             recognize. If you give a ..SSUUFFFFIIXXEESS dependency line
             with no sources, PMake will forget about  all  the
             suffixes  it  knew  (this also nukes the null suf-
             fix).  For those targets that need  to  have  suf-
             fixes defined, this is how you do it.
   In addition to these targets, a line of the form

        _a_t_t_r_i_b_u_t_e :: _s_o_u_r_c_e_s

   applies  the _a_t_t_r_i_b_u_t_e to all the targets listed as _s_o_u_r_c_e_s.

   33..66..  MMooddiiffyyiinngg VVaarriiaabbllee EExxppaannssiioonn
   Variables  need  not  always  be  expanded  verbatim.  PMake
   defines  several  modifiers  that  may be applied to a vari-
   able's value before it is expanded. You apply a modifier  by
   placing  it after the variable name with a colon between the









   PSD:12-32                                PMake -- A Tutorial


   two, like so:

        $${{_V_A_R_I_A_B_L_E::_m_o_d_i_f_i_e_r}}

   Each modifier is a single character  followed  by  something
   specific to the modifier itself.  You may apply as many mod-
   ifiers as you want -- each one is applied to the  result  of
   the  previous  and is separated from the previous by another
   colon.
   There are seven ways to modify a variable's expansion,  most
   of which come from the C shell variable modification charac-
   ters:
        M_p_a_t_t_e_r_n
             This is used to select only those words (a word is
             a series of characters that are neither spaces nor
             tabs) that match the given _p_a_t_t_e_r_n.   The  pattern
             is a wildcard pattern like that used by the shell,
             where ** means 0 or more characters of any sort;  ??
             is any single character; [[aabbccdd]] matches any single
             character that is either  `a',  `b',  `c'  or  `d'
             (there may be any number of characters between the
             brackets); [[00--99]] matches any single character that
             is  between `0' and `9' (i.e. any digit. This form
             may be freely mixed with the other bracket  form),
             and  `\'  is  used to escape any of the characters
             `*', `?', `[' or  `:',  leaving  them  as  regular
             characters  to  match  themselves  in a word.  For
             example, the system makefile <<mmaakkeeddeeppeenndd..mmkk>>  uses
             ``$$((CCFFLLAAGGSS::MM--[[IIDD]]**))'' to extract all the --II and --DD
             flags that would be passed to the C compiler. This
             allows  it  to  properly  locate include files and
             generate the correct dependencies.
        N_p_a_t_t_e_r_n
             This is identical to ::MM except it substitutes  all
             words that don't match the given pattern.
        S/_s_e_a_r_c_h_-_s_t_r_i_n_g/_r_e_p_l_a_c_e_m_e_n_t_-_s_t_r_i_n_g/[g]
             Causes  the  first  occurrence of _s_e_a_r_c_h_-_s_t_r_i_n_g in
             the variable to be replaced by _r_e_p_l_a_c_e_m_e_n_t_-_s_t_r_i_n_g,
             unless  the  gg  flag is given at the end, in which
             case all occurences of the  string  are  replaced.
             The  substitution is performed on each word in the
             variable in turn. If _s_e_a_r_c_h_-_s_t_r_i_n_g begins  with  a
             ^^, the string must match starting at the beginning
             of the word. If _s_e_a_r_c_h_-_s_t_r_i_n_g ends with a  $$,  the
             string  must  match  to the end of the word (these
             two may be combined to force an exact match). If a
             backslash  preceeds these two characters, however,
             they lose their special meaning.  Variable  expan-
             sion also occurs in the normal fashion inside both
             the  _s_e_a_r_c_h_-_s_t_r_i_n_g  and  the   _r_e_p_l_a_c_e_m_e_n_t_-_s_t_r_i_n_g,
             eexxcceepptt  that  a  backslash  is used to prevent the
             expansion of a $$, not another dollar sign,  as  is
             usual.   Note that _s_e_a_r_c_h_-_s_t_r_i_n_g is just a string,
             not a pattern,  so  none  of  the  usual  regular-









   PMake -- A Tutorial                                PSD:12-33


             expression/wildcard  characters  have  any special
             meaning save ^^ and $$.  In the replacement  string,
             the  &&  character is replaced by the _s_e_a_r_c_h_-_s_t_r_i_n_g
             unless it is preceded by  a  backslash.   You  are
             allowed  to  use  any  character  except  colon or
             exclamation point to  separate  the  two  strings.
             This  so-called  delimiter character may be placed
             in either string by preceeding  it  with  a  back-
             slash.
        T    Replaces  each  word  in the variable expansion by
             its last component (its  ``tail'').  For  example,
             given

                  OOBBJJSS == ....//lliibb//aa..oo bb //uussrr//lliibb//lliibbmm..aa
                  TTAAIILLSS == $$((OOBBJJSS::TT))

             the   variable  TTAAIILLSS  would  expand  to  ``aa..oo  bb
             lliibbmm..aa.''
        H    This is similar to ::TT, except that every  word  is
             replaced   by   everything   but   the  tail  (the
             ``head''). Using the same definition of OOBBJJSS,  the
             string  ``$$((OOBBJJSS::HH))''  would  expand  to  ``....//lliibb
             //uussrr//lliibb.''  Note that  the  final  slash  on  the
             heads  is  removed  and anything without a head is
             replaced by the empty string.
        E    ::EE replaces each  word  by  its  suffix  (``exten-
             sion'').  So  ``$$((OOBBJJSS::EE))''  would  give  you ``..oo
             ..aa.''
        R    This replaces each word by everything but the suf-
             fix  (the  ``root''  of  the word).  ``$$((OOBBJJSS::RR))''
             expands to `` ....//lliibb//aa bb //uussrr//lliibb//lliibbmm.''
   In addition, the System V style of substitution is also sup-
   ported.  This looks like:

        $$((_V_A_R_I_A_B_L_E::_s_e_a_r_c_h_-_s_t_r_i_n_g==_r_e_p_l_a_c_e_m_e_n_t))

   It  must  be  the  last modifier in the chain. The search is
   anchored at the end of each word, so only suffixes or  whole
   words may be replaced.

   33..77..  MMoorree oonn DDeebbuuggggiinngg

   33..88..  MMoorree EExxeerrcciisseess
   (3.1)
        You've  got  a  set  programs, each of which is created
        from its  own  assembly-language  source  file  (suffix
        ..aassmm).   Each  program  can  be assembled into two ver-
        sions, one with error-checking code  assembled  in  and
        one  without.  You  could assemble them into files with
        different suffixes (..eeoobbjj and ..oobbjj, for instance),  but
        your  linker  only  understands files that end in ..oobbjj.
        To top it all off, the final executables _m_u_s_t have  the
        suffix  ..eexxee.   How  can  you  still use transformation
        rules to make your life easier (Hint: assume the error-









   PSD:12-34                                PMake -- A Tutorial


        checking versions have eecc tacked onto their prefix)?
   (3.2)
        Assume, for a moment or two, you want to perform a sort
        of ``indirection'' by placing the name  of  a  variable
        into another one, then you want to get the value of the
        first by expanding the second  somehow.  Unfortunately,
        PMake doesn't allow constructs like

             $$(($$((FFOOOO))))

        What  do you do? Hint: no further variable expansion is
        performed after modifiers  are  applied,  thus  if  you
        cause  a  $ to occur in the expansion, that's what will
        be in the result.

   44..  PPMMaakkee ffoorr GGooddss
   This chapter is devoted to those facilities  in  PMake  that
   allow  you to do a great deal in a makefile with very little
   work, as well as do some things  you  couldn't  do  in  Make
   without  a  great deal of work (and perhaps the use of other
   programs). The problem with these features, is they must  be
   handled with care, or you will end up with a mess.
   Once  more,  I  assume  a  greater  familiarity with UNIX or
   Sprite than I did in the previous two chapters.

   44..11..  SSeeaarrcchh PPaatthhss
   PMake supports the dispersal of files into multiple directo-
   ries  by  allowing you to specify places to look for sources
   with ..PPAATTHH targets in the makefile. The directories you give
   as sources for these targets make up a ``search path.'' Only
   those files used exclusively as sources are actually  sought
   on  a search path, the assumption being that anything listed
   as a target in the makefile can be created by  the  makefile
   and thus should be in the current directory.
   There  are  two  types of search paths in PMake: one is used
   for all types of files (including included makefiles) and is
   specified with a plain ..PPAATTHH target (e.g.  ``..PPAATTHH :: RRCCSS''),
   while the other is specific to a certain type  of  file,  as
   indicated  by  the  file's suffix. A specific search path is
   indicated by immediately following the ..PPAATTHH with the suffix
   of the file. For instance

        ..PPAATTHH..hh         :: //sspprriittee//lliibb//iinncclluuddee //sspprriittee//aatttt//lliibb//iinncclluuddee

   would    tell    PMake    to   look   in   the   directories
   //sspprriittee//lliibb//iinncclluuddee  and  //sspprriittee//aatttt//lliibb//iinncclluuddee  for   any
   files whose suffix is ..hh.
   The  current directory is always consulted first to see if a
   file exists. Only if it cannot be found there are the direc-
   tories in the specific search path, followed by those in the
   general search path, consulted.
   A search path is also used when expanding  wildcard  charac-
   ters.  If  the  pattern has a recognizable suffix on it, the
   path for  that  suffix  will  be  used  for  the  expansion.









   PMake -- A Tutorial                                PSD:12-35


   Otherwise the default search path is employed.
   When  a  file is found in some directory other than the cur-
   rent one, all local variables that would have contained  the
   target's  name  (..AALLLLSSRRCC,  and ..IIMMPPSSRRCC) will instead contain
   the path to the file, as found by PMake.  Thus if you have a
   file ....//lliibb//mmuummbbllee..cc and a makefile

        ..PPAATTHH..cc         :: ....//lliibb
        mmuummbbllee          :: mmuummbbllee..cc
                $$((CCCC)) --oo $$((..TTAARRGGEETT)) $$((..AALLLLSSRRCC))

   the  command executed to create mmuummbbllee would be ``cccc --oo mmuumm--
   bbllee ....//lliibb//mmuummbbllee..cc.''  (As an aside, the  command  in  this
   case  isn't strictly necessary, since it will be found using
   transformation rules if it isn't given. This is because ..oouutt
   is  the  null  suffix by default and a transformation exists
   from ..cc to ..oouutt.  Just thought I'd throw that in.)
   If a file exists in two directories on the same search path,
   the  file in the first directory on the path will be the one
   PMake uses. So if you have a large system spread  over  many
   directories, it would behoove you to follow a naming conven-
   tion that avoids such conflicts.
   Something you should know about the  way  search  paths  are
   implemented is that each directory is read, and its contents
   cached, exactly once -- when it is first encountered  --  so
   any  changes  to the directories while PMake is running will
   not be noted when searching for implicit sources,  nor  will
   they  be found when PMake attempts to discover when the file
   was last modified, unless the file was created in  the  cur-
   rent  directory.  While  people  have  suggested  that PMake
   should read the directories each time,  my  experience  sug-
   gests  that the caching seldom causes problems. In addition,
   not caching the directories  slows  things  down  enormously
   because  of  PMake's  attempts to apply transformation rules
   through non-existent files --  the  number  of  extra  file-
   system  searches  is  truly  staggering,  especially if many
   files without suffixes are used and the  null  suffix  isn't
   changed from ..oouutt.

   44..22..  AArrcchhiivveess aanndd LLiibbrraarriieess
   UNIX  and  Sprite  allow  you to merge files into an archive
   using the aarr command. Further, if the files are  relocatable
   object  files,  you  can  run  rraannlliibb on the archive and get
   yourself a library that you can link into  any  program  you
   want.  The  main  problem  with  archives is they double the
   space you need to store the archived  files,  since  there's
   one  copy  in  the  archive  and one copy out by itself. The
   problem with libraries is you usually think of them  as  --llmm
   rather  than  //uussrr//lliibb//lliibbmm..aa  and the linker thinks they're
   out-of-date if you so much as look at them.
   PMake solves the problem with archives by  allowing  you  to
   tell  it  to  examine  the files in the archives (so you can
   remove the individual files  without  having  to  regenerate
   them  later).  To  handle  the problem with libraries, PMake









   PSD:12-36                                PMake -- A Tutorial


   adds an additional way of deciding if a library  is  out-of-
   date:
   +o If  the table of contents is older than the library, or is
     missing, the library is out-of-date.
   A library is any target that looks like ``--llname''  or  that
   ends  in  a  suffix  that  was marked as a library using the
   ..LLIIBBSS target.  ..aa is so marked in the system makefile.
   Members of an archive  are  specified  as  ``_a_r_c_h_i_v_e(_m_e_m_b_e_r[
   _m_e_m_b_e_r...])''.   Thus  ``'lliibbddiixx..aa((wwiinnddooww..oo))'' specifies the
   file wwiinnddooww..oo in the archive lliibbddiixx..aa.   You  may  also  use
   wildcards to specify the members of the archive. Just remem-
   ber that most the wildcard characters will only find  _e_x_i_s_t_-
   _i_n_g files.
   A  file that is a member of an archive is treated specially.
   If the file doesn't exist, but it is  in  the  archive,  the
   modification  time  recorded  in the archive is used for the
   file when determining if the file is out-of-date. When  fig-
   uring  out  how  to  make an archived member target (not the
   file  itself,  but  the  file  in   the   archive   --   the
   _a_r_c_h_i_v_e(_m_e_m_b_e_r)  target),  special  care  is  taken with the
   transformation rules, as follows:
   +o _a_r_c_h_i_v_e(_m_e_m_b_e_r) is made to depend on _m_e_m_b_e_r.
   +o The  transformation  from  the  _m_e_m_b_e_r's  suffix  to   the
     _a_r_c_h_i_v_e's suffix is applied to the _a_r_c_h_i_v_e(_m_e_m_b_e_r) target.
   +o The _a_r_c_h_i_v_e(_m_e_m_b_e_r)'s ..TTAARRGGEETT variable is set to the  name
     of  the _m_e_m_b_e_r if _m_e_m_b_e_r is actually a target, or the path
     to the member file if _m_e_m_b_e_r is only a source.
   +o The ..AARRCCHHIIVVEE variable for the  _a_r_c_h_i_v_e(_m_e_m_b_e_r)  target  is
     set to the name of the _a_r_c_h_i_v_e.
   +o The  ..MMEEMMBBEERR  variable  is set to the actual string inside
     the parentheses. In most cases, this will be the  same  as
     the ..TTAARRGGEETT variable.
   +o The  _a_r_c_h_i_v_e(_m_e_m_b_e_r)'s place in the local variables of the
     targets that depend on it is taken by  the  value  of  its
     ..TTAARRGGEETT variable.
   Thus,  a program library could be created with the following
   makefile:

        ..oo..aa            ::
                ......
                rrmm --ff $$((..TTAARRGGEETT::TT))
        OOBBJJSS            == oobbjj11..oo oobbjj22..oo oobbjj33..oo
        lliibbpprroogg..aa       :: lliibbpprroogg..aa(($$((OOBBJJSS))))
                aarr ccrruu $$((..TTAARRGGEETT)) $$((..OOOODDAATTEE))
                rraannlliibb $$((..TTAARRGGEETT))

   This will cause the three object files to  be  compiled  (if
   the  corresponding  source  files  were  modified  after the
   object file or, if that doesn't exist, the  archived  object
   file),  the  out-of-date ones archived in lliibbpprroogg..aa, a table
   of contents placed in the  archive  and  the  newly-archived
   object files to be removed.
   All this is used in the mmaakkeelliibb..mmkk system makefile to create
   a single library with ease. This makefile looks like this:









   PMake -- A Tutorial                                PSD:12-37


        ##
        ## RRuulleess ffoorr mmaakkiinngg lliibbrraarriieess.. TThhee oobbjjeecctt ffiilleess tthhaatt mmaakkee uupp tthhee lliibbrraarryy aarree
        ## rreemmoovveedd oonnccee tthheeyy aarree aarrcchhiivveedd..
        ##
        ## TToo mmaakkee sseevveerraall lliibbaarraarriieess iinn ppaarraalllleell,, yyoouu sshhoouulldd ddeeffiinnee tthhee vvaarriiaabbllee
        ## ""mmaannyy__lliibbrraarriieess"".. TThhiiss wwiillll sseerriiaalliizzee tthhee iinnvvooccaattiioonnss ooff rraannlliibb..
        ##
        ## TToo uussee,, ddoo ssoommeetthhiinngg lliikkee tthhiiss::
        ##
        ## OOBBJJEECCTTSS == <<ffiilleess iinn tthhee lliibbrraarryy>>
        ##
        ## ffiisshh..aa:: ffiisshh..aa(($$((OOBBJJEECCTTSS)))) MMAAKKEELLIIBB
        ##
        ##

        ##iiffnnddeeff __MMAAKKEELLIIBB__MMKK
        __MMAAKKEELLIIBB__MMKK    ==

        ##iinncclluuddee  <<ppoo..mmkk>>

        ..ppoo..aa ..oo..aa     ::
             ......
             rrmm --ff $$((..MMEEMMBBEERR))

        AARRFFLLAAGGSS        ??== ccrrll

        ##
        ## RRee--aarrcchhiivvee tthhee oouutt--ooff--ddaattee mmeemmbbeerrss aanndd rreeccrreeaattee tthhee lliibbrraarryy''ss ttaabbllee ooff
        ## ccoonntteennttss uussiinngg rraannlliibb.. IIff mmaannyy__lliibbrraarriieess iiss ddeeffiinneedd,, ppuutt tthhee rraannlliibb ooffff
        ## ttiill tthhee eenndd ssoo mmaannyy lliibbrraarriieess ccaann bbee mmaaddee aatt oonnccee..
        ##
        MMAAKKEELLIIBB        :: ..UUSSEE ..PPRREECCIIOOUUSS
             aarr $$((AARRFFLLAAGGSS)) $$((..TTAARRGGEETT)) $$((..OOOODDAATTEE))
        ##iiffnnddeeff nnoo__rraannlliibb
        ## iiffddeeff mmaannyy__lliibbrraarriieess
             ......
        ## eennddiiff mmaannyy__lliibbrraarriieess
             rraannlliibb $$((..TTAARRGGEETT))
        ##eennddiiff nnoo__rraannlliibb

        ##eennddiiff __MMAAKKEELLIIBB__MMKK


   44..33..  OOnn tthhee CCoonnddiittiioonn......
   Like the C compiler before it, PMake allows you to configure
   the makefile, based on the current environment, using condi-
   tional statements. A conditional looks like this:
















   PSD:12-38                                PMake -- A Tutorial


        ##iiff _b_o_o_l_e_a_n _e_x_p_r_e_s_s_i_o_n
        _l_i_n_e_s
        ##eelliiff _a_n_o_t_h_e_r _b_o_o_l_e_a_n _e_x_p_r_e_s_s_i_o_n
        _m_o_r_e _l_i_n_e_s
        ##eellssee
        _s_t_i_l_l _m_o_r_e _l_i_n_e_s
        ##eennddiiff

   They may be nested to a maximum depth of 30  and  may  occur
   anywhere  (except  in  a comment, of course). The ``##'' must
   the very first character on the line.
   Each _b_o_o_l_e_a_n _e_x_p_r_e_s_s_i_o_n is made up of terms that  look  like
   function calls, the standard C boolean operators &&&&, ||||, and
   !!, and the standard relational operators ====, !!==, >>,  >>==,  <<,
   and <<==, with ==== and !!== being overloaded to allow string com-
   parisons as well.  &&&& represents logical AND; |||| is  logical
   OR  and !!  is logical NOT.  The arithmetic and string opera-
   tors take precedence over  all  three  of  these  operators,
   while  NOT takes precedence over AND, which takes precedence
   over OR.  This precedence may be overridden  with  parenthe-
   ses,  and an expression may be parenthesized to your heart's
   content.  Each term looks like a call on one of  four  func-
   tions:
   make     The syntax is mmaakkee((_t_a_r_g_e_t)) where _t_a_r_g_e_t is a target
            in the makefile. This is true if the  given  target
            was specified on the command line, or as the source
            for a ..MMAAIINN target (note that the sources for ..MMAAIINN
            are  only used if no targets were given on the com-
            mand line).
   defined  The syntax is  ddeeffiinneedd((_v_a_r_i_a_b_l_e))  and  is  true  if
            _v_a_r_i_a_b_l_e  is defined. Certain variables are defined
            in the system makefile that identify the system  on
            which PMake is being run.
   exists   The  syntax is eexxiissttss((_f_i_l_e)) and is true if the file
            can be found on the global search path (i.e.   that
            defined  by  ..PPAATTHH targets, not by ..PPAATTHH_s_u_f_f_i_x tar-
            gets).
   empty    This syntax is much like  the  others,  except  the
            string  inside  the parentheses is of the same form
            as you would put between parentheses when expanding
            a variable, complete with modifiers and everything.
            The function returns true if the  resulting  string
            is  empty (NOTE: an undefined variable in this con-
            text will cause at the very least a warning message
            about  a  malformed  conditional,  and at the worst
            will cause the process to stop once it has read the
            makefile. If you want to check for a variable being
            defined    or    empty,    use    the    expression
            ``!!ddeeffiinneedd((_v_a_r))  ||||  eemmppttyy((_v_a_r))'' as the definition
            of |||| will prevent the eemmppttyy(()) from being evaluated
            and  causing  an  error,  if  the variable is unde-
            fined). This can be used to see if a variable  con-
            tains a given word, for example:










   PMake -- A Tutorial                                PSD:12-39


                 ##iiff !!eemmppttyy((_v_a_r::MM_w_o_r_d))

   The arithmetic and string operators may only be used to test
   the value of a variable. The lefthand side must contain  the
   variable expansion, while the righthand side contains either
   a string, enclosed in double-quotes, or a number. The  stan-
   dard  C  numeric conventions (except for specifying an octal
   number) apply to both sides. E.g.

        ##iiff $$((OOSS)) ==== 44..33

        ##iiff $$((MMAACCHHIINNEE)) ==== ""ssuunn33""

        ##iiff $$((LLOOAADD__AADDDDRR)) << 00xxcc000000

   are all valid conditionals. In addition, the  numeric  value
   of a variable can be tested as a boolean as follows:

        ##iiff $$((LLOOAADD))

   would see if LLOOAADD contains a non-zero value and

        ##iiff !!$$((LLOOAADD))

   would test if LLOOAADD contains a zero value.
   In  addition to the bare ``##iiff,'' there are other forms that
   apply one of the first two functions to each term. They  are
   as follows:

             iiffddeeff     defined
             iiffnnddeeff    !defined
             iiffmmaakkee    make
             iiffnnmmaakkee   !make

   There  are also the ``else if'' forms: eelliiff, eelliiffddeeff, eelliiffnn--
   ddeeff, eelliiffmmaakkee, and eelliiffnnmmaakkee.
   For instance, if you wish to create two versions of  a  pro-
   gram, one of which is optimized (the production version) and
   the other of which is for debugging (has symbols  for  dbx),
   you  have  two choices: you can create two makefiles, one of
   which uses the --gg flag for the compilation, while the  other
   uses  the  --OO  flag,  or you can use another target (call it
   ddeebbuugg) to create the debug version. The construct below will
   take  care  of this for you. I have also made it so defining
   the variable DDEEBBUUGG (say with ppmmaakkee --DD DDEEBBUUGG) will also cause
   the debug version to be made.

        ##iiff ddeeffiinneedd((DDEEBBUUGG)) |||| mmaakkee((ddeebbuugg))
        CCFFLLAAGGSS         ++== --gg
        ##eellssee
        CCFFLLAAGGSS         ++== --OO
        ##eennddiiff

   There  are, of course, problems with this approach. The most









   PSD:12-40                                PMake -- A Tutorial


   glaring annoyance is that if you want to go  from  making  a
   debug  version  to  making a production version, you have to
   remove all the object files, or you will get some  optimized
   and  some debug versions in the same program. Another annoy-
   ance is you have to be careful not to make two targets  that
   ``conflict''  because  of some conditionals in the makefile.
   For instance

        ##iiff mmaakkee((pprriinntt))
        FFOORRMMAATTTTEERR == ddiittrrooffff --PPllaasseerr__pprriinntteerr
        ##eennddiiff
        ##iiff mmaakkee((ddrraafftt))
        FFOORRMMAATTTTEERR == nnrrooffff --PPddoott__mmaattrriixx__pprriinntteerr
        ##eennddiiff

   would wreak havok if you tried ``ppmmaakkee ddrraafftt  pprriinntt''  since
   you would use the same formatter for each target. As I said,
   this all gets somewhat complicated.

   44..44..  AA SShheellll iiss aa SShheellll iiss aa SShheellll
   In normal operation,  the  Bourne  Shell  (better  known  as
   ``sshh'')  is  used  to execute the commands to re-create tar-
   gets. PMake also allows you to specify a different shell for
   it  to  use when executing these commands. There are several
   things PMake must know about the  shell  you  wish  to  use.
   These  things  are  specified  as the sources for the ..SSHHEELLLL
   target by keyword, as follows:
   ppaatthh==_p_a_t_h
        PMake needs to know where the shell  actually  resides,
        so  it  can execute it. If you specify this and nothing
        else, PMake will use the last component of the path and
        look  in  its  table of the shells it knows and use the
        specification it finds, if any. Use this  if  you  just
        want  to  use  a  different  version of the Bourne or C
        Shell (yes, PMake knows how to use the C Shell too).
   nnaammee==_n_a_m_e
        This is the name by which the shell is to be known.  It
        is  a  single word and, if no other keywords are speci-
        fied (other than ppaatthh), it is the name by  which  PMake
        attempts  to  find a specification for it (as mentioned
        above). You can use this if you would just  rather  use
        the C Shell than the Bourne Shell (``..SSHHEELLLL:: nnaammee==ccsshh''
        will do it).
   qquuiieett==_e_c_h_o_-_o_f_f _c_o_m_m_a_n_d
        As mentioned before, PMake  actually  controls  whether
        commands  are  printed by introducing commands into the
        shell's input stream. This keyword, and the  next  two,
        control  what  those commands are. The qquuiieett keyword is
        the command used to turn echoing off. Once it is turned
        off,  echoing is expected to remain off until the echo-
        on command is given.
   eecchhoo==_e_c_h_o_-_o_n _c_o_m_m_a_n_d
        The command PMake should give to turn echoing  back  on
        again.









   PMake -- A Tutorial                                PSD:12-41


   ffiilltteerr==_p_r_i_n_t_e_d _e_c_h_o_-_o_f_f _c_o_m_m_a_n_d
        Many  shells  will echo the echo-off command when it is
        given. This keyword tells  PMake  in  what  format  the
        shell  actually  prints  the echo-off command. Wherever
        PMake sees this string in the shell's output,  it  will
        delete  it  and  any  following  whitespace,  up to and
        including the next newline. See the example at the  end
        of this section for more details.
   eecchhooFFllaagg==_f_l_a_g _t_o _t_u_r_n _e_c_h_o_i_n_g _o_n
        Unless a target has been marked ..SSIILLEENNTT, PMake wants to
        start the shell running with echoing on. To do this, it
        passes  this flag to the shell as one of its arguments.
        If either this or the next flag begins with a `-',  the
        flags  will  be  passed  to the shell as separate argu-
        ments. Otherwise, the two will be concatenated (if they
        are used at the same time, of course).
   eerrrrFFllaagg==_f_l_a_g _t_o _t_u_r_n _e_r_r_o_r _c_h_e_c_k_i_n_g _o_n
        Likewise,  unless  a  target  is  marked ..IIGGNNOORREE, PMake
        wishes error-checking to be on from the very start.  To
        this  end,  it  will  pass this flag to the shell as an
        argument. The same rules for an initial  `-'  apply  as
        for the eecchhooFFllaagg.
   cchheecckk==_c_o_m_m_a_n_d _t_o _t_u_r_n _e_r_r_o_r _c_h_e_c_k_i_n_g _o_n
        Just  as for echo-control, error-control is achieved by
        inserting commands into the shell's input stream.  This
        is  the  command to make the shell check for errors. It
        also serves another purpose if the shell  doesn't  have
        error-control  as commands, but I'll get into that in a
        minute. Again, once error checking has been turned  on,
        it  is  expected  to  remain  on until it is turned off
        again.
   iiggnnoorree==_c_o_m_m_a_n_d _t_o _t_u_r_n _e_r_r_o_r _c_h_e_c_k_i_n_g _o_f_f
        This is the command PMake uses to turn  error  checking
        off.  It has another use if the shell doesn't do error-
        control, but I'll tell you about that...now.
   hhaassEErrrrCCttll==_y_e_s _o_r _n_o
        This takes a value that is either yyeess or nnoo.   Now  you
        might  think that the existence of the cchheecckk and iiggnnoorree
        keywords would be enough to tell PMake if the shell can
        do  error-control,  but you'd be wrong. If hhaassEErrrrCCttll is
        yyeess, PMake uses the check  and  ignore  commands  in  a
        straight-forward manner.  If this is nnoo, however, their
        use is rather different. In this case, the  check  com-
        mand  is  used as a template, in which the string %%ss is
        replaced by the command that's about to be executed, to
        produce a command for the shell that will echo the com-
        mand to be executed. The ignore command is also used as
        a template, again with %%ss replaced by the command to be
        executed, to produce a command that  will  execute  the
        command to be executed and ignore any error it returns.
        When these strings are used as templates, you must pro-
        vide newline(s) (``\\nn'') in the appropriate place(s).
   The  strings  that  follow these keywords may be enclosed in
   single or double quotes (the quotes will  be  stripped  off)









   PSD:12-42                                PMake -- A Tutorial


   and may contain the usual C backslash-characters (\n is new-
   line, \r is return, \b is backspace, \'  escapes  a  single-
   quote inside single-quotes, \" escapes a double-quote inside
   double-quotes). Now for an example.
   This is actually the contents of the <<sshhxx..mmkk>>  system  make-
   file, and causes PMake to use the Bourne Shell in such a way
   that each command is printed as it is executed. That is,  if
   more  than  one  command  is  given  on a line, each will be
   printed separately.  Similarly, each time the body of a loop
   is  executed, the commands within that loop will be printed,
   etc. The specification runs like this:

        ##
        ## TThhiiss iiss aa sshheellll ssppeecciiffiiccaattiioonn ttoo hhaavvee tthhee bboouurrnnee sshheellll eecchhoo
        ## tthhee ccoommmmaannddss jjuusstt bbeeffoorree eexxeeccuuttiinngg tthheemm,, rraatthheerr tthhaann wwhheenn iitt rreeaaddss
        ## tthheemm.. UUsseeffuull iiff yyoouu wwaanntt ttoo sseeee hhooww vvaarriiaabblleess aarree bbeeiinngg eexxppaannddeedd,, eettcc..
        ##
        ..SSHHEELLLL    :: ppaatthh==//bbiinn//sshh \\
             qquuiieett==""sseett --"" \\
             eecchhoo==""sseett --xx"" \\
             ffiilltteerr==""++ sseett -- "" \\
             eecchhooFFllaagg==xx \\
             eerrrrFFllaagg==ee \\
             hhaassEErrrrCCttll==yyeess \\
             cchheecckk==""sseett --ee"" \\
             iiggnnoorree==""sseett ++ee""

   It tells PMake the following:
   +o The shell is located in the file  //bbiinn//sshh.   It  need  not
     tell  PMake  that the name of the shell is sshh as PMake can
     figure that out for itself (it's the last component of the
     path).
   +o The command to stop echoing is sseett --.
   +o The command to start echoing is sseett --xx.
   +o When  the  echo  off  command  is executed, the shell will
     print ++ sseett -- (The  `+'  comes  from  using  the  --xx  flag
     (rather  than the --vv flag PMake usually uses)). PMake will
     remove all occurences of this string from the  output,  so
     you don't notice extra commands you didn't put there.
   +o The  flag  the  Bourne Shell will take to start echoing in
     this way is the --xx flag. The Bourne Shell will  only  take
     its  flag arguments concatenated as its first argument, so
     neither this nor the eerrrrFFllaagg specification begins  with  a
     -.
   +o The  flag  to use to turn error-checking on from the start
     is --ee.
   +o The shell can turn error-checking on and off, and the com-
     mands to do so are sseett ++ee and sseett --ee, respectively.
   I  should  note that this specification is for Bourne Shells
   that are not part of Berkeley UNIX, as shells from  Berkeley
   don't  do  error control. You can get a similar effect, how-
   ever, by changing the last three lines to be:











   PMake -- A Tutorial                                PSD:12-43


             hhaassEErrrrCCttll==nnoo \\
             cchheecckk==""eecchhoo \\""++ %%ss\\""\\nn"" \\
             iiggnnoorree==""sshh --cc ''%%ss |||| eexxiitt 00\\nn""

   This will cause PMake to execute the two commands

        eecchhoo ""++ _c_m_d""
        sshh --cc ''_c_m_d |||| ttrruuee''

   for each command for which errors are  to  be  ignored.  (In
   case you are wondering, the thing for iiggnnoorree tells the shell
   to execute another  shell  without  error  checking  on  and
   always exit 0, since the |||| causes the eexxiitt 00 to be executed
   only if the first command exited non-zero, and if the  first
   command  exited  zero,  the shell will also exit zero, since
   that's the last command it executed).

   44..55..  CCoommppaattiibbiilliittyy
   There  are  three  (well,  3  1/2)  levels   of   backwards-
   compatibility  built  into  PMake.  Most makefiles will need
   none at all. Some may need a little bit of work  to  operate
   correctly  when  run in parallel. Each level encompasses the
   previous levels (e.g.  --BB (one shell  per  command)  implies
   --VV)  The  three  levels are described in the following three
   sections.

   44..55..11..  DDEEFFCCOONN 33 ---- VVaarriiaabbllee EExxppaannssiioonn
   As noted before, PMake will not expand a variable unless  it
   knows  of  a value for it. This can cause problems for make-
   files that expect to leave  variables  undefined  except  in
   special  circumstances (e.g. if more flags need to be passed
   to the C compiler or the output from a text processor should
   be  sent  to  a  different  printer).  If  the variables are
   enclosed in curly braces (``$${{PPRRIINNTTEERR}}''),  the  shell  will
   let them pass. If they are enclosed in parentheses, however,
   the shell will declare a syntax error and the make will come
   to a grinding halt.
   You  have  two  choices:  change  the makefile to define the
   variables (their values can be  overridden  on  the  command
   line,  since  that's  where  they would have been set if you
   used Make, anyway) or always give the --VV flag (this  can  be
   done with the ..MMAAKKEEFFLLAAGGSS target, if you want).

   44..55..22..  DDEEFFCCOONN 22 ---- TThhee NNuummbbeerr ooff tthhee BBeeaasstt
   Then  there  are the makefiles that expect certain commands,
   such as changing to a different  directory,  to  not  affect
   other  commands in a target's creation script. You can solve
   this is either by going back to executing one shell per com-
   mand  (which  is what the --BB flag forces PMake to do), which
   slows the process down a good bit and requires  you  to  use
   semicolons  and escaped newlines for shell constructs, or by
   changing the makefile to execute the offending command(s) in
   a  subshell  (by  placing the line inside parentheses), like
   so:









   PSD:12-44                                PMake -- A Tutorial


        iinnssttaallll :::: ..MMAAKKEE
             ((ccdd ssrrcc;; $$((..PPMMAAKKEE)) iinnssttaallll))
             ((ccdd lliibb;; $$((..PPMMAAKKEE)) iinnssttaallll))
             ((ccdd mmaann;; $$((..PPMMAAKKEE)) iinnssttaallll))

   This will always execute the three makes  (even  if  the  --nn
   flag  was  given)  because  of the combination of the ``::''
   operator and the ..MMAAKKEE attribute. Each command  will  change
   to  the proper directory to perform the install, leaving the
   main shell in the directory in which it started.

   44..55..33..  DDEEFFCCOONN 11 ---- IImmiittaattiioonn iiss tthhee NNoott tthhee HHiigghheesstt FFoorrmm ooff
   FFllaatttteerryy
   The final category of makefile is the one where  every  com-
   mand requires input, the dependencies are incompletely spec-
   ified, or you simply cannot create more than one target at a
   time,  as  mentioned  earlier. In addition, you may not have
   the time or desire to upgrade the makefile to  run  smoothly
   with  PMake.  If  you are the conservative sort, this is the
   compatibility mode for you. It is entered either  by  giving
   PMake  the  --MM  flag  (for  Make),  or by executing PMake as
   ``mmaakkee.''  In either case,  PMake  performs  things  exactly
   like  Make (while still supporting most of the nice new fea-
   tures PMake provides). This includes:
   +o No parallel execution.
   +o Targets are made in the exact order specified by the make-
     file. The sources for each target are made in strict left-
     to-right order, etc.
   +o A single Bourne shell is used  to  execute  each  command,
     thus the shell's $$$$ variable is useless, changing directo-
     ries doesn't work across command lines, etc.
   +o If no special characters exist in a  command  line,  PMake
     will  break  the command into words itself and execute the
     command directly, without executing  a  shell  first.  The
     characters  that cause PMake to execute a shell are: ##, ==,
     ||, ^^, ((, )), {{, }}, ;;, &&, <<, >>, **, ??, [[, ]], ::, $$, ``, and  \\.
     You  should  notice that these are all the characters that
     are given special meaning by the shell (except ''  and    ,,
     which PMake deals with all by its lonesome).
   +o The use of the null suffix is turned off.

   44..66..  TThhee WWaayy TThhiinnggss WWoorrkk
   When PMake reads the makefile, it parses sources and targets
   into nodes in a graph. The graph is  directed  only  in  the
   sense  that  PMake knows which way is up. Each node contains
   not only links to all its parents and  children  (the  nodes
   that  depend  on  it  and those on which it depends, respec-
   tively), but also a count of the number of its children that
   have already been processed.
   The  most  important thing to know about how PMake uses this
   graph is that the traversal is breadth-first and  occurs  in
   two passes.
   After  PMake  has  parsed  the  makefile, it begins with the
   nodes the user has told it to make (either  on  the  command









   PMake -- A Tutorial                                PSD:12-45


   line,  or  via  a  ..MMAAIINN  target, or by the target being the
   first in the file not labeled with the  ..NNOOTTMMAAIINN  attribute)
   placed  in  a  queue.  It continues to take the node off the
   front of the queue, mark it as something that  needs  to  be
   made,  pass the node to SSuuffff__FFiinnddDDeeppss (mentioned earlier) to
   find any implicit sources for the node, and  place  all  the
   node's children that have yet to be marked at the end of the
   queue. If any of the children is a ..UUSSEE rule, its attributes
   are applied to the parent, then its commands are appended to
   the parent's list of commands and its children are linked to
   its  parent.  The  parent's  unmade children counter is then
   decremented (since the ..UUSSEE node has  been  processed).  You
   will note that this allows a ..UUSSEE node to have children that
   are ..UUSSEE nodes and the rules will be  applied  in  sequence.
   If  the  node  has  no  children, it is placed at the end of
   another queue to be examined in the second pass.  This  pro-
   cess continues until the first queue is empty.
   At this point, all the leaves of the graph are in the exami-
   nation queue. PMake removes the node  at  the  head  of  the
   queue  and sees if it is out-of-date. If it is, it is passed
   to a function that will execute the commands  for  the  node
   asynchronously.  When  the  commands have completed, all the
   node's parents have their  unmade  children  counter  decre-
   mented and, if the counter is then 0, they are placed on the
   examination queue. Likewise, if the node is up-to-date. Only
   those parents that were marked on the downward pass are pro-
   cessed in this way. Thus PMake traverses the graph  back  up
   to  the  nodes  the  user  instructed it to create. When the
   examination queue is empty and no shells are running to cre-
   ate a target, PMake is finished.
   Once  all  targets  have  been processed, PMake executes the
   commands attached to the ..EENNDD target, either  explicitly  or
   through  the  use of an ellipsis in a shell script. If there
   were no errors during the entire process but there are still
   some targets unmade (PMake keeps a running count of how many
   targets are left to be made), there is a cycle in the graph.
   PMake  does a depth-first traversal of the graph to find all
   the targets that weren't made and prints  them  out  one  by
   one.

   55..  AAnnsswweerrss ttoo EExxeerrcciisseess
   (3.1)
        This  is  something  of  a  trick question, for which I
        apologize. The trick comes from the UNIX definition  of
        a  suffix,  which  PMake doesn't necessarily share. You
        will have noticed that all the suffixes  used  in  this
        tutorial  (and  in UNIX in general) begin with a period
        (..mmss, ..cc, etc.). Now, PMake's idea of a suffix is  more
        like  English's:  it's  the  characters at the end of a
        word. With this in mind, one possible solution to  this
        problem goes as follows:












   PSD:12-46                                PMake -- A Tutorial


             ..SSUUFFFFIIXXEESS       :: eecc..eexxee ..eexxee eecc..oobbjj ..oobbjj ..aassmm
             eecc..oobbjjeecc..eexxee ..oobbjj..eexxee ::
                     lliinnkk --oo $$((..TTAARRGGEETT)) $$((..IIMMPPSSRRCC))
             ..aassmmeecc..oobbjj      ::
                     aassmm --oo $$((..TTAARRGGEETT)) --DDDDOO__EERRRROORR__CCHHEECCKKIINNGG $$((..IIMMPPSSRRCC))
             ..aassmm..oobbjj        ::
                     aassmm --oo $$((..TTAARRGGEETT)) $$((..IIMMPPSSRRCC))

   (3.2)
        The  trick  to  this  one  lies in the ``:='' variable-
        assignment operator and the  ``:S''  variable-expansion
        modifier.   Basically  what  you  want  is  to take the
        pointer variable, so to speak, and transform it into an
        invocation  of  the  variable  at  which it points. You
        might try something like

             $$((PPTTRR::SS//^^//\\$$((//::SS//$$//))))

        which places ``$$(('' at the front of the  variable  name
        and  ``))''  at  the end, thus transforming ``VVAARR,'' for
        example, into ``$$((VVAARR)),'' which is just what  we  want.
        Unfortunately  (as you know if you've tried it), since,
        as it says in the hint, PMake does no further substitu-
        tion  on the result of a modified expansion, that's _a_l_l
        you get. The solution is to make use of ``:='' to place
        that  string into yet another variable, then invoke the
        other variable directly:

             **PPTTRR            ::== $$((PPTTRR::SS//^^//\\$$((//::SS//$$//))//))

        You can then use ``$$((**PPTTRR))'' to your heart's content.

   66..  GGlloossssaarryy ooff JJaarrggoonn
   aattttrriibbuuttee:: A property given to a target that causes PMake to
        treat it differently.
   ccoommmmaanndd ssccrriipptt:: The lines immediately following a dependency
        line that specify commands to execute to create each of
        the  targets  on  the dependency line. Each line in the
        command script must begin with a tab.
   ccoommmmaanndd--lliinnee vvaarriiaabbllee:: A variable  defined  in  an  argument
        when  PMake  is  first executed.  Overrides all assign-
        ments to the same variable name in the makefile.
   ccoonnddiittiioonnaall:: A construct much  like  that  used  in  C  that
        allows  a makefile to be configured on the fly based on
        the local environment, or on what is being made by that
        invocation of PMake.
   ccrreeaattiioonn  ssccrriipptt::  Commands  used  to  create  a target. See
        ``command script.''
   ddeeppeennddeennccyy:: The relationship between a source and a  target.
        This comes in three flavors, as indicated by the opera-
        tor between the target and  the  source.  `:'  gives  a
        straight  time-wise  dependency (if the target is older
        than the source, the target is out-of-date), while  `!'
        provides  simply  an  ordering and always considers the









   PMake -- A Tutorial                                PSD:12-47


        target out-of-date. `::' is much like `:', save it cre-
        ates  multiple  instances  of  a  target  each of which
        depends on its own list of sources.
   ddyynnaammiicc ssoouurrccee:: This refers to a source  that  has  a  local
        variable  invocation  in  it. It allows a single depen-
        dency line to specify a different source for each  tar-
        get on the line.
   gglloobbaall  vvaarriiaabbllee::  Any variable defined in a makefile. Takes
        precedence over variables defined in  the  environment,
        but not over command-line or local variables.
   iinnppuutt ggrraapphh:: What PMake constructs from a makefile. Consists
        of nodes made of the targets in the makefile,  and  the
        links  between  them  (the dependencies). The links are
        directed (from source to target) and there may  not  be
        any cycles (loops) in the graph.
   llooccaall  vvaarriiaabbllee:: A variable defined by PMake visible only in
        a target's shell script.  There are seven  local  vari-
        ables,  not  all of which are defined for every target:
        ..TTAARRGGEETT, ..AALLLLSSRRCC, ..OOOODDAATTEE, ..PPRREEFFIIXX, ..IIMMPPSSRRCC,  ..AARRCCHHIIVVEE,
        and  ..MMEEMMBBEERR.   ..TTAARRGGEETT, ..PPRREEFFIIXX, ..AARRCCHHIIVVEE, and ..MMEEMMBBEERR
        may be used on dependency  lines  to  create  ``dynamic
        sources.''
   mmaakkeeffiillee::  A  file  that describes how a system is built. If
        you  don't  know  what  it  is   after   reading   this
        tutorial....
   mmooddiiffiieerr::  A  letter, following a colon, used to alter how a
        variable is expanded.  It has no effect on the variable
        itself.
   ooppeerraattoorr:: What separates a source from a target (on a depen-
        dency line) and specifies the relationship between  the
        two. There are three: `::', `::::', and `!!'.
   sseeaarrcchh ppaatthh:: A list of directories in which a file should be
        sought. PMake's view of the contents of directories  in
        a  search  path  does  not change once the makefile has
        been read. A file is sought on a search path only if it
        is exclusively a source.
   sshheellll::  A  program  to which commands are passed in order to
        create targets.
   ssoouurrccee:: Anything to the right of an operator on a dependency
        line.  Targets  on the dependency line are usually cre-
        ated from the sources.
   ssppeecciiaall ttaarrggeett:: A target that causes  PMake  to  do  special
        things when it's encountered.
   ssuuffffiixx::  The  tail end of a file name. Usually begins with a
        period, ..cc or ..mmss, e.g.
   ttaarrggeett:: A word to the left of the operator on  a  dependency
        line. More generally, any file that PMake might create.
        A file may be (and often is) both a target and a source
        (what  it  is  depends on how PMake is looking at it at
        the time -- sort of like the wave/particle  duality  of
        light, you know).
   ttrraannssffoorrmmaattiioonn  rruullee:: A special construct in a makefile that
        specifies how to create a file of one type from a  file
        of another, as indicated by their suffixes.









   PSD:12-48                                PMake -- A Tutorial


   vvaarriiaabbllee eexxppaannssiioonn:: The process of substituting the value of
        a variable for a reference  to  it.  Expansion  may  be
        altered by means of modifiers.
   vvaarriiaabbllee::  A  place  in  which  to  store  text  that may be
        retrieved later. Also used to define the local environ-
        ment.  Conditionals  exist that test whether a variable
        is defined or not.
























































   PMake -- A Tutorial                                PSD:12-49


                           TTaabbllee ooff CCoonntteennttss


        1.    Introduction  . . . . . . . . . . . . . . . .   1
        2.    The Basics of PMake . . . . . . . . . . . . .   2
        2.1.  Dependency Lines  . . . . . . . . . . . . . .   2
        2.2.  Shell Commands  . . . . . . . . . . . . . . .   4
        2.3.  Variables . . . . . . . . . . . . . . . . . .   6
        2.3.1.Local Variables . . . . . . . . . . . . . . .   8
        2.3.2.Command-line Variables  . . . . . . . . . . .   9
        2.3.3.Global Variables  . . . . . . . . . . . . . .   9
        2.3.4.Environment Variables . . . . . . . . . . . .  10
        2.4.  Comments  . . . . . . . . . . . . . . . . . .  10
        2.5.  Parallelism . . . . . . . . . . . . . . . . .  10
        2.6.  Writing and Debugging a Makefile  . . . . . .  11
        2.7.  Invoking PMake  . . . . . . . . . . . . . . .  14
        2.8.  Summary . . . . . . . . . . . . . . . . . . .  18
        2.9.  Exercises . . . . . . . . . . . . . . . . . .  18
        3.    Short-cuts and Other Nice Things  . . . . . .  18
        3.1.  Transformation Rules  . . . . . . . . . . . .  19
        3.2.  Including Other Makefiles . . . . . . . . . .  23
        3.3.  Saving Commands . . . . . . . . . . . . . . .  24
        3.4.  Target Attributes . . . . . . . . . . . . . .  25
        3.5.  Special Targets . . . . . . . . . . . . . . .  29
        3.6.  Modifying Variable Expansion  . . . . . . . .  31
        3.7.  More on Debugging . . . . . . . . . . . . . .  33
        3.8.  More Exercises  . . . . . . . . . . . . . . .  33
        4.    PMake for Gods  . . . . . . . . . . . . . . .  34
        4.1.  Search Paths  . . . . . . . . . . . . . . . .  34
        4.2.  Archives and Libraries  . . . . . . . . . . .  35
        4.3.  On the Condition...   . . . . . . . . . . . .  37
        4.4.  A Shell is a Shell is a Shell . . . . . . . .  40
        4.5.  Compatibility . . . . . . . . . . . . . . . .  43
        4.5.1.DEFCON 3 -- Variable Expansion  . . . . . . .  43
        4.5.2.DEFCON 2 -- The Number of the Beast . . . . .  43
        4.5.3.DEFCON 1 -- Imitation is the Not the Highest
        Form of Flattery  . . . . . . . . . . . . . . . . .  44
        4.6.  The Way Things Work . . . . . . . . . . . . .  44
        5.    Answers to Exercises  . . . . . . . . . . . .  45
        6.    Glossary of Jargon  . . . . . . . . . . . . .  46




















