<!--
     $FreeBSD$
-->

<chapter id="basics">
  <title>The Basics of PMake</title>

  <para><application>PMake</application> takes as input a file that
    tells which files depend on which other files to be complete and
    what to do about files that are <quote>out-of-date</quote>.
    This file is known as a <quote>makefile</quote> and is usually
    kept in the top-most directory of the system to be built.
    While you can call the makefile anything you want,
    <application>PMake</application> will look for
    <filename>Makefile</filename> and <filename>makefile</filename>
    (in that order) in the current directory if you do not tell it
    otherwise.  To specify a different makefile, use the
    <option>-f</option> flag, e.g.</para>

  <screen>&prompt.user; <userinput>pmake <option>-f</option> <replaceable>program.mk</replaceable></userinput></screen>

  <para>A makefile has four different types of lines in it:</para>

  <itemizedlist>
    <listitem>
      <para>File dependency specifications</para>
    </listitem>

    <listitem>
      <para>Creation commands</para>
    </listitem>

    <listitem>
      <para>Variable assignments</para>
    </listitem>

    <listitem>
      <para>Comments, include statements and conditional directives</para>
    </listitem>
  </itemizedlist>

  <para>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
    <application>PMake</application>.</para>

  <section id="deplines">
    <title>Dependency Lines</title>

    <para>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 dependencies and are
      specified by means of dependency lines in the makefile.</para>

    <para>On a dependency line, there are targets and sources,
      separated by a one-&nbsp;or two-character operator.  The targets
      <quote>depend</quote> 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.</para>

    <para>Any file may be a target and any file may be a source, but
      the relationship between the two (or however many) is determined
      by the <quote>operator</quote> 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 follows:</para>

    <informaltable frame="none">
      <tgroup cols="2">
	<colspec colwidth="1*">
	<colspec colwidth="10*">

	<tbody>
	  <row valign="top">
	    <entry><literal>:</literal></entry>

	    <entry>If a colon is used, a target on the line is
	      considered to be <quote>out-of-date</quote> (and in need
	      of creation) if any of the sources has been modified
	      more recently than the target, or 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.<entry>
	  </row>

	  <row valign="top">
	    <entry><literal>!</literal></entry>

	    <entry>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
	      necessary.</entry>
	  </row>

	  <row valign="top">
	    <entry><literal>::</literal></entry>

	    <entry>If a double-colon is used, a target is
	      <quote>out-of-date</quote> if any of the sources has
	      been modified more recently than the target, or the
	      target doesn't exist, or 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
	      something else to the targets, but I will go into that
	      in the next section
	      (see <xref linkend="shellcmds">).</entry>
	  </row>
	</tbody>
      </tgroup>
    </informaltable>

    <para>Enough words, now for an example.  Take that C program I
      mentioned earlier.  Say there are three C files
      (<filename>a.c</filename>, <filename>b.c</filename> and
      <filename>c.c</filename>) each of which includes the file
      <filename>defs.h</filename>.  The dependencies between the files
      could then be expressed as follows:</para>

    <programlisting>program         : a.o b.o c.o

a.o b.o c.o     : defs.h

a.o             : a.c

b.o             : b.c

c.o             : c.c</programlisting>

    <para>You may be wondering at this point, where
      <filename>a.o</filename>, <filename>b.o</filename> and
      <filename>c.o</filename> came in and why they depend on
      <filename>defs.h</filename> and the C files do not.
      The reason is quite simple: <maketarget>program</maketarget>
      cannot be made by linking together <filename>.c</filename>
      files&mdash;it must be made from <filename>.o</filename> files.
      Likewise, if you change <filename>defs.h</filename>, it is not
      the <filename>.c</filename> files that need to be re-created,
      it is the <filename>.o</filename> files.  If you think of
      dependencies in these terms&mdash;which files (targets) need to
      be created from which files (sources)&mdash;you should have no
      problems.</para>

    <para>An important thing to notice about the above example, is
      that all the <filename>.o</filename> 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.  For example, <filename>a.o</filename> depends
      on both <filename>defs.h</filename> and <filename>a.c</filename>.</para>

    <para>The order of the dependency lines in the makefile is
      important: the first target on the first dependency line in the
      makefile will be the one that gets made if you do not say
      otherwise.  That is why program comes first in the example
      makefile, above.</para>

    <para>Both targets and sources may contain the standard C-Shell wildcard
      characters (<literal>{</literal>, <literal>}</literal>,
      <literal>*</literal>, <literal>?</literal>, <literal>[</literal>, and
      <literal>]</literal>), but the non-curly-brace ones may only appear in
      the final component (the file portion) of the target or source.
      The characters mean the following things:</para>

    <informaltable frame="none">
      <tgroup cols="2">
	<colspec colwidth="1*">
	<colspec colwidth="10*">

	<tbody>
	  <row valign="top">
	    <entry><literal>{}</literal></entry>

	    <entry>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
	      element.  For example,
	      <filename>src/{whiffle,beep,fish}.c</filename> expands
	      to the three words <filename>src/whiffle.c</filename>,
	      <filename>src/beep.c</filename>, and
	      <filename>src/fish.c</filename>.  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 <application>PMake</application> is
	      started.</entry> </row>

	  <row valign="top">
	    <entry><literal>*</literal></entry>

	    <entry>This matches zero or more characters of any sort.
	      <filename>src/*.c</filename> will expand to the same
	      three words as above as long as src contains those three
	      files  (and  no other files that end in
	      <filename>.c</filename>).></entry>
	  </row>

	  <row valign="top">
	    <entry><literal>?</literal></entry>

	    <entry>Matches any single character.</entry>
	  </row>

	  <row valign="top">
	    <entry><literal>[]</literal></entry>

	    <entry>This is known as a character class and contains
	      either a list of single characters, or a series of
	      character ranges (<literal>a-z</literal>, for example
	      means all characters between <literal>a</literal> and
	      <literal>z</literal>), or both.  It matches any single
	      character contained in the list.  For example,
	      <literal>[A-Za-z]</literal> will match all letters,
	      while <literal>[0123456789]</literal> will match all
	      numbers.</entry>
	  </row>
	</tbody>
      </tgroup>
    </informaltable>
  </section>

  <section id="shellcmds" xreflabel="Shell Commands">
    <title>Shell Commands</title>

    <para><quote>Is not that nice,</quote> you say to yourself,
      <quote>but how are files actually ``re-created'', as he likes to
	spell it?</quote>
      The re-creation is accomplished by commands you place in the
      makefile.  These commands are passed to the Bourne shell (better
      known as <filename>/bin/sh</filename>) to be executed and are
      expected to do what is necessary to update the target file
      (<application>PMake</application> does not actually check to see
      if the target was created.  It just assumes it is there).</para>

    <para>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 must be preceded by at least one
      tab.</para>

    <para>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 <literal>::</literal>
      operator was used on the dependency line.</para>

    <para>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.</para>

    <para>To expand on the earlier makefile, you might add commands
      as follows:</para>

    <programlisting>program         : a.o b.o c.o
        cc a.o b.o c.o -o program

a.o b.o c.o     : defs.h
a.o             : a.c
       cc -c a.c

b.o             : b.c
       cc -c b.c

c.o             : c.c
       cc -c c.c</programlisting>

    <para>Something you should remember when writing a makefile is,
      the commands will be executed if the target on the dependency
      line is out-of-date, not the sources.  In this example, the
      command <command>cc -c a.c</command> will be executed if
      <filename>a.o</filename> is out-of-date.  Because of the
      <literal>:</literal> operator, this means that should
      <filename>a.c</filename> or <filename>defs.h</filename> have
      been modified more recently than <filename>a.o</filename>, the
      command will be executed (<filename>a.o</filename> will be
      considered out-of-date).</para>

    <para>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 <filename>@</filename> and <literal>-</literal>, they cause
      <application>PMake</application> to do different things.</para>

    <para>In most cases, shell commands are printed before they are
      actually executed.  This is to keep you informed of what is
      going on.  If an <literal>@</literal> appears, however, this
      echoing is suppressed.  In the case of an echo command,
      say</para>

    <programlisting>echo Linking index</programlisting>

    <para>it would be rather silly to see</para>

    <screen>echo Linking index
Linking index</screen>

    <para>so <application>PMake</application> allows you to place an
      <literal>@</literal> before the command to prevent the command
      from being printed:</para>

    <programlisting>@echo Linking index</programlisting>

    <para>The other special character is the <literal>-</literal>.
      In case you did not know, shell commands finish with a certain
      <quote>exit status</quote>.  This status is made available by
      the operating system to whatever program invoked the command.
      Normally this status will be <literal>0</literal> if everything
      went ok and non-zero if something went wrong.  For this reason,
      <application>PMake</application> will consider an error to have
      occurred if one of the shells it invokes returns a non-zero
      status.  When it detects an error,
      <application>PMake</application>'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.
      <application>PMake</application> will exit after the last job
      finishes).  This behavior can be altered, however, by placing a
      <literal>-</literal> at the front of a command
      (e.g. <command>-mv index index.old</command>), certain
      command-line arguments, or doing other things, to be detailed
      later.  In such a case, the non-zero status is simply ignored
      and <application>PMake</application> keeps chugging
      along.</para>

    <para>Because all the commands are given to a single shell to
      execute, 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 for
      loops) to be entered in a natural manner.  Since this could
      cause problems for some makefiles that depend on each command
      being executed by a single shell,
      <application>PMake</application> has a <option>-B</option> flag
      (it stands for backwards-compatible) that forces each command to
      be given to a separate shell.  It also does several other
      things, all of which I discourage since they are now
      old-fashioned.</para>

    <para>A target's shell script is fed to the shell on its (the
      shell's) input stream. This means that any commands, such as
      <application>ci</application> that need to get input from the
      terminal will not work right &ndash; they willl get the shell's
      input, something they probably will not find to their liking.
      A simple way around this is to give a command like this:</para>

    <screen><command>ci $(SRCS) < <devicename>/dev/tty</devicename></command></screen>

    <para>This would force the program's input to come from the
      terminal.  If you cannot do this for some reason, your only
      other alternative is to use <application>PMake</application> in
      its fullest compatibility mode.
      See <quote>Compatibility</quote> in <xref linkend="gods">.</para>
  </section>


  <section id="variables">
    <title>Variables</title>

    <para><application>PMake</application>, like
      <application>Make</application> before it, has the ability to
      save text in variables to be recalled later at your convenience.
      Variables in <application>PMake</application> are used much like
      variables in the shell and, by tradition, consist of all
      upper-case letters (you do not have to use all upper-case
      letters.  In fact there is nothing to stop you from calling a
      variable <literal>@^&$%$</literal>.  Just tradition).  Variables
      are assigned-to using lines of the form:</para>

    <programlisting>VARIABLE = value</programlisting>

    <para>appended-to by:</para>

    <programlisting>VARIABLE += value</programlisting>

    <para>conditionally assigned-to (if the variable is not already
      defined) by:</para>

    <programlisting>VARIABLE ?= value</programlisting>

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

    <programlisting>VARIABLE := value</programlisting>

    <para>Any whitespace before value is stripped off.  When
      appending, a space is placed between the old value and the stuff
      being appended.</para>

    <para>The final way a variable may be assigned to is using:</para>

    <programlisting>VARIABLE != shell-command</programlisting>

    <para>In this case, shell-command 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 newlines
      (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:</para>

    <programlisting>CWD             != pwd</programlisting>

    <note>
      <para>This is intended to be used to execute commands that
	produce small amounts of output
	(e.g.&nbsp;<application>pwd</application>).
	The implementation is less than intelligent and will likely
	freeze if you execute something that produces thousands of
	bytes of output (8 Kb is the limit on many &unix; systems).
	The value of a variable may be retrieved by enclosing the
	variable name in parentheses or curly braces and preceding the
	whole thing with a dollar sign.</para>
    </note>

    <para>For example, to set the variable <envar>CFLAGS</envar> to
      the string <literal>-I/sprite/src/lib/libc -O,</literal> you
      would place a line:</para>

    <programlisting>CFLAGS = -I/sprite/src/lib/libc -O</programlisting>

    <para>in the makefile and use the word
      <literal>$(CFLAGS)</literal> wherever you would like the string
      <literal>-I/sprite/src/lib/libc -O</literal> to appear.  This is
      called variable expansion.</para>

    <note>
      <para>Unlike <application>Make</application>,
	<application>PMake</application> will not expand a variable
	unless it knows the variable exists.  E.g.&nbsp;if you have a
	<literal>${i}</literal> in a shell command and you have not
	assigned a value to the variable <varname>i</varname> (the
	empty string is considered a value, by the way), where
	<application>Make</application> would have substituted the
	empty string, <application>PMake</application> will leave the
	<literal>${i}</literal> alone.
	To keep <application>PMake</application> from substituting for
	a variable it knows, precede the dollar sign with another
	dollar sign (e.g.&nbsp;to pass <literal>${HOME}</literal> to
	the shell, use <literal>$${HOME}</literal>).  This causes
	<application>PMake</application>, in effect, to expand the
	<literal>$</literal> macro, which expands to a single
	<literal>$</literal>.</para>
    </note>

    <para>For compatibility, <application>Make</application>'s style
      of variable expansion will be used if you invoke
      <application>PMake</application> with any of the compatibility
      flags (<option>-V</option>, <option>-B</option> or
      <option>-M</option>.  The <option>-V</option> flag alters just
      the variable expansion).  There are two different times at which
      variable expansion occurs: when parsing a dependency line, the
      expansion occurs immediately upon reading the line.  If any
      variable used on a dependency line is undefined,
      <application>PMake</application> 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.  For
      example, 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 substituted for the outer
      variable).</para>

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

    <itemizedlist>
      <listitem>
	<para>Local variables.</para>
      </listitem>

      <listitem>
	<para>Command-line variables.</para>
      </listitem>

      <listitem>
	<para>Global variables.</para>
      </listitem>

      <listitem>
	<para>Environment variables.</para>
      </listitem>
    </itemizedlist>

    <para>The classification of variables does not 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.</para>

    <section id="localvariables">
      <title>Local Variables</title>

      <para>Each target can have as many as seven local variables.
	These are variables that are only <quote>visible</quote>
	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:</para>

      <variablelist>
	<varlistentry>
	  <term><makevar>.TARGET</makevar></term>

	  <listitem>
	    <para>The name of the target.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><makevar>.OODATE</makevar></term>

	  <listitem>
	    <para>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.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><makevar>.ALLSRC</makevar></term>

	  <listitem>
	    <para>The list of all sources for this target in the order
	      in which they were given.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><makevar>.PREFIX</makevar></term>

	  <listitem>
	    <para>The target without its suffix and without any
	      leading path.  E.g.&nbsp;for the target
	      <filename>../../lib/compat/fsRead.c</filename>, this
	      variable would contain <literal>fsRead</literal>.</para>
	  </listitem>
	</varlistentry>
      </variablelist>

      <para>Three other local variables are set only for certain
	targets under special circumstances.  These are the
	<makevar>.IMPSRC,</makevar> <makevar>.ARCHIVE,</makevar> and
	<makevar>.MEMBER</makevar> variables.  When they are set and
	how they are used is described later.</para>

      <para>Four of these variables may be used in sources as well as
	in shell scripts.  These are <makevar>.TARGET</makevar>,
	<makevar>.PREFIX</makevar>, <makevar>.ARCHIVE</makevar> and
	<makevar>.MEMBER</makevar>.  The variables in the sources are
	expanded once for each target on the dependency line,
	providing what is known as a <quote>dynamic source,</quote>
	allowing  you to specify several dependency lines at once.
	For example:</para>

      <programlisting>$(OBJS)         : $(.PREFIX).c</programlisting>

      <para>will create a dependency between each object file and its
	corresponding C source file.</para>
    </section>

    <section id="cmdvars">
      <title>Command-line Variables</title>

      <para>Command-line variables are set when
	<application>PMake</application> is first invoked by giving a
	variable assignment as one of the arguments.
	For example:</para>

      <screen>pmake "CFLAGS = -I/sprite/src/lib/libc -O"</screen>

      <para>would make <envar>CFLAGS</envar> be a command-line
	variable with the given value.  Any assignments to
	<envar>CFLAGS</envar> 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 <literal>=</literal> and
	<literal>?=</literal> behave as you would expect them to,
	mostly because assignments to command-line variables are
	performed before the makefile is read, thus the values set in
	the makefile are unavailable at the time.
	<literal>+=</literal> is the same as <literal>=</literal>,
	because the old value of the variable is sought only in the
	scope in which the assignment is taking place (for reasons of
	efficiency that I won't get into here).  <literal>:=</literal>
	and <literal>?=</literal> will work if the  only variables
	used are in the environment.  <literal>!=</literal> 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).</para>
    </section>

    <section id="globalvariables">
      <title>Global Variables</title>

      <para>Global variables are those set or appended-to in the
	makefile.  There are two classes of global variables: those
	you set and those <application>PMake</application> 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 <application>PMake</application> sets (almost)
	always begin with a period and always contain upper-case
	letters, only.  The variables are as follows:</para>

      <variablelist>
	<varlistentry>
	  <term><makevar>.PMAKE</makevar></term>

	  <listitem>
	    <para>The name by which <application>PMake</application>
	      was invoked is stored in this variable.  For
	      compatibility, the name is also stored in the
	      <makevar>MAKE</makevar> variable.</para>
	  </listitem>
	</varlistentry>

	<varlistentry>
	  <term><makevar>.MAKEFLAGS</makevar></term>

	  <listitem>
	    <para>All the relevant flags with which
	      <application>PMake</application> was invoked.
	      This does not include such things as <option>-f</option>
	      or variable assignments. Again for compatibility, this
	      value is stored in the <makevar>MFLAGS</makevar>
	      variable as well.</para>
	  </listitem>
	</varlistentry>
      </variablelist>

      <para>Two other variables, <makevar>.INCLUDES</makevar> and
	<makevar>.LIBS,</makevar> are covered in the section on
	special targets in <xref linkend="shortcuts">.</para>

      <para>Global variables may be deleted using lines of the
	form:</para>

      <programlisting>#undef variable</programlisting>

      <para>The <literal>#</literal> must be the first character on
	the line.  Note that this may only be done on global
	variables.</para>
    </section>

    <section id="envvars">
      <title>Environment Variables</title>

      <para>Environment variables are passed by the shell that invoked
	<application>PMake</application> and are given by
	<application>PMake</application> to each shell it invokes.
	They are expanded like any other variable, but they cannot be
	altered in any way.</para>

      <para>One special environment variable, <envar>PMAKE</envar>, is
	examined by <application>PMake</application> for command-line
	flags, variable assignments, etc., it should always use.  This
	variable is examined before the actual arguments to
	<application>PMake</application> are.  In addition, all flags
	given to <application>PMake</application>, either through the
	<envar>PMAKE</envar> variable or on the command line, are
	placed in this environment variable and exported to each shell
	<application>PMake</application> executes.  Thus recursive
	invocations of <application>PMake</application> automatically
	receive the same flags as the top-most one.</para>

      <para>Using all these variables, you can compress the sample
	makefile even more:</para>

      <programlisting>OBJS            = a.o b.o c.o

program         : $(OBJS)
        cc $(.ALLSRC) -o $(.TARGET)

$(OBJS)         : defs.h

a.o             : a.c
        cc -c a.c

b.o             : b.c
        cc -c b.c

c.o             : c.c
        cc -c c.c</programlisting>
    </section>
  </section>

  <section id="comments">
    <title>Comments</title>

    <para>Comments in a makefile start with a <literal>#</literal>
      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 <literal>#</literal> in a variable or on a
      dependency line, put a backslash in front of it.
      <application>PMake</application> will compress the two into a
      single <literal>#</literal>.</para>

    <note>
      <para>This is not true if <application>PMake</application> is
	operating in full-compatibility mode).</para>
    </note>
  </section>

  <section id="parellelism">
    <title>Parallelism</title>

    <para><application>PMake</application> was specifically designed
      to re-create several targets at once, when possible. You do not
      have to do anything special to cause this to happen (unless
      <application>PMake</application> was configured to not act in
      parallel, in which case you will have to make use of the
      <option>-L</option> and <option>-J</option> flags (see below)),
      but you do have to be careful at times.</para>

    <para>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 <application>xstr</application>, for example, always
      modifies the files <filename>strings</filename> and
      <filename>x.c</filename>.  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 <literal>$$$$</literal> to
      the end of the file name to tack on the process ID of the shell
      executing the command (each <literal>$$</literal> expands to a
      single <literal>$</literal>, thus giving you the shell variable
      <literal>$$</literal>).  Since only one shell is used for all
      the commands, you will get the same file name for each command
      in the script.</para>

    <para>The other problem comes from improperly-specified
      dependencies that worked in <application>Make</application>
      because of its sequential, depth-first way of examining them.
      While I do not want to go into depth on how
      <application>PMake</application> works (look in <xref
      linkend="gods"> if you are interested), I will warn you that
      files in two different levels of the dependency tree may be
      examined in a different order in
      <application>PMake</application> than they were in
      <application>Make</application>.
      For example, given the makefile:</para>

    <programlisting>a               :

b c b           : d</programlisting>

    <para><application>PMake</application> will examine the targets in
      the order <maketarget>c</maketarget>,
      <maketarget>d</maketarget>, <maketarget>b</maketarget>,
      <maketarget>a</maketarget>.  If the makefile's author expected
      <application>PMake</application> to abort before making
      <maketarget>c</maketarget> if an error occurred while making
      <maketarget>b</maketarget>, or if <maketarget>b</maketarget>
      needed to exist before <maketarget>c</maketarget> was made,
      (s)he will be sorely disappointed.  The dependencies are
      incomplete, since in both these cases,
      <maketarget>c</maketarget> would depend on
      <maketarget>b</maketarget>.  So watch out.</para>

    <para>Another problem you may face is that, while
      <application>PMake</application> is set up to handle the output
      from multiple jobs in a graceful fashion, the same is not so for
      input.  It has no way to regulate input to different jobs, so if
      you use the redirection from <devicename>/dev/tty</devicename> I
      mentioned earlier, you must be careful not to run two of the
      jobs at once.</para>
  </section>

  <section id="writeanddebug">
    <title>Writing and Debugging a Makefile</title>

    <para>Now you know most of what is in a
      <filename>Makefile</filename>, what do you do next?  There are
      two choices: use one of the uncommonly-available makefile
      generators or write your own makefile (I leave out the third
      choice of ignoring <application>PMake</application> and doing
      everything by hand as being beyond the bounds of common
      sense).</para>

    <para>When faced with the writing of a makefile, it is usually
      best to start from first principles: just what are you trying 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, <command>expr</command>, that
      takes standard infix expressions and converts them to prefix
      form (for no readily apparent reason).  You have got three
      source files, in C, that make up the program:
      <filename>main.c</filename>, <filename>parse.c</filename>, and
      <filename>output.c</filename>.  Harking back to my pithy advice
      about dependency lines, you write the first line of the
      file:</para>

    <programlisting>expr            : main.o parse.o output.o</programlisting>

    <para>because you remember <filename>expr</filename> is made from
      <filename>.o</filename> files, not <filename>.c</filename>
      files.  Similarly for the <filename>.o</filename> files you
      produce the lines:</para>

    <programlisting>main.o          : main.c

parse.o         : parse.c

output.o        : output.c

main.o parse.o output.o : defs.h</programlisting>

    <para>Great.  You have 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 have listed.  You remember about local variables?
      Good, so it should come to you as no surprise when you
      write:</para>

    <programlisting>expr            : main.o parse.o output.o
	cc -o $(.TARGET) $(.ALLSRC)</programlisting>

    <para>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 and
      <filename>defs.h</filename>, thus if you said:</para>

    <programlisting>cc -c $(.ALLSRC)</programlisting>

    <para>you will get (for <filename>main.o</filename>):</para>

    <programlisting>cc -c main.c defs.h</programlisting>

    <para>which is wrong.  So you round out the makefile with these
      lines:</para>

    <programlisting>main.o          : main.c
	cc -c main.c

parse.o         : parse.c
	cc -c parse.c

output.o        : output.c
	cc -c output.c</programlisting>

    <para>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 will address in <xref linkend="shortcuts">):</para>

    <orderedlist>
      <listitem>
	<para>The string <literal>main.o parse.o output.o</literal> is
	  repeated twice, necessitating two changes when you add
	  postfix (you were planning on that, were not you?).  This is
	  in direct violation of de Boor's First Rule of writing
	  makefiles:</para>

	<para>Anything that needs to be written more than once should
	  be placed in a variable.  I cannot emphasize this enough as
	  being very important to the maintenance of a makefile and
	  its program.</para>
      </listitem>

      <listitem>
	<para>There is no way to alter the way compilations are
	  performed 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:</para>

	<para>Any flags or programs used inside a makefile should be
	  placed in a variable so they may be changed, temporarily or
	  permanently, with the greatest ease.</para>
      </listitem>
    </orderedlist>

    <para>The makefile should more properly read:</para>

    <programlisting>OBJS            = main.o parse.o output.o

expr            : $(OBJS)
	$(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)

main.o          : main.c
	$(CC) $(CFLAGS) -c main.c

parse.o         : parse.c
	$(CC) $(CFLAGS) -c parse.c

output.o        : output.c
	$(CC) $(CFLAGS) -c output.c

$(OBJS)         : defs.h</programlisting>

    <para>Alternatively, if you like the idea of dynamic sources
      mentioned in <xref linkend="localvariables">, you could write it
      like this:</para>

    <programlisting>OBJS            = main.o parse.o output.o

expr            : $(OBJS)
	$(CC) $(CFLAGS) -o $(.TARGET) $(.ALLSRC)

$(OBJS)         : $(.PREFIX).c defs.h
	$(CC) $(CFLAGS) -c $(.PREFIX).c</programlisting>

    <para>These two rules and examples lead to de Boor's First
      Corollary:
      <emphasis>Variables are your friends</emphasis>.</para>

    <para>Once you have written the makefile comes the
      sometimes-difficult task of making sure the darn thing works.
      Your most helpful tool to make sure the makefile is at least
      syntactically correct is the <option>-n</option> flag, which
      allows you to see if <application>PMake</application> will choke
      on the makefile.  The second thing the <option>-n</option> flag
      lets you do is see what <application>PMake</application> would
      do without it actually doing it, thus you can make sure the
      right commands would be executed were you to give
      <application>PMake</application> its head.</para>

    <para>When you find your makefile is not behaving as you hoped,
      the first question that comes to mind (after <quote>What time is
      it, anyway?</quote>) is <quote>Why not?</quote> In answering
      this, two flags will serve you well: <literal>-d m</literal> and
      <quote>-p 2</quote>.
      The first causes <application>PMake</application> 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 <quote>-p 2</quote> flag makes
      <application>PMake</application> 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 output from <quote>-p 2</quote> is intended
      to resemble closely a real makefile, but with additional
      information provided and with variables expanded in those
      commands <application>PMake</application> actually printed or
      executed.</para>

    <para>Something to be especially careful about is circular
      dependencies.  For example:</para>

    <programlisting>a         : b

b         : c d

d         : a</programlisting>

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

  <section id="invoking">
    <title>Invoking PMake</title>

    <para><application>PMake</application> 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:</para>

    <variablelist>
      <varlistentry>
	<term><option>-d <replaceable>what</replaceable></option></term>

	<listitem>
	  <para>This causes <application>PMake</application> to spew
	    out debugging information that may prove useful to you.
	    If you cannot figure out why
	    <application>PMake</application> is doing what it is
	    doing, you might try using this flag.
	    The <replaceable>what</replaceable> parameter is a string
	    of single characters that tell
	    <application>PMake</application> what aspects you are
	    interested in.  Most of what I describe will make little
	    sense to you, unless you have dealt with
	    <application>Make</application> 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:</para>

	  <informaltable frame="none">
	    <tgroup cols="2">
	      <colspec colwidth="1*">
	      <colspec colwidth="7*">

	      <tbody>
		<row valign="top">
		  <entry><literal>a</literal></entry>

		  <entry>Archive searching and caching.</entry>
		</row>

		<row valign="top">
		  <entry><literal>c</literal></entry>

		  <entry>Conditional evaluation.</entry>
		</row>

		<row valign="top">
		  <entry><literal>d</literal></entry>

		  <entry>The searching and caching of
		    directories.</entry>
		</row>

		<row valign="top">
		  <entry><literal>j</literal></entry>

		  <entry>Various snippets of information related to
		    the running of the multiple shells.  Not
		    particularly interesting.</entry>
		</row>

		<row valign="top">
		  <entry><literal>m</literal></entry>

		  <entry>The making of each target: what target is
		    being examined; when it was last modified; whether
		    it is out-of-date; etc.</entry>
		</row>

		<row valign="top">
		  <entry><literal>p</literal></entry>

		  <entry>Makefile parsing.</entry>
		</row>

		<row valign="top">
		  <entry><literal>r</literal></entry>

		  <entry>Remote execution.</entry>
		</row>

		<row valign="top">
		  <entry><literal>s</literal></entry>

		  <entry>The application of suffix-transformation
		    rules.  (See <xref linkend="shortcuts">.)</entry>
		</row>

		<row valign="top">
		  <entry><literal>t</literal></entry>

		  <entry>The maintenance of the list of targets.</entry>
		</row>

		<row valign="top">
		  <entry><literal>v</literal></entry>

		  <entry>Variable assignment.</entry>
		</row>
	      </tbody>
	    </tgroup>
	  </informaltable>

	  <para>Of these all, the <literal>m</literal> and
	    <literal>s</literal> letters will be most useful to you.
	    If the <option>-d</option> is the final argument or the
	    argument from which it would get these key letters (see
	    below for a note about which argument would be used)
	    begins with a &ndash;, all of these debugging flags will
	    be set, resulting in massive amounts of output.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-f</option> makefile</term>

	<listitem>
	  <para>Specify a makefile to read different from the standard
	  makefiles (<filename>Makefile</filename> or
	  <filename>makefile</filename>).
	  If makefile is <literal>-</literal>,
	  <application>PMake</application> uses the standard input.
	  This is useful for making quick and dirty makefiles.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-h</option></term>

	<listitem>
	  <para>Prints out a summary of the various flags
	    <application>PMake</application> accepts.
	    It can also be used to find out what level of concurrency was
	    compiled into the version of <application>PMake</application> you
	    are using (look at <literal>-J</literal> and
	    <literal>-L</literal>) and various other information on how
	    <application>PMake</application> was configured.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-i</option></term>

	<listitem>
	  <para>If you give this flag, <application>PMake</application> will
	    ignore non-zero status returned by any of its shells.  It is like
	    placing a <literal>-</literal> before all the commands in the
	    makefile.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-k</option></term>

	<listitem>
	  <para>This is similar to <option>-i</option> in that it allows
	    <application>PMake</application> to continue when it sees an
	    error, but unlike <option>-i</option>, where
	    <application>PMake</application> continues blithely as if nothing
	    went wrong, <option>-k</option> causes it to recognize the error
	    and only continue work on those things that do not depend on the
	    target, either directly or indirectly (through depending on
	    something that depends on it), whose creation returned the error.
	    The <option>k</option> is for <quote>keep going</quote>.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-l</option></term>

	<listitem>
	  <para><application>PMake</application> has the ability to lock a
	    directory against other people executing it in the same directory
	    (by means of a file called <filename>LOCK.make</filename> 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, <option>-l</option> will turn it
	    off, and vice versa.
	    Note that this locking will not prevent you from invoking
	    <application>PMake</application> twice in the same place&ndash;if
	    you own the lock file, <application>PMake</application> will warn
	    you about it but continue to execute.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-m <replaceable>directory</replaceable></option></term>

	<listitem>
	  <para>Tells <application>PMake</application> another place to search
	    for included makefiles via the
	    &lt;<replaceable>filename</replaceable>&gt; style.
	    Several <filename>-m</filename> options can be given to form a
	    search path.  If this construct is used the default system
	    makefile search path is completely overridden.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-n</option></term>

	<listitem>
	  <para>This flag tells <application>PMake</application> not to
	    execute the commands needed to update the out-of-date targets in
	    the makefile.  Rather, <application>PMake</application> will
	    simply print the commands it would have executed and exit.
	    This is particularly useful for checking the correctness of a
	    makefile.  If <application>PMake</application> does not do what
	    you expect it to, it is a good chance the makefile is wrong.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-p number</option></term>

	<listitem>
	  <para>This causes <application>PMake</application> to print its
	    input in a reasonable form, though not necessarily one that would
	    make immediate sense to anyone but me.  The number 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 <option>-p 3</option> would print it twice-a-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.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-q</option></term>

	<listitem>
	  <para>If you give <application>PMake</application> this flag, it
	    will not try to re-create anything.  It will just see if anything
	    is out-of-date and exit non-zero if so.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-r</option></term>

	<listitem>
	  <para>When <application>PMake</application> starts up, it reads a
	    default makefile that tells it what sort of system it is on and
	    gives it some idea of what to do if you do not tell it anything.
	    I will tell you about it in <xref linkend="shortcuts">.
	    If you give this flag, <application>PMake</application> will not
	    read the default makefile.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-s</option></term>

	<listitem>
	  <para>This causes <application>PMake</application> to not print
	    commands before they are executed.  It is the equivalent of
	    putting an <quote>@</quote> before every command in the
	    makefile.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-t</option></term>

	<listitem>
	  <para>Rather than try to re-create a target,
	    <application>PMake</application> will simply <quote>touch</quote>
	    it so as to make it appear up-to-date.
	    If the target did not exist before, it will when
	    <application>PMake</application> finishes, but if the target did
	    exist, it will appear to have been updated.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-v</option></term>

	<listitem>
	  <para>Targets can still be created in parallel, however.
	    This is the mode <application>PMake</application> will enter
	    if it is invoked either as <command>smake</command> or
	    <command>vmake</command>.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-x</option></term>

	<listitem>
	  <para>This tells <application>PMake</application> it is ok to export
	    jobs to other machines, if they are 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 executed
	    locally.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-B</option></term>

	<listitem>
	  <para>Forces <application>PMake</application> to be as
	    backwards-compatible with <application>Make</application> as
	    possible while still being itself.  This includes:</para>

	  <itemizedlist>
	    <listitem>
	      <para>Executing one shell per shell command</para>
	    </listitem>

	    <listitem>
	      <para>Expanding anything that looks even vaguely like a
		variable, with the empty string replacing any variable
		<application>PMake</application> does not know.</para>
	    </listitem>

	    <listitem>
	      <para>Refusing to allow you to escape a <literal>#</literal>
		with a backslash.</para>
	    </listitem>

	    <listitem>
	      <para>Permitting undefined variables on dependency lines and
		conditionals (see below).  Normally this causes
		<application>PMake</application> to abort.</para>
	    </listitem>
	  </itemizedlist>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-C</option></term>

	<listitem>
	  <para>This nullifies any and all compatibility mode flags you may
	    have given or implied up to the time the <option>-C</option> is
	    encountered.  It is useful mostly in a makefile that you wrote for
	    <application>PMake</application> to avoid bad things happening
	    when someone runs <application>PMake</application> as
	    <application>make</application> or has things set in the
	    environment that tell it to be compatible.
	    <option>-C</option> is not placed in the <envar>PMAKE</envar>
	    environment variable or the <makevar>.MAKEFLAGS</makevar> or
	    <envar>MFLAGS</envar> global variables.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-D <replaceable>variable</replaceable></option></term>

	<listitem>
	  <para>Allows you to define a variable to have <quote>1</quote> as
	    its value.  The variable is a global variable, not a command-line
	    variable.  This is useful mostly for people who are used to the C
	    compiler arguments and those using conditionals, which I will get
	    into in <xref linkend="condition">.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-I <replaceable>directory</replaceable></option></term>

	<listitem>
	  <para>Tells <application>PMake</application> another place to search
	    for included makefiles.  Yet another thing to be explained in
	    <xref linkend="shortcuts"> (<xref linkend="including">, to be
	    precise).</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-J <replaceable>number</replaceable></option></term>

	<listitem>
	  <para>Gives the absolute maximum number of targets to create at once
	    on both local and remote machines.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-L <replaceable>number</replaceable></option></term>

	<listitem>
	  <para>This specifies the maximum number of targets to create on the
	    local machine at once.
	    This may be <literal>0</literal>, though you should be wary of
	    doing this, as <application>PMake</application> may hang until a
	    remote machine becomes available, if one is not available when it
	    is started.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-M</option></term>

	<listitem>
	  <para>This is the flag that provides absolute, complete, full
	    compatibility with <application>Make</application>.  It still
	    allows you to use all but a few of the features of
	    <application>PMake</application>, but it is non-parallel.
	    This is the mode <application>PMake</application> enters if you
	    call it <command>make</command>.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-P</option></term>

	<listitem>
	  <para>When creating targets in parallel, several shells are
	    executing at once, each wanting to write its own two cents'-worth
	    to the screen.
	    This output must be captured by <application>PMake</application>
	    in some way  in order to prevent the screen from being filled with
	    garbage even more indecipherable than you usually see.
	    <application>PMake</application> has two ways of doing this, one
	    of which provides for much cleaner output and a clear separation
	    between the output of different jobs, the other of which provides
	    a more immediate response so one can tell what is really
	    happening.  The former is done by notifying you when the creation
	    of a target starts, capturing the output and transferring it to
	    the screen all at once when the job finishes.  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 preceded by an indication of which job produced the output.
	    Since I prefer this second method, it is the one used by default.
	    The first method will be used if you give the <option>-P</option>
	    flag to <application>PMake</application>.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-V</option></term>

	<listitem>
	  <para>As mentioned before, the <option>-V</option> flag tells
	    <application>PMake</application> to use
	    <application>Make</application>'s style of expanding variables,
	    substituting the empty string for any variable it does not
	    know.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-W</option></term>

	<listitem>
	  <para>There are several times when <application>PMake</application>
	    will print a message at you that is only a warning, i.e.&nbsp;it
	    can continue to work in spite of your having done something silly
	    (such as forgotten a leading tab for a shell command).  Sometimes
	    you are well aware of silly things you have done and would like
	    <application>PMake</application> to stop bothering you.  This flag
	    tells it to shut up about anything non-fatal.</para>
	</listitem>
      </varlistentry>

      <varlistentry>
	<term><option>-X</option></term>

	<listitem>
	  <para>This flag causes <application>PMake</application> to not
	    attempt to export any jobs to another machine.</para>
	</listitem>
      </varlistentry>
    </variablelist>

    <para>Several flags may follow a single <literal>-</literal>.  Those flags
      that require arguments take them from successive parameters.
      For example:</para>

    <screen>pmake -fDnI server.mk DEBUG /chip2/X/server/include</screen>

    <para>will cause <application>PMake</application> to read
      <filename>server.mk</filename> as the input makefile,
      define the variable <makevar>DEBUG</makevar> as a global variable and
      look  for included makefiles in the directory
      <filename>/chip2/X/server/include</filename>.</para>
  </section>

  <section id="summary">
    <title>Summary</title>

    <para>A makefile is made of four types of lines:</para>

    <itemizedlist>
      <listitem>
	<para>Dependency lines</para>
      </listitem>

      <listitem>
	<para>Creation commands</para>
      </listitem>

      <listitem>
	<para>Variable assignments</para>
      </listitem>

      <listitem>
	<para>Comments, include statements and conditional directives</para>
      </listitem>
    </itemizedlist>

    <para>A dependency line is a list of one or more targets, an operator
      (<literal>:</literal>, <literal>::</literal>, or <literal>!</literal>),
      and a list of zero or more sources.  Sources may contain wildcards and
      certain local variables.</para>

    <para>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 <literal>@</literal> or
      <literal>-</literal>, <application>PMake</application> will cause the
      command to not be printed (if the character is <literal>@</literal>) or
      errors from it to be ignored (if <literal>-</literal>).  A blank line,
      dependency line or variable assignment terminates a creation script.
      There may be only one creation script for each target with a
      <literal>:</literal> or <literal>!</literal> operator.</para>

    <para>Variables are places to store text.  They may be unconditionally
      assigned-to using the <literal>=</literal> operator, appended-to using
      the <literal>+=</literal> operator, conditionally (if the variable is
      undefined) assigned-to with the <literal>?=</literal> operator, and
      assigned-to with variable expansion with the <literal>:=</literal>
      operator.  The output of a shell command may be assigned to a variable
      using the <literal>!=</literal> operator.  Variables may be expanded
      (their value inserted) by enclosing their name in parentheses or curly
      braces, preceded by a dollar sign.  A dollar sign may be escaped with
      another dollar sign.  Variables are not expanded if
      <application>PMake</application> does not know about them.
      There are seven local variables: <makevar>.TARGET</makevar>,
      <makevar>.ALLSRC</makevar>, <makevar>.OODATE</makevar>,
      <makevar>.PREFIX</makevar>, <makevar>.IMPSRC</makevar>,
      <makevar>.ARCHIVE</makevar>, and <makevar>.MEMBER</makevar>.
      Four of them (<makevar>.TARGET</makevar>, <makevar>.PREFIX</makevar>,
      <makevar>.ARCHIVE</makevar>, and <makevar>.MEMBER</makevar>) may be used
      to specify <quote>dynamic sources</quote>.  Variables are good.  Know
      them.  Love them.  Live them.</para>

    <para>Debugging of makefiles is best accomplished using the
      <option>-n</option>, <option>-d m</option>, and
      <option>-p 2</option> flags.</para>
  </section>
</chapter>

<!--
     Local Variables:
     mode: sgml
     sgml-indent-data: t
     sgml-omittag: nil
     sgml-always-quote-attributes: t
     sgml-parent-document: ("../book.sgml" "part" "chapter")
     End:
-->
