1229 lines
48 KiB
Text
1229 lines
48 KiB
Text
<!--
|
|
$FreeBSD$
|
|
-->
|
|
|
|
<chapter id="shortcuts">
|
|
<title>Short-cuts and Other Nice Things</title>
|
|
|
|
<para>Based on what I have told you so far, you may have gotten the
|
|
impression that <application>PMake</application> is just a way of
|
|
storing away commands and making sure you do not forget to compile
|
|
something. Good. That is just what it is. However, the ways I
|
|
have 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 is
|
|
what you are using) than I did in <xref linkend="basics">, just so
|
|
you are on your toes. So without further ado…</para>
|
|
|
|
<section id="rules">
|
|
<title>Transformation Rules</title>
|
|
|
|
<para>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; has developed, naming conventions, with
|
|
regard to suffixes, have also developed that have become almost
|
|
as incontrovertible as Law. E.g. a file ending in
|
|
<filename>.c</filename> is assumed to contain C source code; one
|
|
with a <filename>.o</filename> suffix is assumed to be a
|
|
compiled, relocatable object file that may be linked into any
|
|
program; a file with a <filename>.ms</filename> suffix is
|
|
usually a text file to be processed by
|
|
<application>Troff</application> with the <literal>-ms</literal>
|
|
macro package, and so on. One of the best aspects of both
|
|
<application>Make</application> and
|
|
<application>PMake</application> 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 solely 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.</para>
|
|
|
|
<para>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
|
|
<application>PMake</application> by placing them
|
|
as sources on a dependency line whose target is the special
|
|
target <makevar>.SUFFIXES</makevar>. E.g.:</para>
|
|
|
|
<programlisting>.SUFFIXES : .o .c
|
|
.c.o :
|
|
$(CC) $(CFLAGS) -c $(.IMPSRC)</programlisting>
|
|
|
|
<para>The creation script attached to the target is used to
|
|
trans form a file with the first suffix (in this case,
|
|
<filename>.c</filename>) into a
|
|
file with the second suffix (here, <filename>.o</filename>).
|
|
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 compile it using
|
|
<application>cc</application> with the <option>-c</option>
|
|
flag. This rule is taken straight from the system makefile.
|
|
Many transformation rules (and suffixes) are defined there,
|
|
and I refer you to it for more examples
|
|
(type <command>pmake -h</command> to find out where it
|
|
is).</para>
|
|
|
|
<para>There are several things to note about the
|
|
transformation rule given above:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>The <makevar>.IMPSRC</makevar> variable.
|
|
This variable is set to the
|
|
<quote>implied source</quote> (the file from which
|
|
the target is being created; the one with the first
|
|
suffix), which, in this case, is the
|
|
<filename>.c</filename> file.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The <envar>CFLAGS</envar> variable. Almost all of
|
|
the transformation 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
|
|
<option>-g</option> flag, to provide information for
|
|
dbx, you would set the <envar>CFLAGS</envar> variable to
|
|
contain <option>-g</option> (<literal>CFLAGS =
|
|
-g</literal>) and <application>PMake</application>
|
|
would take care of the rest.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>To give you a quick example, the makefile in
|
|
<xref linkend="envvars"> could be changed to this:</para>
|
|
|
|
<programlisting>OBJS = a.o b.o c.o
|
|
program : $(OBJS)
|
|
$(CC) -o $(.TARGET) $(.ALLSRC)
|
|
$(OBJS) : defs.h</programlisting>
|
|
|
|
<para>The transformation rule I gave above takes the place of the
|
|
6 lines
|
|
<footnote>
|
|
<para>This is also somewhat cleaner, I think, than
|
|
the dynamic source solution presented in
|
|
<xref linkend="writeanddebug">.</para>
|
|
</footnote>:</para>
|
|
|
|
<programlisting>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>Now you may be wondering about the dependency between the
|
|
<filename>.o</filename>
|
|
and <filename>.c</filename> files – it is not mentioned
|
|
anywhere in the new makefile. This is because it is not needed:
|
|
one of the effects of applying a transformation rule is the
|
|
target comes to depend on the implied source. That's why it is
|
|
called the implied source.</para>
|
|
|
|
<para>For a more detailed example. Say you have a makefile like
|
|
this:</para>
|
|
|
|
<programlisting>a.out : a.o b.o
|
|
$(CC) $(.ALLSRC)</programlisting>
|
|
|
|
<para>and a directory set up like this:</para>
|
|
|
|
<screen>total 4
|
|
-rw-rw-r-- 1 deboor 34 Sep 7 00:43 Makefile
|
|
-rw-rw-r-- 1 deboor 119 Oct 3 19:39 a.c
|
|
-rw-rw-r-- 1 deboor 201 Sep 7 00:43 a.o
|
|
-rw-rw-r-- 1 deboor 69 Sep 7 00:43 b.c</screen>
|
|
|
|
<para>While just typing <command>pmake</command> will do
|
|
the right thing, it is much more informative to type
|
|
<command>pmake -d s</command>. This will
|
|
show you what <application>PMake</application> is up
|
|
to as it processes the files. In this case,
|
|
<application>PMake</application> prints the following:</para>
|
|
|
|
<screen>Suff_FindDeps (a.out)
|
|
using existing source a.o
|
|
applying .o -> .out to "a.o"
|
|
Suff_FindDeps (a.o)
|
|
trying a.c...got it
|
|
applying .c -> .o to "a.c"
|
|
Suff_FindDeps (b.o)
|
|
trying b.c...got it
|
|
applying .c -> .o to "b.c"
|
|
Suff_FindDeps (a.c)
|
|
trying a.y...not there
|
|
trying a.l...not there
|
|
trying a.c,v...not there
|
|
trying a.y,v...not there
|
|
trying a.l,v...not there
|
|
Suff_FindDeps (b.c)
|
|
trying b.y...not there
|
|
trying b.l...not there
|
|
trying b.c,v...not there
|
|
trying b.y,v...not there
|
|
trying b.l,v...not there
|
|
--- a.o ---
|
|
cc -c a.c
|
|
--- b.o ---
|
|
cc -c b.c
|
|
--- a.out ---
|
|
cc a.o b.o</screen>
|
|
|
|
<para><computeroutput>Suff_FindDeps</computeroutput> is the
|
|
name of a function in <application>PMake</application> that
|
|
is called to check for implied sources for a target using
|
|
transformation rules. The transformations it tries are,
|
|
naturally enough, limited to the ones that have been defined
|
|
(a transformation may be defined multiple times, by the way,
|
|
but only the most recent one will be used). You will notice,
|
|
however, that there is a definite order to the suffixes that
|
|
are tried. This order is set by the relative positions of
|
|
the suffixes on the <makevar>.SUFFIXES</makevar> line
|
|
– the earlier a suffix appears, the earlier it is
|
|
checked as the source of a transformation. 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
|
|
<makevar>.SUFFIXES</makevar> dependency line with no sources)
|
|
and redefine them in the order you want.
|
|
(Previously-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 dependency explicit. In the above example,
|
|
<filename>a.out</filename> depends on <filename>a.o</filename>
|
|
and <filename>b.o</filename>. Since a transformation exists
|
|
from <filename>.o</filename> to <filename>.out</filename>,
|
|
<application>PMake</application> uses that, as indicated by
|
|
the <computeroutput>using existing source a.o</computeroutput>
|
|
message.</para>
|
|
|
|
<para>The search for a transformation starts from the suffix of
|
|
the target and continues through all the defined
|
|
transformations, 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.</para>
|
|
|
|
<para>For example, ignoring what's in the system makefile for
|
|
now, say you have a makefile like this:</para>
|
|
|
|
<screen>.SUFFIXES : .out .o .c .y .l
|
|
.l.c :
|
|
lex $(.IMPSRC)
|
|
mv lex.yy.c $(.TARGET)
|
|
.y.c :
|
|
yacc $(.IMPSRC)
|
|
mv y.tab.c $(.TARGET)
|
|
.c.o :
|
|
cc -c $(.IMPSRC)
|
|
.o.out :
|
|
cc -o $(.TARGET) $(.IMPSRC)</screen>
|
|
|
|
<para>and the single file <filename>jive.l</filename>.
|
|
If you were to type <command>pmake -rd ms jive.out</command>,
|
|
you would get the following output for
|
|
<filename>jive.out</filename>:</para>
|
|
|
|
<screen>Suff_FindDeps (jive.out)
|
|
trying jive.o...not there
|
|
trying jive.c...not there
|
|
trying jive.y...not there
|
|
trying jive.l...got it
|
|
applying .l -> .c to "jive.l"
|
|
applying .c -> .o to "jive.c"
|
|
applying .o -> .out to "jive.o"</screen>
|
|
|
|
<para>and this is why: <application>PMake</application> starts with the
|
|
target <filename>jive.out</filename>, figures out its suffix
|
|
(<filename>.out</filename>) and looks for things it can
|
|
transform to a <filename>.out</filename> file. In this case, it
|
|
only finds <filename>.o</filename>, so it looks for the file
|
|
<filename>jive.o</filename>. It fails to find it, so it
|
|
looks for transformations into a <filename>.o</filename>
|
|
file. Again it has only one choice: <filename>.c</filename>.
|
|
So it looks for <filename>jive.c</filename> and, as you
|
|
know, fails to find it. At this point it has two choices: it can
|
|
create the <filename>.c</filename> file from either a
|
|
<filename>.y</filename> file or a <filename>.l</filename> file.
|
|
Since <filename>.y</filename> came first on the
|
|
<makevar>.SUFFIXES</makevar> line, it checks for
|
|
<filename>jive.y</filename> first, but can not find it, so it looks
|
|
for <filename>jive.l</filename> and, lo and behold, there it is.
|
|
At this point, it has defined a transformation path as follows:</para>
|
|
|
|
<literallayout><filename>.l</filename> -> <filename>.c</filename> -> <filename>.o</filename> -> <filename>.out</filename></literallayout>
|
|
|
|
<para>and applies the transformation rules accordingly. For completeness,
|
|
and to give you a better idea of what <application>PMake</application>
|
|
actually did with this three-step transformation, this is what
|
|
<application>PMake</application> printed for the rest of the
|
|
process:</para>
|
|
|
|
<screen>Suff_FindDeps (jive.o)
|
|
using existing source jive.c
|
|
applying .c -> .o to "jive.c"
|
|
Suff_FindDeps (jive.c)
|
|
using existing source jive.l
|
|
applying .l -> .c to "jive.l"
|
|
Suff_FindDeps (jive.l)
|
|
Examining jive.l...modified 17:16:01 Oct 4, 1987...up-to-date
|
|
Examining jive.c...non-existent...out-of-date
|
|
--- jive.c ---
|
|
lex jive.l
|
|
... meaningless lex output deleted ...
|
|
mv lex.yy.c jive.c
|
|
Examining jive.o...non-existent...out-of-date
|
|
--- jive.o ---
|
|
cc -c jive.c
|
|
Examining jive.out...non-existent...out-of-date
|
|
--- jive.out ---
|
|
cc -o jive.out jive.o</screen>
|
|
|
|
<para>One final question remains: what does
|
|
<application>PMake</application> do with targets that have no
|
|
known suffix? <application>PMake</application> simply pretends
|
|
it actually has a known suffix and searches for
|
|
transformations accordingly. The suffix it chooses is the
|
|
source for the <maketarget>.NULL</maketarget> target mentioned
|
|
later. In the system makefile, <filename>.out</filename> is
|
|
chosen as the <quote>null suffix</quote> because most people
|
|
use <application>PMake</application> to create programs. You
|
|
are, however, free and welcome to change it to a suffix
|
|
of your own choosing. The null suffix is ignored, however,
|
|
when <application>PMake</application> is in compatibility
|
|
mode (see <xref linkend="gods">).</para>
|
|
</section>
|
|
|
|
<section id="including">
|
|
<title>Including Other Makefiles</title>
|
|
|
|
<para>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 something
|
|
like:</para>
|
|
|
|
<programlisting>#include "defs.h"</programlisting>
|
|
|
|
<para>to include the contents of <filename>defs.h</filename>
|
|
in the source file. <application>PMake</application>
|
|
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:</para>
|
|
|
|
<programlisting>#include <file></programlisting>
|
|
|
|
<para>or this:</para>
|
|
|
|
<programlisting>#include "file"</programlisting>
|
|
|
|
<para>The difference between the two is where
|
|
<application>PMake</application> searches for the file: the first way,
|
|
<application>PMake</application> will look for the file only in the
|
|
system makefile directory (or directories) (to find out what that
|
|
directory is, give <application>PMake</application> the
|
|
<filename>-h</filename> flag).
|
|
The system makefile directory search path can be overridden via the
|
|
<option>-m</option> option. For files in double-quotes, the search
|
|
is more complex:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>The directory of the makefile that's including the
|
|
file.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The current directory (the one in which you
|
|
invoked <application>PMake</application>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The directories given by you using
|
|
<option>-I</option> flags, in the order in which you
|
|
gave them.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Directories given by
|
|
<makevar>.PATH</makevar> dependency lines (see
|
|
<xref linkend="gods">).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The system makefile directory.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>in that order.</para>
|
|
|
|
<para>You are free to use <application>PMake</application> variables
|
|
in the filename – <application>PMake</application>
|
|
will expand them before searching for the file. You must
|
|
specify the searching method with either angle brackets or
|
|
double-quotes outside of a variable expansion. I.e. the following:</para>
|
|
|
|
<programlisting>SYSTEM = <command.mk>
|
|
|
|
#include $(SYSTEM)</programlisting>
|
|
|
|
<para>will not work.</para>
|
|
</section>
|
|
|
|
<section id="savingcmds">
|
|
<title>Saving Commands</title>
|
|
|
|
<para>There may come a time when you will want to save certain
|
|
commands to be executed when everything else is done. For
|
|
instance: you are making several different libraries at one
|
|
time and you want to create the members in parallel. Problem is,
|
|
<application>ranlib</application> is another one of those
|
|
programs that can not be run more than once in the same directory
|
|
at the same time (each one creates a file called
|
|
<filename>__.SYMDEF</filename> into which it stuffs information
|
|
for the linker to use. Two of them running 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.
|
|
<application>PMake</application> allows you to do this by
|
|
inserting an ellipsis (<quote>...</quote>) as a command between
|
|
commands to be run at once and those to be run later.</para>
|
|
|
|
<para>So for the <application>ranlib</application> case above,
|
|
you might do this:</para>
|
|
|
|
<programlisting>lib1.a : $(LIB1OBJS)
|
|
rm -f $(.TARGET)
|
|
ar cr $(.TARGET) $(.ALLSRC)
|
|
...
|
|
ranlib $(.TARGET)
|
|
|
|
lib2.a : $(LIB2OBJS)
|
|
rm -f $(.TARGET)
|
|
ar cr $(.TARGET) $(.ALLSRC)
|
|
...
|
|
ranlib $(.TARGET)</programlisting>
|
|
|
|
<para>This would save both</para>
|
|
|
|
<programlisting>ranlib $(.TARGET)</programlisting>
|
|
|
|
<para>commands until the end, when they would run one after the
|
|
other (using the correct value for the
|
|
<makevar>.TARGET</makevar> variable, of course).</para>
|
|
|
|
<para>Commands saved in this manner are only executed if
|
|
<application>PMake</application> manages to re-create
|
|
everything without an error.</para>
|
|
</section>
|
|
|
|
<section id="targetattr">
|
|
<title>Target Attributes</title>
|
|
|
|
<para><application>PMake</application> allows you to give
|
|
attributes to targets by means of special sources. Like
|
|
everything else <application>PMake</application> 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 will have to
|
|
find uses for yourself. Think of it as <quote>an exercise for
|
|
the reader</quote>. By placing one (or more) of these as a
|
|
source on a dependency line, you are <quote>marking the
|
|
target(s) with that attribute</quote>. That is just the way I
|
|
phrase it, so you know.</para>
|
|
|
|
<para>Any attributes given as sources for a transformation
|
|
rule are applied to the target of the transformation rule
|
|
when the rule is applied.</para>
|
|
|
|
<informaltable frame="none">
|
|
<tgroup cols="2">
|
|
<colspec colwidth="1*">
|
|
<colspec colwidth="10*">
|
|
|
|
<tbody>
|
|
<row valign="top">
|
|
<entry><literal>.DONTCARE</literal></entry>
|
|
|
|
<entry>If a target is marked with this attribute and
|
|
<application>PMake</application> can not figure out
|
|
how to create it, it will ignore this fact and assume
|
|
the file is not really needed or actually exists and
|
|
<application>PMake</application> just can not find
|
|
it. This may prove wrong, but the error will be
|
|
noted later on, not when <application>PMake</application>
|
|
tries to create the target so marked. This attribute also
|
|
prevents <application>PMake</application> from attempting
|
|
to touch the target if it is given the
|
|
<option>-t</option> flag.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.EXEC</literal></entry>
|
|
|
|
<entry><para>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 is
|
|
done. Say also that you have to load
|
|
other files from another system before you can compile
|
|
your files and further, that you do not want to go
|
|
through the loading and dumping unless one of your
|
|
files has changed. Your makefile might look a little
|
|
bit like this (remember, this is an educational example,
|
|
and do not worry about the <maketarget>COMPILE</maketarget>
|
|
rule, all will soon become clear, grasshopper):
|
|
|
|
<programlisting>system : init a.fasl b.fasl c.fasl
|
|
for i in $(.ALLSRC);
|
|
do
|
|
echo -n '(load "' >> input
|
|
echo -n ${i} >> input
|
|
echo '")' >> input
|
|
done
|
|
echo '(dump "$(.TARGET)")' >> input
|
|
lisp < input
|
|
|
|
a.fasl : a.l init COMPILE
|
|
b.fasl : b.l init COMPILE
|
|
c.fasl : c.l init COMPILE
|
|
COMPILE : .USE
|
|
echo '(compile "$(.ALLSRC)")' >> input
|
|
init : .EXEC
|
|
echo '(load-system)' > input</programlisting>
|
|
|
|
<literal>.EXEC</literal> sources, do not appear in the
|
|
local variables of targets that depend on them (nor are
|
|
they touched if <application>PMake</application> is
|
|
given the <option>-t</option>
|
|
flag). Note that all the rules, not just that for
|
|
system, include init as a source. This is because
|
|
none of the other targets can be made until init
|
|
has been made, thus they depend on it.</para></entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.EXPORT</literal></entry>
|
|
|
|
<entry>This is used to mark those targets whose
|
|
creation should be sent to another machine if at
|
|
all possible. This may be used by some exportation
|
|
schemes if the exportation is expensive. You
|
|
should ask your system administrator if it is
|
|
necessary.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.EXPORTSAME</literal></entry>
|
|
|
|
<entry>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 nroff) can be
|
|
performed the same on any architecture (CPU and
|
|
operating system type), while others (e.g. compiling
|
|
a program with cc) must be performed on a
|
|
machine with the same architecture. Not all export
|
|
systems will support this attribute.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.IGNORE</literal></entry>
|
|
|
|
<entry>Giving a target the
|
|
<literal>.IGNORE</literal> attribute causes
|
|
<application>PMake</application> to ignore errors
|
|
from any of the target's commands, as if they all
|
|
had <literal>-</literal> before them.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.INVISIBLE</literal></entry>
|
|
|
|
<entry><para>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
|
|
|
|
<programlisting>prog1 : $(PROG1OBJS) prog2 MAKEINSTALL
|
|
prog2 : $(PROG2OBJS) .INVISIBLE MAKEINSTALL</programlisting>
|
|
|
|
where <literal>MAKEINSTALL</literal>
|
|
is some complex <literal>.USE</literal> rule (see
|
|
below) that depends on the <makevar>.ALLSRC</makevar>
|
|
variable containing the right things. Without the
|
|
<literal>.INVISIBLE</literal>
|
|
attribute for <maketarget>prog2</maketarget>,
|
|
the <literal>MAKEINSTALL</literal> rule
|
|
could not 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.</para></entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.JOIN</literal></entry>
|
|
|
|
<entry><para>This is another way to avoid performing some
|
|
operations in parallel while permitting
|
|
everything 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
|
|
<makevar>.TARGET</makevar>
|
|
variable and all the local variables of any
|
|
target that depends on it, is replaced by the value
|
|
of its <makevar>.ALLSRC</makevar> 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 ranlib that I mentioned
|
|
earlier, only this time it is more severe: you can not
|
|
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:
|
|
|
|
<programlisting>program : $(OBJS) libraries
|
|
cc -o $(.TARGET) $(.ALLSRC)
|
|
|
|
libraries : lib1.a lib2.a lib3.a lib4.a .JOIN
|
|
ranlib $(.OODATE)</programlisting>
|
|
|
|
In this case, <application>PMake</application> will re-create
|
|
the <literal>$(OBJS)</literal>
|
|
as necessary, along with <filename>lib1.a</filename>,
|
|
<filename>lib2.a</filename>, <filename>lib3.a</filename>
|
|
and <filename>lib4.a</filename>. It will then
|
|
execute ranlib on any library that was changed and set
|
|
program's <makevar>.ALLSRC</makevar> variable to contain
|
|
what's in <literal>$(OBJS)</literal>
|
|
followed by <quote><filename>lib1.a</filename>
|
|
<filename>lib2.a</filename>
|
|
<filename>lib3.a</filename>
|
|
<filename>lib4.a</filename>.</quote> In
|
|
case you are wondering, it is called
|
|
<literal>.JOIN</literal> because
|
|
it joins together different threads of the
|
|
<quote>input graph</quote> at the target marked
|
|
with the attribute. Another aspect of the
|
|
<literal>.JOIN</literal>
|
|
attribute is it keeps the target from being
|
|
created if the <option>-t</option> flag was
|
|
given.</para></entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.MAKE</literal></entry>
|
|
|
|
<entry><para>The <literal>.MAKE</literal>
|
|
attribute marks its target as being a
|
|
recursive invocation of PMake. This forces
|
|
<application>PMake</application> to execute the
|
|
script associated with the
|
|
target (if it is out-of-date) even if you gave
|
|
the <option>-n</option> or
|
|
<option>-t</option> flag. By doing this, you can start
|
|
at the top of a system and type
|
|
|
|
<literallayout><command>pmake -n</command></literallayout>
|
|
|
|
and have it descend the directory tree (if your
|
|
makefiles are set up correctly), printing what
|
|
it would have executed if you had not included
|
|
the <option>-n</option> flag.</para></entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.NOEXPORT</literal></entry>
|
|
|
|
<entry>If possible,
|
|
<application>PMake</application> will attempt to
|
|
export the creation of all targets to another machine
|
|
(this depends on how <application>PMake</application>
|
|
was configured). Sometimes, the creation is so
|
|
simple, it is pointless to send it to another machine.
|
|
If you give the target the
|
|
<literal>.NOEXPORT</literal> attribute, it will be run
|
|
loally, even if you have given
|
|
<application>PMake</application> the <option>-L
|
|
0</option> flag.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.NOTMAIN</literal></entry>
|
|
|
|
<entry>Normally, if you do not specify a target to
|
|
make in any other way,
|
|
<application>PMake</application> will take the first
|
|
target on the first dependency line of a makefile as
|
|
the target to create. That target is known as the
|
|
<quote>Main Target</quote> and is labeled as such if
|
|
you print the dependencies out using the
|
|
<option>-p</option> flag. Giving a target this
|
|
attribute tells <application>PMake</application> that
|
|
the target is definitely not the Main Target. This
|
|
allows you to place targets in an included makefile
|
|
and have <application>PMake</application> create
|
|
something else by default.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.PRECIOUS</literal></entry>
|
|
|
|
<entry>When <application>PMake</application> 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
|
|
<literal>.PRECIOUS</literal> attribute, however,
|
|
<application>PMake</application> will leave it alone.
|
|
An additional side effect of the <literal>::</literal>
|
|
operator is to mark the targets as
|
|
<literal>.PRECIOUS</literal>.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.SILENT</literal></entry>
|
|
|
|
<entry>Marking a target with this attribute keeps its
|
|
commands from being printed when they are
|
|
executed, just as if they had an <literal>@</literal>
|
|
in front of them.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><literal>.USE</literal></entry>
|
|
|
|
<entry><para>By giving a target this attribute, you turn it
|
|
into <application></application>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
|
|
<literal>.USE</literal>) of the source. If the target
|
|
already has commands, the <literal>.USE</literal> target's
|
|
commands are added to the end. If more than one
|
|
<literal>.USE</literal>-marked source is given to a
|
|
target, the rules are applied sequentially. The typical
|
|
<literal>.USE</literal> rule (as I call them) will use
|
|
the sources of the target to which it is applied (as
|
|
stored in the <makevar>.ALLSRC</makevar> variable for
|
|
the target) as its <quote>arguments,</quote> if you
|
|
will. For example, you probably noticed that the
|
|
commands for creating <filename>lib1.a</filename> and
|
|
<filename>lib2.a</filename> in the example in section
|
|
<xref linkend="savingcmds"> were exactly the same.
|
|
You can use the <literal>.USE</literal> attribute to
|
|
eliminate the repetition, like so:
|
|
|
|
<programlisting>lib1.a : $(LIB1OBJS) MAKELIB
|
|
lib2.a : $(LIB2OBJS) MAKELIB
|
|
|
|
MAKELIB : .USE
|
|
rm -f $(.TARGET)
|
|
ar cr $(.TARGET) $(.ALLSRC)
|
|
...
|
|
ranlib $(.TARGET)</programlisting>
|
|
|
|
Several system makefiles (not to be confused
|
|
with The System Makefile) make use of these
|
|
<literal>.USE</literal> rules to make your life
|
|
easier (they are in the default, system makefile
|
|
directory...take a look). Note that the
|
|
<literal>.USE</literal> rule source itself
|
|
(<maketarget>MAKELIB</maketarget>) does not appear in
|
|
any of the targets's local variables. There is no limit
|
|
to the number of times I could use the
|
|
<maketarget>MAKELIB</maketarget> rule. If there were
|
|
more libraries, I could continue with
|
|
<literal>lib3.a : $(LIB3OBJS) MAKELIB</literal>
|
|
and so on and so forth.</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section id="specialtargets">
|
|
<title>Special Targets</title>
|
|
|
|
<para>As there were in <application>Make</application>, so there
|
|
are certain targets that have special meaning to
|
|
<application>PMake</application>. When you use one on a
|
|
dependency 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 will not describe them all in detail because some of them
|
|
are rather complex and I will describe them in more detail than you
|
|
will want in <xref linkend="gods">. The targets are as follows:</para>
|
|
|
|
<informaltable frame="none">
|
|
<tgroup cols="2">
|
|
<colspec colwidth="1*">
|
|
<colspec colwidth="10*">
|
|
|
|
<tbody>
|
|
<row valign="top">
|
|
<entry><maketarget>.BEGIN</maketarget></entry>
|
|
|
|
<entry>Any commands attached to this target are
|
|
executed before anything else is done. You can use
|
|
it for any initialization that needs
|
|
doing.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.DEFAULT</maketarget></entry>
|
|
|
|
<entry>This is sort of a <literal>.USE</literal>
|
|
rule for any target (that was used only as a source)
|
|
that <application>PMake</application> can not figure
|
|
out any other way to create. It is only <quote>sort
|
|
of</quote> a <literal>.USE</literal> rule because
|
|
only the shell script attached to the
|
|
<maketarget>.DEFAULT</maketarget> target is used.
|
|
The <makevar>.IMPSRC</makevar> variable of a target
|
|
that inherits <maketarget>.DEFAULT</maketarget>'s
|
|
commands is set to the target's own
|
|
name.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.END</maketarget></entry>
|
|
|
|
<entry>This serves a function similar to
|
|
<maketarget>.BEGIN</maketarget>, 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 function of
|
|
being a place on which <application>PMake</application>
|
|
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
|
|
<quote>...</quote>.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.EXPORT</maketarget></entry>
|
|
|
|
<entry>The sources for this target are passed
|
|
to the exportation system compiled into
|
|
<application>PMake</application>. Some systems will use
|
|
these sources to configure themselves. You should ask
|
|
your system administrator about this.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.IGNORE</maketarget></entry>
|
|
|
|
<entry>This target marks each of its sources
|
|
with the <literal>.IGNORE</literal> attribute.
|
|
If you do not give it any sources, then it is
|
|
like giving the <option>-i</option> flag when
|
|
you invoke <application>PMake</application> –
|
|
errors are ignored for all commands.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.INCLUDES</maketarget></entry>
|
|
|
|
<entry><para>The sources for this target are taken to be
|
|
suffixes that indicate a file that can be included in
|
|
a program source file. The suffix must have
|
|
already been declared with <literal>.SUFFIXES</literal>
|
|
(see below).
|
|
Any suffix so marked will have the directories on
|
|
its search path (see <maketarget>.PATH</maketarget>,
|
|
below) placed in the <makevar>.INCLUDES</makevar>
|
|
variable, each preceded by a <option>-I</option> flag.
|
|
This variable can then be used as an argument for
|
|
the compiler in the normal fashion. The
|
|
<filename>.h</filename> suffix is already marked in
|
|
this way in the system makefile. E.g. if you have
|
|
|
|
<programlisting>.SUFFIXES : .bitmap
|
|
.PATH.bitmap : /usr/local/X/lib/bitmaps
|
|
.INCLUDES : .bitmap</programlisting>
|
|
|
|
<application>PMake</application> will place
|
|
<literal>-I/usr/local/X/lib/bitmaps</literal>
|
|
in the <makevar>.INCLUDES</makevar> variable and you can
|
|
then say
|
|
|
|
<programlisting>cc $(.INCLUDES) -c xprogram.c</programlisting>
|
|
|
|
(Note: the <makevar>.INCLUDES</makevar> variable is
|
|
not actually filled in until the entire makefile has
|
|
been read.)</para></entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.INTERRUPT</maketarget></entry>
|
|
|
|
<entry>When <application>PMake</application> is
|
|
interrupted, it will execute the commands in the
|
|
script for this target, if it exists.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.LIBS</maketarget></entry>
|
|
|
|
<entry>This does for libraries what
|
|
<maketarget>.INCLUDES</maketarget> does for include
|
|
files, except the flag used is
|
|
<option>-L</option>, as required by those linkers
|
|
that allow you to tell them where to find libraries.
|
|
The variable used is <makevar>.LIBS</makevar>.
|
|
Be forewarned that <application>PMake</application>
|
|
may not have been compiled to do this if the linker
|
|
on your system does not accept the <option>-L</option>
|
|
flag, though the <makevar>.LIBS</makevar> variable
|
|
will always be defined once the makefile has been
|
|
read.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.MAIN</maketarget></entry>
|
|
|
|
<entry>If you did not give a target (or targets) to
|
|
create when you invoked
|
|
<application>PMake</application>, it will take the
|
|
sources of this target as the targets to
|
|
create.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.MAKEFLAGS</maketarget></entry>
|
|
|
|
<entry>This target provides a way for you to
|
|
always specify flags for <application>PMake</application>
|
|
when the makefile is used. The flags are just as they
|
|
would be typed to the shell (except you can not use shell
|
|
variables unless they are in the environment), though
|
|
the <option>-f</option> and <option>-r</option>
|
|
flags have no effect.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.NULL</maketarget></entry>
|
|
|
|
<entry>This allows you to specify what
|
|
suffix <application>PMake</application> should pretend
|
|
a file has if, in fact, it has no known suffix. Only
|
|
one suffix may be so designated. The last source on the
|
|
dependency line is the suffix that is used (you
|
|
should, however, only give one suffix...).</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.PATH</maketarget></entry>
|
|
|
|
<entry>If you give sources for this target,
|
|
<application>PMake</application> 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, we will leave it till <xref
|
|
linkend="gods"> to give you a complete
|
|
explanation.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.PATH<replaceable>suffix</replaceable></maketarget></entry>
|
|
|
|
<entry>This does a similar thing to
|
|
<maketarget>.PATH</maketarget>, but it does it only
|
|
for files with the given suffix. The suffix must
|
|
have been defined already. Look at Search Paths
|
|
(<xref linkend="searchpaths">) for more
|
|
information.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.PRECIOUS</maketarget></entry>
|
|
|
|
<entry>Similar to <maketarget>.IGNORE</maketarget>,
|
|
this gives the <literal>.PRECIOUS</literal> attribute to
|
|
each source on the dependency line, unless there are
|
|
no sources, in which case the <literal>.PRECIOUS</literal>
|
|
attribute is given to every target in the file.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.RECURSIVE</maketarget></entry>
|
|
|
|
<entry>This target applies the <literal>.MAKE</literal>
|
|
attribute to all its sources. It does nothing if you
|
|
do not give it any sources.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.SHELL</maketarget></entry>
|
|
|
|
<entry><application>PMake</application> 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 <quote><xref linkend="ashell"
|
|
endterm="ashelltitle"></quote> (<xref
|
|
linkend="ashell">) for more
|
|
information.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.SILENT</maketarget></entry>
|
|
|
|
<entry>When you use
|
|
<maketarget>.SILENT</maketarget> as a target, it
|
|
applies the <literal>.SILENT</literal> attribute to
|
|
each of its sources. If there are no sources on the
|
|
dependency line, then it is as if you gave
|
|
<application>PMake</application> the
|
|
<option>-s</option> flag and no commands will be
|
|
echoed.</entry>
|
|
</row>
|
|
|
|
<row valign="top">
|
|
<entry><maketarget>.SUFFIXES</maketarget></entry>
|
|
|
|
<entry>This is used to give new file suffixes
|
|
for <application>PMake</application> to handle.
|
|
Each source is a suffix
|
|
<application>PMake</application> should
|
|
recognize. If you give a
|
|
<maketarget>.SUFFIXES</maketarget> dependency line
|
|
with no sources, <application>PMake</application>
|
|
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.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>In addition to these targets, a line of the form:</para>
|
|
|
|
<programlisting>attribute : sources</programlisting>
|
|
|
|
<para>applies the attribute to all the targets listed as sources.</para>
|
|
</section>
|
|
|
|
<section id="modyvarex">
|
|
<title>Modifying Variable Expansion</title>
|
|
|
|
<para>Variables need not always be expanded verbatim.
|
|
<application>PMake</application> defines several modifiers
|
|
that may be applied to a variable'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:</para>
|
|
|
|
<programlisting>${VARIABLE:modifier}</programlisting>
|
|
|
|
<para>Each modifier is a single character followed by something
|
|
specific to the modifier itself. You may apply as many
|
|
modifiers as you want – each one is applied to the
|
|
result of the previous and is separated from the
|
|
previous by another colon.</para>
|
|
|
|
<para>There are seven ways to modify a variable's expansion,
|
|
most of which come from the C shell variable modification
|
|
characters:</para>
|
|
|
|
<variablelist>
|
|
<varlistentry>
|
|
<term><literal>Mpattern</literal></term>
|
|
|
|
<listitem>
|
|
<para>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 pattern. The pattern is a
|
|
wildcard pattern like that used by the shell, where
|
|
<literal>*</literal> means <literal>0</literal> or more
|
|
characters of any sort; <literal>?</literal> is any
|
|
single character; <literal>[abcd]</literal> matches any
|
|
single character that is either <literal>a</literal>,
|
|
<literal>b</literal>, <literal>c</literal> or
|
|
<literal>d</literal> (there may be any number of
|
|
characters between the brackets);
|
|
<literal>[0-9]</literal> matches any single character
|
|
that is between <literal>0</literal> and
|
|
<literal>9</literal> (i.e. any digit. This form may be
|
|
freely mixed with the other bracket form), and
|
|
<literal>\</literal> is used to escape any of the
|
|
characters <literal>*</literal>, <literal>?</literal>,
|
|
<literal>[</literal> or <literal>:</literal>, leaving
|
|
them as regular characters to match themselves in a
|
|
word. For example, the system makefile
|
|
<filename><makedepend.mk></filename> uses
|
|
<literal>$(CFLAGS:M-[ID]*)</literal> to extract all the
|
|
<option>-I</option> and <option>-D</option> flags that
|
|
would be passed to the C compiler. This allows it to
|
|
properly locate include files and generate the correct
|
|
dependencies.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>Npattern</literal></term>
|
|
|
|
<listitem>
|
|
<para>This is identical to <literal>:M</literal> except
|
|
it substitutes all words that do not match the given
|
|
pattern.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>S/search-string/replacement-string/[g]</literal></term>
|
|
|
|
<listitem>
|
|
<para>Causes the first occurrence of search-string in
|
|
the variable to be replaced by replacement-string,
|
|
unless the <option>g</option> flag is given at the end,
|
|
in which case all occurrences of the string are
|
|
replaced. The substitution is performed on each word in
|
|
the variable in turn. If search-string begins with a
|
|
<literal>^</literal>, the string must match starting at
|
|
the beginning of the word. If search-string ends with a
|
|
<literal>$</literal>, the string must match to the end
|
|
of the word (these two may be combined to force an exact
|
|
match). If a backslash precedes these two characters,
|
|
however, they lose their special meaning. Variable
|
|
expansion also occurs in the normal fashion inside both
|
|
the search-string and the replacement-string, except
|
|
that a backslash is used to prevent the expansion of a
|
|
<literal>$</literal>, not another dollar sign, as is
|
|
usual. Note that search-string is just a string, not a
|
|
pattern, so none of the usual regularexpression/wildcard
|
|
characters have any special meaning save
|
|
<literal>^</literal> and <literal>$</literal>. In the
|
|
replacement string, the <literal>&</literal> character
|
|
is replaced by the search-string 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 preceding it with a
|
|
backslash.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>T</literal></term>
|
|
|
|
<listitem>
|
|
<para>Replaces each word in the variable expansion by
|
|
its last component (its <quote>tail</quote>).
|
|
For example, given:</para>
|
|
|
|
<programlisting>OBJS = ../lib/a.o b /usr/lib/libm.a
|
|
TAILS = $(OBJS:T)</programlisting>
|
|
|
|
<para>the variable <makevar>TAILS</makevar> would expand
|
|
to <literal>a.o b libm.a.</literal></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>H</literal></term>
|
|
|
|
<listitem>
|
|
<para>This is similar to <literal>:T</literal>, except
|
|
that every word is replaced by everything but the tail
|
|
(the <quote>head</quote>). Using the same definition of
|
|
<makevar>OBJS</makevar>, the string
|
|
<literal>$(OBJS:H)</literal> would expand to
|
|
<literal>../lib /usr/lib.</literal> Note that the final
|
|
slash on the heads is removed and anything without
|
|
a head is replaced by the empty string.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>E</literal></term>
|
|
|
|
<listitem>
|
|
<para><literal>:E</literal> replaces each word by its
|
|
suffix (<quote>extension</quote>). So
|
|
<literal>$(OBJS:E)</literal> would give you
|
|
<literal>.o .a.</literal></para>
|
|
</listitem>
|
|
</varlistentry>
|
|
|
|
<varlistentry>
|
|
<term><literal>R</literal></term>
|
|
|
|
<listitem>
|
|
<para>This replaces each word by everything but the
|
|
suffix (the <quote>root</quote> of the word).
|
|
<literal>$(OBJS:R)</literal> expands to
|
|
<literal>../lib/a b /usr/lib/libm</literal>.</para>
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>In addition, the System V style of substitution is also
|
|
supported. This looks like:</para>
|
|
|
|
<programlisting>$(VARIABLE:search-string=replacement)</programlisting>
|
|
|
|
<para>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.</para>
|
|
</section>
|
|
|
|
<section id="moreexercises">
|
|
<title>More Exercises</title>
|
|
|
|
<bridgehead>Exercise 3.1</bridgehead>
|
|
|
|
<para>You have got a set programs, each of which is created from
|
|
its own assembly-language source file (suffix
|
|
<filename>.asm</filename>). Each program can be assembled into
|
|
two versions, one with error-checking code assembled in and one
|
|
without. You could assemble them into files with different
|
|
suffixes (<filename>.eobj</filename> and
|
|
<filename>.obj</filename>, for instance), but your linker only
|
|
understands files that end in <filename>.obj</filename>. To top
|
|
it all off, the final executables must have the suffix
|
|
<filename>.exe</filename>. How can you still use
|
|
transformation rules to make your life easier (Hint: assume the
|
|
errorchecking versions have ec tacked onto their prefix)?</para>
|
|
|
|
<bridgehead>Exercise 3.2</bridgehead>
|
|
|
|
<para>Assume, for a moment or two, you want to perform
|
|
a sort of <quote>indirection</quote> 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,
|
|
<application>PMake</application> does not allow constructs like:</para>
|
|
|
|
<programlisting>$($(FOO))</programlisting>
|
|
|
|
<para>What do you do? Hint: no further variable expansion is
|
|
performed after modifiers are applied, thus if you
|
|
cause a <literal>$</literal> to occur in the expansion,
|
|
that is what will be in the result.</para>
|
|
</section>
|
|
</chapter>
|
|
|
|
<!--
|
|
Local Variables:
|
|
mode: sgml
|
|
sgml-indent-data: t
|
|
sgml-omittag: nil
|
|
sgml-always-quote-attributes: t
|
|
sgml-parent-document: ("../book.sgml" "chapter")
|
|
End:
|
|
-->
|