








                       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

                           _R_e_v_i_s_i_o_n_s _b_y
                         _A_n_d_r_e_a_s _S_t_o_l_c_k_e
             International Computer Science Institute
                  1947 Center Street, Suite 600
                        Berkeley, CA 94704
                    stolcke@icsi.berkeley.edu






   23 February 2002


















   -----------
      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, Adam de Boor,  the  International  Com-
   puter  Science Institute, and Andreas Stolcke make
   no representations about the suitability  of  this
   software  for any purpose.  It is provided "as is"
   without express or implied warranty.















                       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

                           _R_e_v_i_s_i_o_n_s _b_y
                         _A_n_d_r_e_a_s _S_t_o_l_c_k_e
             International Computer Science Institute
                  1947 Center Street, Suite 600
                        Berkeley, CA 94704
                    stolcke@icsi.berkeley.edu



   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:
   _N_o_t_e
   -----------
      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, Adam de Boor,  the  International  Com-
   puter  Science Institute, and Andreas Stolcke make
   no representations about the suitability  of  this
   software  for any purpose.  It is provided "as is"
   without express or implied warranty.









                                -2-


   This tutorial is divided into  three  main  sections  corre-
   sponding to basic, intermediate and advanced PMake usage. If
   you 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  contains
   possible  solutions to the problems presented throughout the
   tutorial, and chapter 6 has definitions  for  the  jargon  I
   use.
   _O_L_D _T_h_e _t_u_t_o_r_i_a_l _y_o_u _a_r_e _r_e_a_d_i_n_g _h_a_s _b_e_e_n _u_p_d_a_t_e_d _t_o _r_e_f_l_e_c_t
   _t_h_e _c_h_a_n_g_e_s _m_a_d_e _t_o _P_M_a_k_e _a_t _I_C_S_I _o_v_e_r  _r_e_c_e_n_t  _y_e_a_r_s_.   _T_h_e
   _c_h_a_n_g_e_s  _f_a_l_l _i_n_t_o _f_o_u_r _b_r_o_a_d _c_a_t_e_g_o_r_i_e_s_: _1_) _r_e_m_o_v_a_l _o_f _g_r_a_-
   _t_u_i_t_o_u_s  _i_n_c_o_m_p_a_t_i_b_i_l_i_t_i_e_s  _w_i_t_h  _o_t_h_e_r  _M_a_k_e  _v_e_r_s_i_o_n_s_,  _2_)
   _e_n_h_a_n_c_e_m_e_n_t_s  _(_o_f_t_e_n _b_o_r_r_o_w_e_d _f_r_o_m _o_t_h_e_r _M_a_k_e_s_)_, _3_) _f_e_a_t_u_r_e_s
   _p_r_e_v_i_o_u_s_l_y _p_r_e_s_e_n_t _b_u_t _u_n_d_o_c_u_m_e_n_t_e_d_,  _a_n_d  _4_)  _o_u_t_r_i_g_h_t  _b_u_g
   _f_i_x_e_s_.   _T_o _h_e_l_p _h_i_g_h_l_i_g_h_t _t_h_e _d_i_f_f_e_r_e_n_c_e_s _o_b_s_o_l_e_t_e _t_e_x_t _h_a_s
   _b_e_e_n _r_e_t_a_i_n_e_d _a_n_d _f_l_a_g_g_e_d _w_i_t_h _t_h_e _"_O_L_D_" _s_i_g_n _y_o_u _s_e_e  _h_e_r_e_.
   _N_E_W  _N_e_w  _a_n_d  _u_p_d_a_t_e_d  _f_e_a_t_u_r_e_s _a_r_e _s_i_m_i_l_a_r_l_y _m_a_r_k_e_d _w_i_t_h _a
   _"_N_E_W_" _s_i_g_n_, _a_n_d _i_m_p_o_r_t_a_n_t _c_h_a_n_g_e_s _a_r_e  _a_d_d_i_t_i_o_n_a_l_l_y  _t_y_p_e_s_e_t
   _i_n _i_t_a_l_i_c _f_o_n_t_.  _-_-_A_._S_.


   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











                                -3-


   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:

   :    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:










                                -4-


        +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.
   _N_o_t_e

   The order of the dependency lines in the makefile is  impor-
   tant:  the  first target on the first dependency line in the
   makefile 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.
   _N_E_W CCoommppaattiibbiilliittyy:: _H_o_w_e_v_e_r_, _t_a_r_g_e_t_s _s_t_a_r_t_i_n_g _w_i_t_h  _a  _p_e_r_i_o_d
   _a_n_d  _n_o_t  _c_o_n_t_a_i_n_i_n_g _`_`_/_'_' _a_r_e _n_o_t _u_s_e_d _a_s _d_e_f_a_u_l_t _m_a_i_n _t_a_r_-
   _g_e_t_s_.  _T_h_i_s _s_e_e_m_s _t_o _b_e _w_h_a_t _o_t_h_e_r _M_a_k_e_s _d_o_, _a_n_d  _a_l_s_o  _p_r_e_-
   _v_e_n_t_s  _m_i_s_c_e_l_l_a_n_e_o_u_s  _p_s_e_u_d_o_-_t_a_r_g_e_t_s  _(_s_p_e_c_i_f_i_c  _t_o _P_M_a_k_e _o_r
   _o_t_h_e_r _M_a_k_e_s_) _f_r_o_m _b_e_i_n_g _m_i_s_t_a_k_e_n _a_s _n_o_r_m_a_l _t_a_r_g_e_t_s_.

   Both targets and sources may contain  the  standard  C-Shell
   wildcard  characters  ({{,  }},  **, ??, [[, and ]]), but the non-









                                -5-


   curly-brace ones may only appear in the final component (the
   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.
   _N_o_t_e










                                -6-


   If  the  double-colon was used, each dependency line for the
   target may be followed by a shell script. That  script  will
   only  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:

        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.
   _N_E_W CCoommppaattiibbiilliittyy:: _T_h_e _`_@_' _a_n_d _`_-_'  _c_h_a_r_a_t_e_r_s  _m_a_y  _a_c_t_u_a_l_l_y
   _o_c_c_u_r  _i_n_t_e_r_s_p_e_r_s_e_d _w_i_t_h _w_h_i_t_e _s_p_a_c_e_, _a_n_d _i_n_i_t_i_a_l _w_h_i_t_e_s_p_a_c_e
   _i_s _r_e_m_o_v_e_d _f_r_o_m _t_h_e _s_h_e_l_l _c_o_m_m_a_n_d _l_i_n_e_.

   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.









                                -7-


   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.
   _N_o_t_e

   Because all the commands are given to a single shell to exe-
   cute,  such  things  as  setting  shell  variables, changing
   directories, etc., last beyond the command in which they are
   found.  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....
   _N_o_t_e

   A target's shell script is fed to  the  shell  on  its  (the
   shell'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.
   _N_E_W NNoottee:: _W_h_e_n _e_x_p_o_r_t_i_n_g  _c_o_m_m_a_n_d_s  _t_o  _o_t_h_e_r  _m_a_c_h_i_n_e_s  _t_h_e
   //ddeevv//ttttyy  _t_r_i_c_k  _w_o_n_'_t  _w_o_r_k_, _o_f _c_o_u_r_s_e_.  _S_u_c_h _t_a_r_g_e_t _s_h_o_u_l_d
   _t_h_e_r_e_f_o_r_e _a_l_s_o _b_e _m_a_r_k_e_d _w_i_t_h ..NNOOEEXXPPOORRTT_.


   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.









                                -8-


   Variables 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


   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

   _O_L_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).
   _N_E_W FFiixxeedd:: _A_n_y _a_m_o_u_n_t _o_f _o_u_t_p_u_t _c_a_n _n_o_w _b_e _r_e_a_d  _b_y  _t_h_e  !!==
   _a_s_s_i_g_n_m_e_n_t  _o_p_e_r_a_t_o_r_,  _s_u_b_j_e_c_t  _o_n_l_y  _t_o _m_e_m_o_r_y _l_i_m_i_t_a_t_i_o_n_s_.
   _A_l_s_o_, _n_o_t_e _t_h_a_t _t_h_e _c_o_m_m_a_n_d _f_o_l_l_o_w_i_n_g !!== _i_s _e_x_e_c_u_t_e_d _b_y  _t_h_e
   _p_r_e_v_a_i_l_i_n_g _s_h_e_l_l_, _a_s _s_p_e_c_i_f_i_e_d _b_y _t_h_e ..SSHHEELLLL _t_a_r_g_e_t_.









                                -9-


   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.
   _O_L_D

   Unlike Make, PMake will not  expand  a  variable  unless  it
   knows  the  variable  exists.  E.g.  if you have a $${{ii}} in a
   shell 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).
   _N_E_W

   CCoommppaattiibbiilliittyy::   _S_i_n_c_e   _n_o_n_-_s_t_a_n_d_a_r_d   _v_a_r_i_a_b_l_e   _e_x_p_a_n_s_i_o_n
   _a_c_c_o_u_n_t_e_d  _f_o_r _t_h_e _v_a_s_t _m_a_j_o_r_i_t_y _o_f _p_r_o_b_l_e_m_s _w_i_t_h _p_r_e_-_e_x_i_s_t_-
   _i_n_g _m_a_k_e_f_i_l_e_s_, _i_t _i_s _n_o_w _d_i_s_a_b_l_e_d _b_y _d_e_f_a_u_l_t_, _a_s  _i_f  _s_p_e_c_i_-
   _f_i_e_d  _b_y --VV_.  _T_o _r_e_-_e_n_a_b_l_e _t_h_e _o_r_i_g_i_n_a_l _P_M_a_k_e _s_t_y_l_e _o_f _v_a_r_i_-
   _a_b_l_e _e_x_p_a_n_s_i_o_n_, _u_s_e _t_h_e --CC _f_l_a_g_.

   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
   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):











                               -10-


        +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.
   _N_E_W  As  in  other  Makes, the --ee flag switches the order in
   which global variables and environment are searched.   (This
   is a compatibility feature that was not documented.)

   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
             _O_L_D The target without its suffix and without  any
             leading  path.  E.g. for the target ....//....//lliibb//ccoomm--
             ppaatt//ffssRReeaadd..cc, this variable would contain  ffssRReeaadd.
             _N_E_W CCoommppaattiibbiilliittyy:: _S_t_r_i_p_p_i_n_g _o_f _d_i_r_e_c_t_o_r_y _p_a_t_h_s _i_n
             _._P_R_E_F_I_X _i_s _a_n_n_o_y_i_n_g_l_y _d_i_f_f_e_r_e_n_t _f_r_o_m _o_t_h_e_r  _m_o_d_e_r_n
             _M_a_k_e_s_.   _D_i_r_e_c_t_o_r_y  _p_a_t_h_s  _a_r_e _t_h_e_r_e_f_o_r_e _r_e_t_a_i_n_e_d_,
             _i_n_c_l_u_d_i_n_g  _t_h_o_s_e  _a_d_d_e_d  _a_s  _t_h_e  _r_e_s_u_l_t  _o_f  _p_a_t_h
             _s_e_a_r_c_h_e_s_.   _T_h_e  _f_i_l_e_n_a_m_e  _p_o_r_t_i_o_n  _o_f _a_n _e_x_p_a_n_d_e_d
             _._P_R_E_F_I_X _c_a_n _e_a_s_i_l_y _b_e  _o_b_t_a_i_n_e_d  _b_y  _a_p_p_l_y_i_n_g  _t_h_e
             _`_:_T_' _m_o_d_i_f_i_e_r_.

   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.









                               -11-


   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.
   _N_E_W  _D_u_e  _t_o  _t_h_e _a_b_o_v_e _c_h_a_n_g_e_, _t_h_i_s _d_e_p_e_n_d_e_n_c_y _w_o_u_l_d _l_o_c_a_t_e
   _t_h_e _s_o_u_r_c_e _f_i_l_e_s _i_n _t_h_e _s_a_m_e _d_i_r_e_c_t_o_r_y _a_s _t_h_e _o_b_j_e_c_t  _f_i_l_e_s_.
   _I_f  $$((OOBBJJSS)) _i_n_c_l_u_d_e_s _d_i_r_e_c_t_o_r_i_e_s _p_a_t_h _a_n_d _t_h_e _s_o_u_r_c_e_s _a_r_e _t_o
   _b_e _l_o_c_a_t_e_d _e_l_s_e_w_h_e_r_e_, _u_s_e

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

   instead.
   _N_E_W

   The seven dynamic variables are also known under their  tra-
   ditional names found in other Makes.  If makefiles are meant
   be compatible the  following  one-character  variable  names
   should be used instead:

        @@    ..TTAARRGGEETT
        ??    ..OOOODDAATTEE
        >>    ..AALLLLSSRRCC
        **    ..PPRREEFFIIXX
        <<    ..IIMMPPSSRRCC
        !!    ..AARRCCHHIIVVEE
        %%    ..MMEEMMBBEERR

   These were always present by undocumented.

   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









                               -12-


   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.

   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









                               -13-


   command 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
   _N_o_t_e

   PMake was specifically designed to re-create several targets
   at once, when possible. You do not have to do anything  spe-
   cial 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
   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









                               -14-


   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









                               -15-


   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:











                               -16-


        _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.

   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-diffi-
   cult task of making sure the darn  thing  works.  Your  most
   helpful tool to make sure the makefile is at least syntacti-
   cally 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.











                               -17-


   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
   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:











                               -18-


        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.

        q    Job queue maintenance.

        r    Remote execution.

        s    The application  of  suffix-transformation  rules.
             (See chapter 3)

        t    The maintenance of the list of targets.

        v    Variable assignment.

        *    All  of the above, resulting in massive amounts of
             output (`*' may need to be quoted in the shell).

        Of these all, the mm and ss letters will be  most  useful
        to you.

   --ee   Causes global variable values defined in the UNIX envi-
        ronment to take precedence over any  assignments  found
        in the makefile.
        _N_E_W  _T_h_i_s _f_l_a_g _w_a_s _p_r_e_v_i_o_u_s_l_y _p_r_e_s_e_n_t _b_u_t _u_n_d_o_c_u_m_e_n_t_e_d_.

   --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.










                               -19-


   --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_E_W  _W_h_e_n  _r_u_n_n_i_n_g  _a_s  _s_u_p_e_r_-_u_s_e_r_, _P_M_a_k_e _w_i_l_l _c_o_n_t_i_n_u_e
        _i_n_s_p_i_t_e _o_f _a _f_a_i_l_u_r_e _t_o _c_r_e_a_t_e _t_h_e _l_o_c_k _f_i_l_e_, _i_s_s_u_i_n_g _a
        _w_a_r_n_i_n_g  _t_o _t_h_a_t _e_f_f_e_c_t_.  _F_r_e_q_u_e_n_t_l_y _t_h_e _r_o_o_t _u_s_e_r _c_a_n_-
        _n_o_t _c_r_e_a_t_e _f_i_l_e_s _i_n _s_o_u_r_c_e  _t_r_e_e_s  _m_o_u_n_t_e_d  _f_r_o_m  _o_t_h_e_r
        _s_y_s_t_e_m_s_,  _e_v_e_n  _i_f  _a_l_l _t_h_a_t_'_s _w_a_n_t_e_d _i_s _a _s_i_m_p_l_e _`_m_a_k_e
        _i_n_s_t_a_l_l_._'

   --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
        find it informative in some bizarre circumstances.

   --qq   If you give PMake this flag, it will not try to re-cre-
        ate 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









                               -20-


        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









                               -21-


        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

   --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.
        _N_E_W _A _n_e_g_a_t_i_v_e _a_r_g_u_m_e_n_t _t_o _t_h_i_s _f_l_a_g _l_i_m_i_t_s _t_h_e  _n_u_m_b_e_r
        _o_f  _l_o_c_a_l _j_o_b_s _(_t_o _t_h_e _a_b_s_o_l_u_t_e _v_a_l_u_e_, _o_f _c_o_u_r_s_e_) _w_h_i_l_e
        _a_l_s_o _f_o_r_c_i_n_g _a_l_l _l_o_c_a_l _j_o_b_s _s_l_o_t_s _t_o _b_e  _f_i_l_l_e_d  _b_e_f_o_r_e
        _e_x_p_o_r_t_a_t_i_o_n  _c_a_n _b_e_g_i_n_.  _T_h_i_s _i_s _u_s_e_f_u_l _t_o _f_o_r_c_e _u_s_e _o_f
        _o_n_e_'_s _o_w_n _m_a_c_h_i_n_e _i_n _c_a_s_e_s _w_h_e_r_e  _i_t  _i_s  _k_n_o_w_n  _t_o  _b_e
        _f_a_s_t_e_r _t_h_a_n _o_t_h_e_r_s_.

   --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-par-
        allel. 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.
        _N_E_W _W_h_e_n _e_x_p_o_r_t_i_n_g _c_o_m_m_a_n_d_s  _u_s_i_n_g  _p_i_p_e_d  _o_u_t_p_u_t_,  _t_h_e









                               -22-


        _i_d_e_n_t_i_f_i_c_a_t_i_o_n  _l_i_n_e_s  _a_l_s_o  _c_o_n_t_a_i_n  _t_h_e  _n_a_m_e  _o_f _t_h_e
        _r_e_m_o_t_e _h_o_s_t _e_x_e_c_u_t_i_n_g _t_h_e _c_o_m_m_a_n_d_.
        _N_E_W

   --RR _w_h_e_n
        Standard Make rechecks the date on a target  after  its
        recreation  the see whether it actually changed, avoid-
        ing recreating dependent targets if not.  PMake  cannot
        use  use  this strategy for targets created by exported
        commands since network filesystems are  typically  slow
        in  propagating  modification  times.   The  value _w_h_e_n
        determines how  to  handle  this  problem:  ``a''  will
        always  recheck file dates, ``l'' only for locally cre-
        ated  targets  (the  default),  and  ``n(ever)''  never
        rechecks, always assuming an update occurred.

   --SS   This  overrides  a previous --kk flag and instructs PMake
        to abort as soon  as  a  target  creation  command  has
        failed.
        _N_E_W  _T_h_i_s _f_l_a_g _w_a_s _p_r_e_v_i_o_u_s_l_y _p_r_e_s_e_n_t _b_u_t _u_n_d_o_c_u_m_e_n_t_e_d_.

   --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.
        _N_E_W _A_s _l_i_k_e_w_i_s_e _m_e_n_t_i_o_n_e_d  _b_e_f_o_r_e_,  _t_h_i_s  _f_l_a_g  _i_s  _n_o_w
        _t_u_r_n_e_d _o_n _b_y _d_e_f_a_u_l_t _i_n _t_h_e _s_t_a_n_d_a_r_d _c_o_n_f_i_g_u_r_a_t_i_o_n_.  _T_o
        _r_e_v_e_r_t _t_o _P_M_a_k_e_-_s_t_y_l_e _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n _u_s_e --CC_.

   --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.
        _N_E_W

   --ZZ _c Changes the character used to introduce Makefile direc-
        tives to _c, from the default ``#''.  This can  be  used
        process  to  BSD makefiles, which use ``.'', or to dis-
        able directives, by choosing some unlikely character.

   Several flags may follow a  single  `-'.  Those  flags  that
   require arguments take them from successive parameters. E.g.

        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.
   _N_E_W









                               -23-


   FFiixxeedd::  _T_h_e _o_r_i_g_i_n_a_l _v_e_r_s_i_o_n _o_f _P_M_a_k_e _i_n _f_a_c_t _d_i_d _n_o_t _h_a_n_d_l_e
   _f_l_a_g_s _i_n_t_e_r_s_p_e_r_s_e_d _w_i_t_h _v_a_r_i_a_b_l_e  _a_s_s_i_g_n_m_e_n_t_s  _a_n_d  _t_a_r_g_e_t_s_,
   _w_h_i_c_h  _w_a_s _a _m_a_j_o_r _a_n_n_o_y_a_n_c_e _a_n_d _i_n_c_o_m_p_a_t_i_b_i_l_i_t_y_, _e_s_p_e_c_i_a_l_l_y
   _i_n _r_e_c_u_r_s_i_v_e _m_a_k_e _c_o_m_m_a_n_d_s_.

   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.   (In  native  PMake  mode
   (--CC)  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.












                               -24-


   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
   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









                               -25-


   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
             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.
   _N_E_W  _A_s  _b_e_f_o_r_e_,  _t_r_a_n_s_f_o_r_m_a_t_i_o_n _r_u_l_e_s _a_r_e _n_o_t _a_p_p_l_i_e_d _i_f _a_t
   _l_e_a_s_t _o_n_e _e_x_p_l_i_c_i_t _d_e_p_e_n_d_e_n_c_y _w_i_t_h _c_r_e_a_t_i_o_n _c_o_m_m_a_n_d _i_s _s_p_e_c_-
   _i_f_i_e_d  _f_o_r  _a  _t_a_r_g_e_t_.  _H_o_w_e_v_e_r_, _P_M_a_k_e _u_s_e_d _t_o _n_o_t _o_b_e_y _t_h_i_s
   _s_t_i_p_u_l_a_t_i_o_n _i_n _t_h_e _c_a_s_e _o_f _t_h_e _e_x_p_l_i_c_i_t _n_u_l_l _c_o_m_m_a_n_d_,  _w_h_i_c_h
   _i_s _o_f_t_e_n _u_s_e_d _t_o _i_n_h_i_b_i_t _i_m_p_l_i_c_i_t _d_e_p_e_n_d_e_n_c_i_e_s_:
   -----------
     1 This  is  also somewhat cleaner, I think, than
   the dynamic source solution presented in 2.6









                               -26-


        dd..oo:: ;;


   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:

        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,









                               -27-


   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,
   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:

















                               -28-


        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:

        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









                               -29-


   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-
   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.
   _N_E_W FFiixxeedd:: _P_M_a_k_e _w_i_l_l _n_o_w _r_e_f_u_s_e _t_o _i_n_c_l_u_d_e _d_i_r_e_c_t_o_r_y _f_i_l_e_s_.
   _A_l_s_o_, --ddpp _a_l_l_o_w_s _t_r_a_c_i_n_g _o_f _f_i_l_e _i_n_c_l_u_s_i_o_n_s_.

   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










                               -30-


        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.
   _N_E_W

   CCoommppaattiibbiilliittyy:: _T_w_o _i_n_c_l_u_d_e _d_i_r_e_c_t_i_v_e_s  _f_r_e_q_u_e_n_t_l_y  _f_o_u_n_d  _i_n
   _o_t_h_e_r  _M_a_k_e_s  _a_r_e _a_l_s_o _s_u_p_p_o_r_t_e_d _(_n_o_t_e _t_h_e _m_i_s_s_i_n_g _`_`_#_'_' _a_n_d
   _q_u_o_t_e_s_)_:

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

   for simple inclusions, and

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

   for inclusions that are ignored if the ffiillee  is  not  found.
   The  effect  of --iinncclluuddee is better achieved using the native
   PMake construction

        ##iiff eexxiissttss((ffiillee))
        ##iinncclluuddee ""ffiillee""
        ##eennddiiff


   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:


















                               -31-


        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

        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).
   _N_E_W NNoottee:: _A_n _i_m_p_o_r_t_a_n_t _f_e_a_t_u_r_e _(_s_o_m_e  _m_i_g_h_t  _s_a_y  _b_u_g_)  _w_i_t_h
   _t_h_i_s _m_e_c_h_a_n_i_s_m _i_s _t_h_a_t _t_h_e _d_e_f_e_r_r_e_d _c_o_m_m_a_n_d_s _a_r_e _r_u_n _a_t _v_e_r_y
   _e_n_d _o_f _t_h_e _e_n_t_i_r_e _P_M_a_k_e _p_r_o_c_e_s_s_, _n_o_t _n_e_c_e_s_s_a_r_i_l_y _i_m_m_e_d_i_a_t_e_l_y
   _a_f_t_e_r  _t_h_e _l_a_s_t _c_r_e_a_t_i_o_n _c_o_m_m_a_n_d _f_o_r _t_h_e _t_a_r_g_e_t _i_n _q_u_e_s_t_i_o_n_.
   _T_h_i_s _m_a_k_e_s _i_t _n_e_c_e_s_s_a_r_y _t_o _e_m_b_e_d _s_u_c_h _d_e_f_e_r_r_e_d  _c_o_m_m_a_n_d_s  _i_n
   _r_e_c_u_r_s_i_v_e  _m_a_k_e _r_u_n_s _i_f _o_t_h_e_r _t_a_r_g_e_t_s _d_e_p_e_n_d _o_n _t_h_e _e_n_d _p_r_o_-
   _c_e_s_s_i_n_g _h_a_v_i_n_g _t_a_k_e_n _p_l_a_c_e _(_o_r _u_s_e _a_n  _a_l_t_e_r_n_a_t_i_v_e  _f_o_r_m_u_l_a_-
   _t_i_o_n_, _e_._g_._, _u_s_i_n_g _t_h_e ..JJOOIINN _a_t_t_r_i_b_u_t_e_)_.

   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









                               -32-


                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.
                _N_E_W

   .OPTIONAL    CCoommppaattiibbiilliittyy:: This is a synonym for  ..DDOONNTTCCAARREE
                found in 4.4BSD make.

   .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):

                     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.











                               -33-


   .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
                system  type),  while  others (e.g. compiling a
                program with cccc) must be performed on a machine
                with the same architecture. Not all export sys-
                tems will support this attribute.
                _N_E_W

   .EXPORT=_a_t_t_r_i_b_u_t_e
                Each such dependency specifies that the  target
                creation  commands  should  only be exported to
                machines having _a_t_t_r_i_b_u_t_e among  their  charac-
                teristics.   Available  attributes are entirely
                site-dependent, and their syntax depends on the
                underlying   exportation   system.    (see  the
                description for eexxppoorrtt((11))).   This  feature  is
                typically  used  to  specify  minimum  resource
                requirements for memory, disk  space,  software
                licenses,  etc.   If  the  target  marked  with
                ..EEXXPPOORRTT== attributes cannot be exported, and the
                local host does not match the attributes speci-
                fied, PMake will try to defer  the  exportation
                indefinitely   until  a  suitable  remote  host
                becomes  available  (or   until   interrupted).
                Whether  deferment  is possible also depends on
                the exportation system.

   .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   below)   that  depends  on  the  ..AALLLLSSRRCC









                               -34-


                variable containing 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N--
                S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 vari-
                ables of any target  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 earlier, 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LSSRRCC variable to contain what's  in  $$((OOBBJJSS))
                followed  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
                created 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










                               -35-


                and have it descend the directory tree (if your
                makefiles  are set up correctly), printing what
                it would have executed if you  hadn't  included
                the --nn flag.
                _N_E_W _T_h_i_s _a_t_t_r_i_b_u_t_e _a_l_s_o _a_f_f_e_c_t_s _q_u_e_r_y _m_o_d_e _(--qq_)
                _p_r_o_c_e_s_s_i_n_g_.  _T_o _v_e_r_i_f_y _t_h_e _u_p_t_o_d_a_t_e_-_n_e_s_s  _o_f  _a
                _r_e_c_u_r_s_i_v_e  _m_a_k_e  _t_a_r_g_e_t_, _P_M_a_k_e _i_n_v_o_k_e_s _t_h_e _c_o_m_-
                _m_a_n_d _a_n_d _c_h_e_c_k_s _f_o_r _a _z_e_r_o _r_e_t_u_r_n _s_t_a_t_u_s_.
                CCoommppaattiibbiilliittyy:: _I_n _c_o_m_p_a_t_i_b_i_l_i_t_y _(--MM_) _m_o_d_e_,  _a_l_l
                _c_o_m_m_a_n_d_s  _t_h_a_t  _e_x_p_a_n_d  _t_h_e  MMAAKKEE  _v_a_r_i_a_b_l_e _a_r_e
                _a_u_t_o_m_a_t_i_c_a_l_l_y _c_o_n_s_i_d_e_r_e_d _r_e_c_u_r_s_i_v_e _m_a_k_e _i_n_v_o_c_a_-
                _t_i_o_n_s_.

   .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 target  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 target 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 tar-
                gets  in  an  included  makefile and have PMake
                create something else by default.
                _N_E_W CCoommppaattiibbiilliittyy:: _T_a_r_g_e_t_s  _w_h_o_s_e  _n_a_m_e_s  _s_t_a_r_t
                _w_i_t_h _`_`_._'_' _a_r_e _a_l_s_o _n_o_t _c_o_n_s_i_d_e_r_e_d _m_a_i_n _t_a_r_g_e_t_s
                _(_u_n_l_e_s_s _t_h_e_y _l_o_o_k _l_i_k_e _a _p_a_t_h _n_a_m_e_, _i_._e_._,  _c_o_n_-
                _t_a_i_n _a _`_`_/_'_'_)_.

   .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,  how-
                ever,  PMake will leave it alone. An additional
                side effect of the `::' operator is to mark the
                targets as ..PPRREECCIIOOUUSS.
                _N_E_W  FFiixxeedd::  _A_c_t_u_a_l_l_y_,  _o_n_l_y  _f_i_l_e_s  _t_h_a_t  _h_a_v_e
                _c_h_a_n_g_e_d _s_i_n_c_e _P_M_a_k_e _s_t_a_r_t_e_d _a_r_e _r_e_m_o_v_e_d_, _o_t_h_e_r_-
                _w_i_s_e _w_e _m_i_g_h_t _d_e_s_t_r_o_y _p_r_e_-_e_x_i_s_t_i_n_g _w_o_r_k_.  _A_l_s_o_,
                _d_i_r_e_c_t_o_r_i_e_s  _a_r_e  _s_p_a_r_e_d_,  _s_i_n_c_e  _u_n_l_i_n_k_i_n_g   _a
                _d_i_r_e_c_t_o_r_y  _c_a_n  _l_e_a_d  _t_o _i_n_c_o_n_s_i_s_t_e_n_t _f_i_l_e _s_y_s_-
                _t_e_m_s_.
                _N_E_W











                               -36-


   .RESTART     Tells PMake to restart commands that exit  with
                a  non-zero  status, instead of aborting.  With
                this feature, PMake can be used to manage long-
                running  computations  performed by restartable
                commands.  Between  restarts  the  job  may  be
                assigned  to  different  hosts for exportation.
                Note that the effect in the  case  of  multiple
                creation  commands depends on the compatibility
                mode in effect.  In PMake  (single-shell)  mode
                the  entire  command list is restarted from the
                top; in backwards (--BB)  mode  only  the  failed
                command  is  restarted;  in  Make (--MM) mode the
                attribute has no effect.
                If an exportation system is  available  it  may
                have its own criteria for restarting jobs inde-
                pendent of ..RREESSTTAARRTT, e.g., in the event that  a
                remote jobs is evicted from its importing host.

   .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 target) as its ``arguments,'' if you  will.
                For example, you probably noticed that the com-
                mands 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:

                     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))












                               -37-


                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
                continue 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 exe-
               cuted 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 fig-
               ure  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 variable 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
               everything has been re-created (so  long  as  no
               errors occurred). It also serves the extra func-
               tion of being a place on which  PMake  can  hang
               commands you put off to the end. Thus the script
               for this target 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
               systems  will  use  these  sources  to configure
               themselves. You should ask your system  adminis-
               trator about this.
               _N_E_W  _S_p_e_c_i_a_l  _s_o_u_r_c_e  _k_e_y_w_o_r_d_s _i_n_c_l_u_d_e_: SSAAMMEE_, _t_o
               _m_a_k_e ..EEXXPPOORRTTSSAAMMEE _t_h_e _d_e_f_a_u_l_t_; _a_n_d  UUSSEELLOOCCAALL_,  _t_o
               _a_l_w_a_y_s  _c_h_e_c_k  _t_h_e  _l_o_c_a_l  _h_o_s_t _f_o_r _a_v_a_i_l_a_b_i_l_i_t_y









                               -38-


               _b_e_f_o_r_e _e_x_p_o_r_t_i_n_g _a _c_o_m_m_a_n_d _(_s_i_m_i_l_a_r _t_o  _a  _n_e_g_a_-
               _t_i_v_e --LL _o_p_t_i_o_n _v_a_l_u_e_)_.
               _O_n  _s_y_s_t_e_m_s  _t_h_a_t  _a_l_l_o_w _t_h_e _s_e_l_e_c_t_i_o_n _o_f _r_e_m_o_t_e
               _h_o_s_t_s _b_y _a_t_t_r_i_b_u_t_e_s_, _o_t_h_e_r _s_o_u_r_c_e_s  _f_o_r  ..EEXXPPOORRTT
               _a_r_e  _i_n_t_e_r_p_r_e_t_e_d  _a_s  _a_t_t_r_i_b_u_t_e_s  _t_h_a_t _s_h_o_u_l_d _b_e
               _u_s_e_d _g_l_o_b_a_l_l_y _(_s_e_e _t_h_e _d_e_s_c_r_i_p_t_i_o_n _f_o_r  ..EEXXPPOORRTT==
               _s_o_u_r_c_e_s _a_b_o_v_e_)_.
               _S_p_e_c_i_f_y_i_n_g  ..EEXXPPOORRTT  _w_i_t_h_o_u_t  _s_o_u_r_c_e_s _w_i_l_l _r_e_s_e_t
               _t_h_e _e_x_p_o_r_t_a_t_i_o_n  _s_y_s_t_e_m_s_'_s  _c_o_n_f_i_g_u_r_a_t_i_o_n  _t_o  _a
               _d_e_f_a_u_l_t  _s_t_a_t_e  _a_n_d  _d_i_s_c_a_r_d  _a_n_y  _g_l_o_b_a_l _e_x_p_o_r_t
               _a_t_t_r_i_b_u_t_e_s_.  _T_h_i_s _i_s _u_s_e_f_u_l _t_o _u_n_d_o  _t_h_e  _e_f_f_e_c_t
               _o_f _d_i_r_e_c_t_i_v_e_s _p_r_e_s_e_n_t _i_n _t_h_e _s_y_s_t_e_m _m_a_k_e_f_i_l_e_.

   .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.
               _N_E_W  FFiixxeedd::  ..IIGGNNOORREE _a_n_d --ii _n_o_w _a_l_s_o _i_g_n_o_r_e _c_o_m_-
               _m_a_n_d_s _t_h_a_t _f_a_i_l _a_s _a _r_e_s_u_l_t _o_f _b_e_i_n_g _k_i_l_l_e_d _b_y _a
               _s_i_g_n_a_l_.   _T_h_i_s  _u_s_e_d _t_o _b_e _t_r_u_e _o_n_l_y _i_n _c_o_m_p_a_t_i_-
               _b_i_l_i_t_y _m_o_d_e_.

   .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 nor-
               mal  fashion. The ..hh suffix is already marked in
               this way in the system makefile.   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.











                               -39-


   .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  variable  will always be defined once the
               makefile has been read.

   .MAIN       If you didn't give a target (or targets) to cre-
               ate  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
               specify 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  vari-
               ables 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
               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...).
               _N_E_W  _I_f  _n_o  _s_o_u_r_c_e_s _a_r_e _g_i_v_e_n_, _P_M_a_k_e _r_e_v_e_r_t_s _t_o
               _t_h_e _d_e_f_a_u_l_t _w_h_i_c_h _i_s _t_o _h_a_v_e  _n_o  _i_m_p_l_i_c_i_t  _n_u_l_l
               _s_u_f_f_i_x  _a_t _a_l_l_.  _T_h_i_s _i_s _u_s_e_f_u_l _t_o _u_n_d_o _w_h_a_t_e_v_e_r
               _i_s _d_e_f_i_n_e_d _i_n _t_h_e _s_y_s_t_e_m _m_a_k_e_f_i_l_e_.

   .ORDER      This target constrains  PMake  to  run  creation
               commands  for  certain targets sequentially in a
               specified order.  The  sources  listed  will  be
               created  in the order they are given.  Note that
               this affects only the targets listed, not  their
               child  dependencies, which may be created in any
               order unless mentioned in ..OORRDDEERR  targets  them-
               selves.  PMake will silently fail to create tar-
               gets that cannot be created  under  any  allowed
               ordering,  such  as  when  a  cyclic ordering is
               specified.
               _N_E_W _T_h_i_s _s_p_e_c_i_a_l _t_a_r_g_e_t _w_a_s  _p_r_e_v_i_o_u_s_l_y  _p_r_e_s_e_n_t
               _b_u_t _u_n_d_o_c_u_m_e_n_t_e_d_.

   .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
               directories  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 explanation.









                               -40-


   .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 makefile. 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 informa-
               tion.
               _N_E_W  ..SSHHEELLLL  _w_i_t_h _n_o _d_e_p_e_n_d_e_n_c_i_e_s _r_e_v_e_r_t_s _t_o _t_h_e
               _c_o_n_f_i_g_u_r_e_d _d_e_f_a_u_l_t _(_u_s_u_a_l_l_y _t_h_e _B_o_u_r_n_e_) _s_h_e_l_l_.

   .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  suffix).   For  those targets that need to
               have suffixes 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
   two, like so:

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










                               -41-


   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-









                               -42-


             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









                               -43-


        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-
        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.
        _N_E_W  CCoommppaattiibbiilliittyy:: _A_s _a _m_a_t_t_e_r _o_f _f_a_c_t_, _P_M_a_k_e _n_o_w _d_o_e_s
        _a_l_l_o_w _`_c_o_m_p_u_t_e_d_' _v_a_r_i_a_b_l_e _n_a_m_e_s _b_o_t_h _i_n _e_x_p_a_n_s_i_o_n_s  _a_n_d
        _a_s_s_i_g_n_m_e_n_t_s_, _j_u_s_t _a_s _o_t_h_e_r _m_o_d_e_r_n _M_a_k_e_s_.

   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.''
   _O_L_D Only those files used exclusively as sources  are  actu-
   ally sought on a search path, the assumption being that any-
   thing listed as a target in the makefile can be  created  by
   the makefile and thus should be in the current directory.
   _N_E_W  CCoommppaattiibbiilliittyy::  _T_h_i_s  _i_s  _n_o _l_o_n_g_e_r _t_r_u_e_.  _B_o_t_h _t_o _m_a_k_e
   _P_M_a_k_e _m_o_r_e _c_o_m_p_a_t_i_b_l_e _a_n_d _l_i_f_e _e_a_s_i_e_r  _w_i_t_h  _t_h_e  _M_A_K_E_O_B_J_D_I_R
   _f_e_a_t_u_r_e  _d_e_s_c_r_i_b_e_d  _b_e_l_o_w_,  _P_M_a_k_e _w_i_l_l _t_r_y _t_o _l_o_c_a_t_e _t_a_r_g_e_t_s
   _u_s_i_n_g _s_e_a_r_c_h _p_a_t_h_s _a_s _w_e_l_l_.

   There are two types of search paths in PMake:  one  is  used
   for all types of files (including included makefiles) and is









                               -44-


   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. Other-
   wise 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.
   _N_E_W

   To be compatible with other Makes, PMake also interprets the
   value of the VPATH variable as  a  list  of  colon-separated
   directories  to  be  added to the general search path.  This
   feature was previously present but undocumented.

   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









                               -45-


   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-sys-
   tem  searches  is truly staggering, especially if many files
   without suffixes are used and the null suffix isn't  changed
   from ..oouutt.
   _N_E_W

   PMake  was  retrofitted  with a useful feature from 4.4BSD's
   make (which is a descendant of PMake).  This feature  allows
   platform-specific  files, in particular, object files, to be
   created in separate directories.  On startup, if  the  envi-
   ronment  variable  MMAAKKEEOOBBJJDDIIRR  is set and refers to a direc-
   tory, or if the subdirectory ``obj'' exists, the PMake  pro-
   cess  changes  its working directory to that directory.  The
   PMake variable ..CCUURRDDIIRR is set to the original working direc-
   tory (``.'' if no MAKEOBJDIR was found).

   Unless  specified  otherwise,  all commands will thus create
   their targets in the object directory.  Since the  value  of
   ..CCUURRDDIIRR  is also added to the default file search path, most
   target creation commands written in terms of variables ..AALLLL--
   SSRRCC,   ..IIMMPPSSRRCC,   ..OOOODDAATTEE,  etc.,  will  continue  to  work.
   Explicit path references may have to be modified to be rela-
   tive  to  $$((..CCUURRDDIIRR)).   For  example,  the first line in the
   example above would have to read thusly:

        ..PPAATTHH..cc         :: $$((..CCUURRDDIIRR))//....//lliibb


   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









                               -46-


   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.
     _N_E_W  _A_c_t_u_a_l_l_y_, _t_h_i_s _i_s _t_r_u_e _o_n_l_y _i_f _t_h_e _l_i_b_r_a_r_y _d_e_p_e_n_d_s _o_n
     _o_n_e _o_f _i_t_s _m_e_m_b_e_r_s_.  _O_t_h_e_r_w_i_s_e _w_e _c_o_u_l_d _n_e_v_e_r _c_r_e_a_t_e  _n_o_n_-
     _o_b_j_e_c_t _f_i_l_e _a_r_c_h_i_v_e_s _t_h_a_t _a_r_e _u_p_-_t_o_-_d_a_t_e_.

   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.
   _N_E_W

   CCoommppaattiibbiilliittyy:: Additionally, archive member may  be  identi-
   fied  by  a symbol they define.  The symbols are enclosed in
   parentheses and take the place  of  a  regular  member  file
   name,  i.e., ``_a_r_c_h_i_v_e(... (_s_y_m_b_o_l) ...)''.  The correspond-
   ing actual file names found in the library are  expanded  in
   any local variables, of course.  The member in question must
   already be part of the library, or an  error  will  be  sig-
   naled.   Consider  this clever way to extract an object file
   from a library.

        LLIIBBCC == //lliibb//lliibbcc..aa

        mmyyggeettoopptt..oo      :: $$((LLIIBBCC))((((ggeettoopptt))))
                aarr xx $$((LLIIBBCC)) $$((..OOOODDAATTEE))
                mmvv $$((..OOOODDAATTEE)) $$((..TTAARRGGEETT))

   Member lookup by symbol may not be supported on some  system
   with weird symbol table formats.

   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.










                               -47-


   +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:




























                               -48-


        ##
        ## 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

   _N_E_W

   _P_M_a_k_e _k_n_o_w_s _h_o_w _t_o _r_e_a_d _a _f_a_i_r _n_u_m_b_e_r _o_f  _d_i_f_f_e_r_e_n_t  _a_r_c_h_i_v_e
   _f_o_r_m_a_t_s  _(_i_n_c_l_u_d_i_n_g  _t_h_e  _r_a_n_l_i_b  _f_o_r_m_a_t_s _u_s_e_d _b_y _4_._4_B_S_D _a_n_d
   _M_I_P_S_, _a_s _w_e_l_l _a_s _S_y_s_t_e_m _V _c_o_m_m_o_n _a_r_c_h_i_v_e_s_)_.  _H_o_w_e_v_e_r_, _d_u_e _t_o
   _d_i_f_f_e_r_e_n_t  _w_o_r_d  _s_i_z_e_s  _a_n_d  _b_y_t_e _o_r_d_e_r_i_n_g_s _i_t _i_s _n_o_t _a_l_w_a_y_s
   _p_o_s_s_i_b_l_e _t_o _i_n_t_e_r_p_r_e_t _o_b_j_e_c_t _f_i_l_e  _a_r_c_h_i_v_e_s  _c_r_e_a_t_e_d  _f_o_r  _a
   _t_a_r_g_e_t _p_l_a_t_f_o_r_m _d_i_f_f_e_r_e_n_t _f_r_o_m _t_h_e _h_o_s_t _s_y_s_t_e_m_.

   44..33..  OOnn tthhee CCoonnddiittiioonn......











                               -49-


   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:

        ##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









                               -50-


            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:

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


   target   The syntax is ttaarrggeett((_n_a_m_e)) and is true if _n_a_m_e is a
            target mentioned in the makefile(s) read up to that
            point, i.e., appears somewhere to  the  left  of  a
            dependency  operator.   This  is  useful  following
            makefile inclusions or  wildcard  expansions  which
            may or may not result in the definition of targets.
            _N_E_W _T_h_i_s _f_u_n_c_t_i_o_n _w_a_s _p_r_e_v_i_o_u_s_l_y _p_r_e_s_e_n_t _b_u_t _u_n_d_o_c_-
            _u_m_e_n_t_e_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










                               -51-


   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
   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.
   _N_E_W

   _E_v_e_n _m_o_r_e _s_o _a_s _s_o_m_e _o_f _t_h_e _o_r_g_i_n_a_l _v_a_r_i_a_n_t_s  _o_f  ##iiff  _w_h_e_r_e
   _h_i_g_h_l_y  _u_n_i_n_t_u_i_t_i_v_e_,  _a_s _v_a_r_i_a_b_l_e _e_x_p_a_n_s_i_o_n_s _i_n _c_o_n_d_i_t_i_o_n_a_l_s
   _w_e_r_e _a_l_w_a_y_s _i_n_t_e_r_p_r_e_t_e_d _a_s _n_u_m_e_r_i_c _c_o_m_p_a_r_i_s_o_n_s_, _e_v_e_n _i_n  _t_h_e
   _a_b_s_e_n_c_e _o_f _a_n _o_p_e_r_a_t_o_r_.  _T_h_e _f_o_l_l_o_w_i_n_g _n_o_w _w_o_r_k _a_s _e_x_p_e_c_t_e_d_:

        ##iiffmmaakkee $$((VVAARR))
        ##iiffddeeff $$((VVAARR))

   expand the variable and apply the mmaakkee(()) or  ddeeffiinneedd(())  test
   to the result, respectively.

        ##iiff aarrgg










                               -52-


   checks  non-zero-ness  if aarrgg is a number (either literal or
   the result of a variable expansion), and  otherwise  assumes
   aarrgg to be a variable name and checks for its existence.
   _N_E_W

   The fact that PMake conditionals appear as comments to other
   Makes can be very convenient.  It allows one to write  make-
   files that work for both, while doing something special when
   run with PMake.  A standard idiom for this purpose is

        ##iiffddeeff ..PPMMAAKKEE
        FFOOOO == ssoommeetthhiinngg__vveerryy__ssppeecciiaall
        ##eellssee
        FFOOOO == ssttaannddaarrdd__vvaalluuee
        ##eennddiiff

   PMake will always choose the  first  branch  of  the  condi-
   tional,  whereas others will effectively only use the second
   assignment as it always overrides the first.

   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









                               -53-


        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.

   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









                               -54-


        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)
   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.











                               -55-


   +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:

             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).
   _N_E_W

   CCoommppaattiibbiilliittyy:: _P_M_a_k_e _n_o_w _a_l_s_o _r_e_c_o_g_n_i_z_e_s _t_h_e SSHHEELLLL  _v_a_r_i_a_b_l_e
   _f_o_u_n_d  _i_n  _m_o_s_t _o_t_h_e_r _M_a_k_e_s_.  _A_s _a_n _e_x_c_e_p_t_i_o_n _t_o _t_h_e _g_e_n_e_r_a_l
   _r_u_l_e_, _t_h_i_s _v_a_r_i_a_b_l_e _i_s _n_o_t _r_e_l_a_t_e_d _t_o _t_h_e _e_n_v_i_r_o_n_m_e_n_t  _v_a_r_i_-
   _a_b_l_e  _h_o_l_d_i_n_g  _t_h_e  _u_s_e_r_'_s _i_n_t_e_r_a_c_t_i_v_e _s_h_e_l_l_.  _I_n_s_t_e_a_d _i_t _i_s
   _s_e_t _f_r_o_m_, _a_n_d _m_a_y _b_e _u_s_e_d _t_o _s_e_t_, _t_h_e _c_u_r_r_e_n_t ..SSHHEELLLL  _s_p_e_c_i_-
   _f_i_c_a_t_i_o_n_.  _T_h_u_s_,

        SSHHEELLLL == //bbiinn//ccsshh

   is equivalent to











                               -56-


        ..SSHHEELLLL:: ppaatthh==//bbiinn//ccsshh

   _A_l_s_o  ##uunnddeeff  SSHHEELLLL  _r_e_s_e_t_s  _t_h_e  _s_h_e_l_l  _t_o  _t_h_e  _c_o_n_f_i_g_u_r_e_d
   _d_e_f_a_u_l_t_.

   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-compati-
   bility  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.
   _O_L_D

   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).
   _N_E_W

   _T_h_i_s  _i_s _t_h_e _d_e_f_a_u_l_t _c_o_n_f_i_g_u_r_a_t_i_o_n _n_o_w_.  _U_s_e --CC _t_o _c_h_a_n_g_e _i_t
   _b_a_c_k_.

   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:













                               -57-


        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 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,









                               -58-


   respectively),  but  also a count of the number of its chil-
   dren 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
   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











                               -59-


   (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:

             ..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.










                               -60-


   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
        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 tuto-
        rial....

   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.











                               -61-


   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.

   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.





















                                -i-


                           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 . . . . . . . . . . . . . . . .   5
        2.3. Variables  . . . . . . . . . . . . . . . . . .   7
        2.3.1. Local Variables  . . . . . . . . . . . . . .  10
        2.3.2. Command-line Variables . . . . . . . . . . .  11
        2.3.3. Global Variables . . . . . . . . . . . . . .  12
        2.3.4. Environment Variables  . . . . . . . . . . .  12
        2.4. Comments . . . . . . . . . . . . . . . . . . .  13
        2.5. Parallelism  . . . . . . . . . . . . . . . . .  13
        2.6. Writing and Debugging a Makefile . . . . . . .  14
        2.7. Invoking PMake . . . . . . . . . . . . . . . .  17
        2.8. Summary  . . . . . . . . . . . . . . . . . . .  23
        2.9. Exercises  . . . . . . . . . . . . . . . . . .  24
        3. Short-cuts and Other Nice Things . . . . . . . .  24
        3.1. Transformation Rules . . . . . . . . . . . . .  24
        3.2. Including Other Makefiles  . . . . . . . . . .  29
        3.3. Saving Commands  . . . . . . . . . . . . . . .  30
        3.4. Target Attributes  . . . . . . . . . . . . . .  31
        3.5. Special Targets  . . . . . . . . . . . . . . .  37
        3.6. Modifying Variable Expansion . . . . . . . . .  40
        3.7. More on Debugging  . . . . . . . . . . . . . .  42
        3.8. More Exercises . . . . . . . . . . . . . . . .  42
        4. PMake for Gods . . . . . . . . . . . . . . . . .  43
        4.1. Search Paths . . . . . . . . . . . . . . . . .  43
        4.2. Archives and Libraries . . . . . . . . . . . .  45
        4.3. On the Condition...  . . . . . . . . . . . . .  48
        4.4. A Shell is a Shell is a Shell  . . . . . . . .  52
        4.5. Compatibility  . . . . . . . . . . . . . . . .  56
        4.5.1. DEFCON 3 -- Variable Expansion . . . . . . .  56
        4.5.2. DEFCON 2 -- The Number of the Beast  . . . .  56
        4.5.3. DEFCON 1 -- Imitation is Not the Highest Form
        of Flattery . . . . . . . . . . . . . . . . . . . .  57
        4.6. The Way Things Work  . . . . . . . . . . . . .  57
        5. Answers to Exercises . . . . . . . . . . . . . .  58
        6. Glossary of Jargon . . . . . . . . . . . . . . .  59
        Index . . . . . . . . . . . . . . . . . . . . . . .  62



















