Remove the pmake book from the published docs.
It doesn't at all match either bmake, or the make that bmake replaced (confusingly also sometimes referred to as pmake and fmake). The style of the Makefiles does not bear any semblance to ours, the commands are different, and so are the options. It's a fascinating document, and it's good that it's not going to completely disappear; it'll be visible in the older versions [1] as well as being searchable, but it's really not something we should have presented as being in any way useful documentation nowadays. [1] https://docs.freebsd.org/doc/9.0-RELEASE/usr/share/doc/freebsd/en_US.ISO8859-1/books/pmake/book.html PR: doc/211949 Reviewed by: linimon Reviewed by: bcr
This commit is contained in:
parent
655e756e4e
commit
ac184111f1
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=52714
11 changed files with 0 additions and 4153 deletions
|
|
@ -7,7 +7,6 @@ SUBDIR+= developers-handbook
|
|||
SUBDIR+= faq
|
||||
SUBDIR+= fdp-primer
|
||||
SUBDIR+= handbook
|
||||
SUBDIR+= pmake
|
||||
SUBDIR+= porters-handbook
|
||||
|
||||
ROOT_SYMLINKS= faq handbook
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# This is an XML version of the pmake tutorial by Adam de Boor that is
|
||||
# also part of the src/share/doc/psd collection of docs.
|
||||
#
|
||||
|
||||
DOC?= book
|
||||
|
||||
FORMATS?= html-split
|
||||
|
||||
INSTALL_COMPRESSED?= gz
|
||||
INSTALL_ONLY_COMPRESSED?=
|
||||
|
||||
# SRCS lists the individual XML files that make up the document.
|
||||
# Changes to any of these files will force a rebuild.
|
||||
|
||||
# XML content
|
||||
SRCS= book.xml
|
||||
SRCS+= answers/chapter.xml
|
||||
SRCS+= basics/chapter.xml
|
||||
SRCS+= glossary/glossary.xml
|
||||
SRCS+= gods/chapter.xml
|
||||
SRCS+= intro/chapter.xml
|
||||
SRCS+= shortcuts/chapter.xml
|
||||
|
||||
DOC_PREFIX?= ${.CURDIR}/../../..
|
||||
.include "${DOC_PREFIX}/share/mk/doc.project.mk"
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
$FreeBSD$
|
||||
-->
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="answers">
|
||||
<title>Answers to Exercises</title>
|
||||
|
||||
<bridgehead>Exercise 3.1</bridgehead>
|
||||
|
||||
<para>This is something of a trick question, for which I apologize.
|
||||
The trick comes from the &unix; definition of a suffix, which
|
||||
<application>PMake</application> does not necessarily share.
|
||||
You will have noticed that all the suffixes used in this tutorial
|
||||
(and in &unix; in general) begin with a period
|
||||
(<filename>.ms</filename>, <filename>.c</filename>, etc.).
|
||||
Now, <application>PMake</application>'s idea of a suffix is more
|
||||
like English's: it is the characters at the end of a word. With
|
||||
this in mind, one possible solution to this problem goes as
|
||||
follows:</para>
|
||||
|
||||
<programlisting>.SUFFIXES : ec.exe .exe ec.obj .obj .asm
|
||||
ec.objec.exe .obj.exe :
|
||||
link -o $(.TARGET) $(.IMPSRC)
|
||||
.asmec.obj :
|
||||
asm -o $(.TARGET) -DDO_ERROR_CHECKING $(.IMPSRC)
|
||||
.asm.obj :
|
||||
asm -o $(.TARGET) $(.IMPSRC)</programlisting>
|
||||
|
||||
<bridgehead>Excercise 3.2</bridgehead>
|
||||
|
||||
<para>The trick to this one lies in the <literal>:=</literal>
|
||||
variable-assignment operator and the <literal>:S</literal>
|
||||
variable-expansion modifier. Basically what you want is to take
|
||||
the pointer variable, so to speak, and transform it into an
|
||||
invocation of the variable at which it points. You might try
|
||||
something like:</para>
|
||||
|
||||
<programlisting>$(PTR:S/^/\$(/:S/$/))</programlisting>
|
||||
|
||||
<para>which places <literal>$(</literal> at the front of the
|
||||
variable name and <literal>)</literal> at the end, thus
|
||||
transforming <literal>VAR,</literal> for example, into
|
||||
<literal>$(VAR)</literal>, which is just what we want.
|
||||
Unfortunately (as you know if you have tried it), since, as it
|
||||
says in the hint, <application>PMake</application> does no further
|
||||
substitution on the result of a modified expansion, that is all
|
||||
you get. The solution is to make use of <literal>:=</literal> to
|
||||
place that string into yet another variable, then invoke the other
|
||||
variable directly:</para>
|
||||
|
||||
<programlisting>*PTR := $(PTR:S/^/\$(/:S/$/)/)</programlisting>
|
||||
|
||||
<para>You can then use <literal>$(*PTR)</literal> to your heart's
|
||||
content.</para>
|
||||
</chapter>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,43 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE book PUBLIC "-//FreeBSD//DTD DocBook XML V5.0-Based Extension//EN"
|
||||
"http://www.FreeBSD.org/XML/share/xml/freebsd50.dtd" [
|
||||
<!ENTITY % chapters.ent SYSTEM "chapters.ent">
|
||||
%chapters.ent;
|
||||
]>
|
||||
<book xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
|
||||
<info><title>PMake — A Tutorial</title>
|
||||
|
||||
|
||||
<author><personname><firstname>Adam</firstname><surname>de Boor</surname></personname></author>
|
||||
|
||||
<copyright>
|
||||
<year>1988</year>
|
||||
<year>1989</year>
|
||||
<holder>Adam de Boor</holder>
|
||||
</copyright>
|
||||
|
||||
<copyright>
|
||||
<year>1989</year>
|
||||
<holder>Berkeley Softworks</holder>
|
||||
</copyright>
|
||||
|
||||
<copyright>
|
||||
<year>1988</year>
|
||||
<year>1989</year>
|
||||
<year>1993</year>
|
||||
<holder>The Regents of the University of California.</holder>
|
||||
</copyright>
|
||||
|
||||
&pmake.legalnotice;
|
||||
|
||||
<releaseinfo>$FreeBSD$</releaseinfo>
|
||||
</info>
|
||||
|
||||
&chap.intro;
|
||||
&chap.basics;
|
||||
&chap.shortcuts;
|
||||
&chap.gods;
|
||||
&chap.answers;
|
||||
|
||||
&glossary;
|
||||
</book>
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
Creates entities for each chapter in the PMake Tutorial.
|
||||
|
||||
$FreeBSD$
|
||||
-->
|
||||
|
||||
<!ENTITY pmake.legalnotice SYSTEM "legalnotice.xml">
|
||||
<!ENTITY chap.intro SYSTEM "intro/chapter.xml">
|
||||
<!ENTITY chap.basics SYSTEM "basics/chapter.xml">
|
||||
<!ENTITY chap.shortcuts SYSTEM "shortcuts/chapter.xml">
|
||||
<!ENTITY chap.gods SYSTEM "gods/chapter.xml">
|
||||
<!ENTITY chap.answers SYSTEM "answers/chapter.xml">
|
||||
<!ENTITY glossary SYSTEM "glossary/glossary.xml">
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
$FreeBSD$
|
||||
-->
|
||||
<glossary xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="glossary">
|
||||
<title>Glossary of Jargon</title>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>attribute</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A property given to a target that causes
|
||||
<application>PMake</application> to treat it differently.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm xml:id="cmdscript">command script</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The lines immediately following a dependency line that specify
|
||||
commands to execute to create each of the targets on the dependency
|
||||
line. Each line in the command script must begin with a tab.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>command-line variable</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A variable defined in an argument when
|
||||
<application>PMake</application> is first executed.
|
||||
Overrides all assignments to the same variable name in the
|
||||
makefile.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>conditional</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A construct much like that used in C that allows a makefile to be
|
||||
configured on the fly based on the local environment, or on what is
|
||||
being made by that invocation of <application>PMake</application>.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>creation script</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Commands used to create a target.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>dependency</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The relationship between a source and a target. This comes in
|
||||
three flavors, as indicated by the operator between the target and the
|
||||
source. <literal>:</literal> gives a straight time-wise dependency
|
||||
(if the target is older than the source, the target is out-of-date),
|
||||
while <literal>!</literal> provides simply an ordering and always
|
||||
considers the target out-of-date. <literal>::</literal> is much like
|
||||
<literal>:</literal>, save it creates multiple instances of a target
|
||||
each of which depends on its own list of sources.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>dynamic source</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>This refers to a source that has a local variable invocation in
|
||||
it. It allows a single dependency line to specify a different source
|
||||
for each target on the line.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>global variable</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Any variable defined in a makefile. Takes precedence over
|
||||
variables defined in the environment, but not over command-line or
|
||||
local variables.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>input graph</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>What <application>PMake</application> constructs from a makefile.
|
||||
Consists of nodes made of the targets in the makefile, and the links
|
||||
between them (the dependencies). The links are directed (from source
|
||||
to target) and there may not be any cycles (loops) in the graph.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>local variable</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A variable defined by <application>PMake</application> visible
|
||||
only in a target's shell script.
|
||||
There are seven local variables, not all of which are defined for
|
||||
every target: <varname>.TARGET</varname>, <varname>.ALLSRC</varname>,
|
||||
<varname>.OODATE</varname>, <varname>.PREFIX</varname>,
|
||||
<varname>.IMPSRC</varname>, <varname>.ARCHIVE</varname>, and
|
||||
<varname>.MEMBER</varname>.
|
||||
<varname>.TARGET</varname>, <varname>.PREFIX</varname>,
|
||||
<varname>.ARCHIVE</varname>, and <varname>.MEMBER</varname>
|
||||
may be used on dependency lines to create
|
||||
<quote>dynamic sources</quote>.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>makefile</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A file that describes how a system is built. If you do not know
|
||||
what it is after reading this tutorial…</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>modifier</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A letter, following a colon, used to alter how a variable is
|
||||
expanded. It has no effect on the variable itself.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>operator</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>What separates a source from a target (on a dependency line) and
|
||||
specifies the relationship between the two. There are three:
|
||||
<literal>:</literal>, <literal>::</literal>,
|
||||
and <literal>!</literal>.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>search path</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A list of directories in which a file should be sought.
|
||||
<application>PMake</application>'s view of the contents of directories
|
||||
in a search path does not change once the makefile has been read.
|
||||
A file is sought on a search path only if it is exclusively a
|
||||
source.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>shell</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A program to which commands are passed in order to create
|
||||
targets.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>source</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Anything to the right of an operator on a dependency line.
|
||||
Targets on the dependency line are usually created
|
||||
from the sources.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>special target</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A target that causes <application>PMake</application> to do
|
||||
special things when it is encountered.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>suffix</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The tail end of a file name. Usually begins with a period, like
|
||||
<filename>.c</filename> or <filename>.ms</filename>.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>target</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A word to the left of the operator on a dependency line.
|
||||
More generally, any file that <application>PMake</application> might
|
||||
create. A file may be (and often is) both a target and a source (what
|
||||
it is depends on how <application>PMake</application> is looking at it
|
||||
at the time – sort of like the wave/particle duality of light,
|
||||
you know).</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>transformation rule</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A special construct in a makefile that specifies how to create a
|
||||
file of one type from a file of another, as indicated by their
|
||||
suffixes.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>variable expansion</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The process of substituting the value of a variable for a
|
||||
reference to it. Expansion may be altered by means of modifiers.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>variable</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A place in which to store text that may be retrieved later.
|
||||
Also used to define the local environment.
|
||||
Conditionals exist that test whether a variable is defined or not.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossary>
|
||||
|
|
@ -1,943 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
$FreeBSD$
|
||||
-->
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="gods">
|
||||
<title>PMake for Gods</title>
|
||||
|
||||
<para>This chapter is devoted to those facilities in
|
||||
<application>PMake</application> that allow you to do a great deal
|
||||
in a makefile with very little work, as well as do some things you
|
||||
could not do in <application>Make</application> without a great
|
||||
deal of work (and perhaps the use of other programs). The problem
|
||||
with these features, is they must be handled with care, or you
|
||||
will end up with a mess.</para>
|
||||
|
||||
<para>Once more, I assume a greater familiarity with &unix; or Sprite
|
||||
than I did in the previous two chapters.</para>
|
||||
|
||||
<section xml:id="searchpaths">
|
||||
<title>Search Paths</title>
|
||||
|
||||
<para><application>PMake</application> supports the dispersal of
|
||||
files into multiple directories by allowing you to specify
|
||||
places to look for sources with <buildtarget>.PATH</buildtarget>
|
||||
targets in the makefile. The directories you give as sources
|
||||
for these targets make up a <quote>search path</quote>. Only
|
||||
those files used exclusively as sources are actually sought on a
|
||||
search path, the assumption being that anything listed as a
|
||||
target in the makefile can be created by the makefile and thus
|
||||
should be in the current directory.</para>
|
||||
|
||||
<para>There are two types of search paths in
|
||||
<application>PMake</application>: one is used for all types of
|
||||
files (including included makefiles) and is specified with a
|
||||
plain <buildtarget>.PATH</buildtarget> target (e.g. <literal>.PATH
|
||||
: RCS</literal>), while the other is specific to a certain
|
||||
type of file, as indicated by the file's suffix. A specific
|
||||
search path is indicated by immediately following the
|
||||
<buildtarget>.PATH</buildtarget> with the suffix of the file. For
|
||||
instance:</para>
|
||||
|
||||
<programlisting>.PATH.h : /sprite/lib/include /sprite/att/lib/include</programlisting>
|
||||
|
||||
<para>would tell <application>PMake</application> to look in the
|
||||
directories <filename>/sprite/lib/include</filename> and
|
||||
<filename>/sprite/att/lib/include</filename> for any
|
||||
files whose suffix is <filename>.h</filename>.</para>
|
||||
|
||||
<para>The current directory is always consulted first to see if a
|
||||
file exists. Only if it cannot be found there are the
|
||||
directories in the specific search path, followed by those in
|
||||
the general search path, consulted.</para>
|
||||
|
||||
<para>A search path is also used when expanding wildcard
|
||||
characters. If the pattern has a recognizable suffix on it,
|
||||
the path for that suffix will be used for the expansion.
|
||||
Otherwise the default search path is employed.</para>
|
||||
|
||||
<para>When a file is found in some directory other than the
|
||||
current one, all local variables that would have contained the
|
||||
target's name (<varname>.ALLSRC</varname>, and
|
||||
<varname>.IMPSRC</varname>) will instead contain
|
||||
the path to the file, as found by
|
||||
<application>PMake</application>.
|
||||
Thus if you have a file <filename>../lib/mumble.c</filename>
|
||||
and a makefile like this:</para>
|
||||
|
||||
<programlisting>.PATH.c : ../lib
|
||||
mumble : mumble.c
|
||||
$(CC) -o $(.TARGET) $(.ALLSRC)</programlisting>
|
||||
|
||||
<para>the command executed to create mumble would be
|
||||
<command>cc -o mumble ../lib/mumble.c.</command>
|
||||
(as an aside, the command in this case is not strictly
|
||||
necessary, since it will be found using transformation rules
|
||||
if it is not given. This is because <filename>.out</filename>
|
||||
is the null suffix by default and a transformation exists
|
||||
from <filename>.c</filename> to
|
||||
<filename>.out</filename>. Just thought I would throw that in).
|
||||
If a file exists in two directories on the same search path,
|
||||
the file in the first directory on the path will be the one
|
||||
<application>PMake</application> uses. So if you have
|
||||
a large system spread over many directories, it would
|
||||
behoove you to follow a naming convention that avoids such
|
||||
conflicts.</para>
|
||||
|
||||
<para>Something you should know about the way search paths are
|
||||
implemented is that each directory is read, and its contents
|
||||
cached, exactly once – when it is first encountered
|
||||
– so any changes to the directories while
|
||||
<application>PMake</application> is running will not be noted
|
||||
when searching for implicit sources, nor will they be found when
|
||||
<application>PMake</application> attempts to discover when the
|
||||
file was last modified, unless the file was created in the
|
||||
current directory. While people have suggested that
|
||||
<application>PMake</application> should read the directories
|
||||
each time, my experience suggests that the caching seldom causes
|
||||
problems. In addition, not caching the directories slows things
|
||||
down enormously because of <application>PMake</application>'s attempts
|
||||
to apply transformation rules through non-existent files – the
|
||||
number of extra file-system searches is truly staggering,
|
||||
especially if many files without suffixes are used and the null
|
||||
suffix is not changed from <filename>.out</filename>.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="archivesandlibraries">
|
||||
<title>Archives and Libraries</title>
|
||||
|
||||
<para>&unix; and Sprite allow you to merge files into an archive
|
||||
using the <command>ar</command> command. Further, if the files
|
||||
are relocatable object files, you can run
|
||||
<application>ranlib</application> on the archive and get
|
||||
yourself a library that you can link into any program you want.
|
||||
The main problem with archives is they double the space you need
|
||||
to store the archived files, since there is one copy in the
|
||||
archive and one copy out by itself. The problem with libraries
|
||||
is you usually think of them as <option>-lm</option> rather
|
||||
than <filename>/usr/lib/libm.a</filename> and the linker thinks
|
||||
they are out-of-date if you so much as look at them.</para>
|
||||
|
||||
<para><application>PMake</application> solves the problem with
|
||||
archives by allowing you to tell it to examine the files in the
|
||||
archives (so you can remove the individual files without having
|
||||
to regenerate them later). To handle the problem with
|
||||
libraries, <application>PMake</application> adds an additional
|
||||
way of deciding if a library is out-of-date: if the table of
|
||||
contents is older than the library, or is missing, the library
|
||||
is out-of-date.</para>
|
||||
|
||||
<para>A library is any target that looks like <option>-lname</option>
|
||||
or that ends in a suffix that was marked as a library using the
|
||||
<buildtarget>.LIBS</buildtarget> target. <filename>.a</filename>
|
||||
is so marked in the system makefile. Members of an archive are
|
||||
specified as <literal>archive(member[member...])</literal>.
|
||||
Thus <literal>libdix.a(window.o)</literal> specifies the
|
||||
file <filename>window.o</filename> in the archive
|
||||
<filename>libdix.a</filename>. You may also use
|
||||
wildcards to specify the members of the archive. Just
|
||||
remember that most the wildcard characters will only find
|
||||
existing files. A file that is a member of an archive is
|
||||
treated specially. If the file does not exist, but it is
|
||||
in the archive, the modification time recorded in the
|
||||
archive is used for the file when determining if the file
|
||||
is out-of-date. When figuring out how to make an archived
|
||||
member target (not the file itself, but the file in the
|
||||
archive – the archive(member) target), special care
|
||||
is taken with the transformation rules, as follows:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>archive(member) is made to depend on member.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The transformation from the member's suffix to the
|
||||
archive's suffix is applied to the archive(member) target.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The archive(member)'s <varname>.TARGET</varname>
|
||||
variable is set to the name of the member if member is
|
||||
actually a target, or the path to the member file if
|
||||
member is only a source.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The <varname>.ARCHIVE</varname> variable for the
|
||||
archive(member) target is set to the name of the
|
||||
archive.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The <varname>.MEMBER</varname> variable is set to the
|
||||
actual string inside the parentheses. In most cases,
|
||||
this will be the same as the <varname>.TARGET</varname>
|
||||
variable.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The archive(member)'s place in the local variables of
|
||||
the targets that depend on it is taken by the value of its
|
||||
<varname>.TARGET</varname> variable.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Thus, a program library could be created with the following
|
||||
makefile:</para>
|
||||
|
||||
<programlisting>.o.a :
|
||||
...
|
||||
rm -f $(.TARGET:T)
|
||||
OBJS = obj1.o obj2.o obj3.o
|
||||
libprog.a : libprog.a($(OBJS))
|
||||
ar cru $(.TARGET) $(.OODATE)
|
||||
ranlib $(.TARGET)</programlisting>
|
||||
|
||||
<para>This will cause the three object files to be compiled (if
|
||||
the corresponding source files were modified after the object
|
||||
file or, if that does not exist, the archived object file), the
|
||||
out-of-date ones archived in <filename>libprog.a</filename>, a
|
||||
table of contents placed in the archive and the newly-archived
|
||||
object files to be removed.</para>
|
||||
|
||||
<para>All this is used in the <filename>makelib.mk</filename> system
|
||||
makefile to create a single library with ease. This makefile looks
|
||||
like this:</para>
|
||||
|
||||
<programlisting>#
|
||||
# Rules for making libraries. The object files that make up the library
|
||||
# are removed once they are archived.
|
||||
#
|
||||
# To make several libraries in parallel, you should define the variable
|
||||
# "many_libraries". This will serialize the invocations of ranlib.
|
||||
#
|
||||
# To use, do something like this:
|
||||
#
|
||||
# OBJECTS = <files in the library>
|
||||
#
|
||||
# fish.a: fish.a($(OBJECTS)) MAKELIB
|
||||
#
|
||||
#
|
||||
|
||||
#ifndef _MAKELIB_MK
|
||||
_MAKELIB_MK =
|
||||
|
||||
#include <po.mk>
|
||||
|
||||
.po.a .o.a :
|
||||
...
|
||||
rm -f $(.MEMBER)
|
||||
|
||||
ARFLAGS ?= crl
|
||||
|
||||
#
|
||||
# Re-archive the out-of-date members and recreate the library's table of
|
||||
# contents using ranlib. If many_libraries is defined, put the ranlib
|
||||
# off til the end so many libraries can be made at once.
|
||||
#
|
||||
MAKELIB : .USE .PRECIOUS
|
||||
ar $(ARFLAGS) $(.TARGET) $(.OODATE)
|
||||
#ifndef no_ranlib
|
||||
# ifdef many_libraries
|
||||
...
|
||||
# endif many_libraries
|
||||
ranlib $(.TARGET)
|
||||
#endif no_ranlib
|
||||
|
||||
#endif _MAKELIB_MK</programlisting>
|
||||
</section>
|
||||
|
||||
<section xml:id="condition">
|
||||
<title>On the Condition...</title>
|
||||
|
||||
<para>Like the C compiler before it, <application>PMake</application>
|
||||
allows you to configure the makefile, based on the current
|
||||
environment, using conditional statements. A conditional looks like
|
||||
this:</para>
|
||||
|
||||
<programlisting>#if boolean expression
|
||||
lines
|
||||
#elif another boolean expression
|
||||
more lines
|
||||
#else
|
||||
still more lines
|
||||
#endif</programlisting>
|
||||
|
||||
<para>They may be nested to a maximum depth of 30 and may occur
|
||||
anywhere (except in a comment, of course). The
|
||||
<literal>#</literal> must the very first character on the
|
||||
line.</para>
|
||||
|
||||
<para>Each boolean expression is made up of terms that look
|
||||
like function calls, the standard C boolean operators
|
||||
<literal>&&</literal>, <literal>||</literal>, and
|
||||
<literal>!</literal>, and the standard relational operators
|
||||
<literal>==</literal>, <literal>!=</literal>, <literal>></literal>,
|
||||
<literal>>=</literal>, <literal><</literal>, and
|
||||
<literal><=</literal>, with <literal>==</literal> and
|
||||
<literal>!=</literal> being overloaded to allow string
|
||||
comparisons as well. <literal>&&</literal> represents logical
|
||||
AND; <literal>||</literal> is logical OR and <literal>!</literal>
|
||||
is logical NOT. The arithmetic and string operators take
|
||||
precedence over all three of these operators, while NOT
|
||||
takes precedence over AND, which takes precedence over OR.
|
||||
This precedence may be overridden with parentheses, and an
|
||||
expression may be parenthesized to your heart's content.
|
||||
Each term looks like a call on one of four functions:</para>
|
||||
|
||||
<informaltable frame="none">
|
||||
<tgroup cols="2">
|
||||
<colspec colwidth="1*"/>
|
||||
<colspec colwidth="10*"/>
|
||||
|
||||
<tbody>
|
||||
<row valign="top">
|
||||
<entry><literal>make</literal></entry>
|
||||
|
||||
<entry>The syntax is make(target) where target is
|
||||
a target in the makefile. This is true if the
|
||||
given target was specified on the command line, or
|
||||
as the source for a <buildtarget>.MAIN</buildtarget>
|
||||
target (note that the sources for
|
||||
<buildtarget>.MAIN</buildtarget> are only used if no
|
||||
targets were given on the command
|
||||
line).</entry>
|
||||
</row>
|
||||
|
||||
<row valign="top">
|
||||
<entry><literal>defined</literal></entry>
|
||||
|
||||
<entry>The syntax is
|
||||
<literal>defined(variable)</literal> and is true
|
||||
if variable is defined. Certain variables are
|
||||
defined in the system makefile that identify the
|
||||
system on which <application>PMake</application>
|
||||
is being run.</entry>
|
||||
</row>
|
||||
|
||||
<row valign="top">
|
||||
<entry><literal>exists</literal></entry>
|
||||
|
||||
<entry>The syntax is
|
||||
<literal>exists(file)</literal> and is true if the
|
||||
file can be found on the global search path (i.e.
|
||||
that defined by <varname>.PATH</varname> targets, not by
|
||||
<buildtarget>.PATH<replaceable>suffix</replaceable></buildtarget>
|
||||
targets).</entry>
|
||||
</row>
|
||||
|
||||
<row valign="top">
|
||||
<entry><literal>empty</literal></entry>
|
||||
|
||||
<entry>This syntax is much like the others, except
|
||||
the string inside the parentheses is of the same
|
||||
form as you would put between parentheses when
|
||||
expanding a variable, complete with modifiers and
|
||||
everything. The function returns true if the
|
||||
resulting string is empty. An undefined
|
||||
variable in this context will cause at the very
|
||||
least a warning message about a malformed
|
||||
conditional, and at the worst will cause the process
|
||||
to stop once it has read the makefile. If you want
|
||||
to check for a variable being defined or empty,
|
||||
use the expression:
|
||||
<literal>!defined(var) || empty(var)</literal>
|
||||
as the definition of <literal>||</literal> will
|
||||
prevent the <literal>empty()</literal> from being
|
||||
evaluated and causing an error, if the variable
|
||||
is undefined. This can be used to see if a
|
||||
variable contains a given word, for example:
|
||||
<literal>#if !empty(var:Mword)</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>The arithmetic and string operators may only be used to test
|
||||
the value of a variable. The lefthand side must contain the
|
||||
variable expansion, while the righthand side contains either
|
||||
a string, enclosed in double-quotes, or a number. The
|
||||
standard C numeric conventions (except for specifying an octal
|
||||
number) apply to both sides. E.g.:</para>
|
||||
|
||||
<programlisting>#if $(OS) == 4.3
|
||||
|
||||
#if $(MACHINE) == "sun3"
|
||||
|
||||
#if $(LOAD_ADDR) > 0xc000</programlisting>
|
||||
|
||||
<para>are all valid conditionals. In addition, the numeric value
|
||||
of a variable can be tested as a boolean as follows:</para>
|
||||
|
||||
<programlisting>#if $(LOAD)</programlisting>
|
||||
|
||||
<para>would see if <literal>LOAD</literal> contains a
|
||||
non-zero value and:</para>
|
||||
|
||||
<programlisting>#if !$(LOAD)</programlisting>
|
||||
|
||||
<para>would test if <literal>LOAD</literal> contains a
|
||||
zero value.</para>
|
||||
|
||||
<para>In addition to the bare <literal>#if</literal>, there are other
|
||||
forms that apply one of the first two functions to each term.
|
||||
They are as follows:</para>
|
||||
|
||||
<informaltable frame="none">
|
||||
<tgroup cols="2">
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>ifdef</literal></entry>
|
||||
|
||||
<entry><literal>defined</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>ifndef</literal></entry>
|
||||
|
||||
<entry><literal>!defined</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>ifmake</literal></entry>
|
||||
|
||||
<entry><literal>make</literal></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><literal>ifnmake</literal></entry>
|
||||
|
||||
<entry><literal>!make</literal></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>There are also the <quote><literal>else
|
||||
if</literal></quote> forms: <literal>elif</literal>,
|
||||
<literal>elifdef</literal>, <literal>elifndef</literal>,
|
||||
<literal>elifmake</literal>, and <literal>elifnmake</literal>.</para>
|
||||
|
||||
<para>For instance, if you wish to create two versions of a
|
||||
program, one of which is optimized (the production version) and
|
||||
the other of which is for debugging (has symbols for dbx),
|
||||
you have two choices: you can create two makefiles, one of
|
||||
which uses the <option>-g</option> flag for the compilation,
|
||||
while the other uses the <option>-O</option> flag, or you
|
||||
can use another target (call it debug) to create the debug
|
||||
version. The construct below will take care of this for you.
|
||||
I have also made it so defining the variable
|
||||
<envar>DEBUG</envar> (say with <command>pmake -D DEBUG</command>)
|
||||
will also cause the debug version to be made.</para>
|
||||
|
||||
<programlisting>#if defined(DEBUG) || make(debug)
|
||||
CFLAGS += -g
|
||||
#else
|
||||
CFLAGS += -O
|
||||
#endif</programlisting>
|
||||
|
||||
<para>There are, of course, problems with this approach. The most
|
||||
glaring annoyance is that if you want to go from making a
|
||||
debug version to making a production version, you have to
|
||||
remove all the object files, or you will get some optimized
|
||||
and some debug versions in the same program. Another
|
||||
annoyance is you have to be careful not to make two targets that
|
||||
<quote>conflict</quote> because of some conditionals in the makefile.
|
||||
For instance:</para>
|
||||
|
||||
<programlisting>#if make(print)
|
||||
FORMATTER = ditroff -Plaser_printer
|
||||
#endif
|
||||
#if make(draft)
|
||||
FORMATTER = nroff -Pdot_matrix_printer
|
||||
#endif</programlisting>
|
||||
|
||||
<para>would wreak havoc if you tried <command>pmake draft print</command>
|
||||
since you would use the same formatter for each target. As I said,
|
||||
this all gets somewhat complicated.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="ashell">
|
||||
<title xml:id="ashelltitle">A Shell is a Shell is a Shell</title>
|
||||
|
||||
<para>In normal operation, the Bourne Shell (better known
|
||||
as <application>sh</application>) is used to execute the
|
||||
commands to re-create targets. <application>PMake</application>
|
||||
also allows you to specify a different shell for it to use when
|
||||
executing these commands. There are several things
|
||||
<application>PMake</application> must know about
|
||||
the shell you wish to use. These things are specified as the
|
||||
sources for the <buildtarget>.SHELL</buildtarget> target by
|
||||
keyword, as follows:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>path=path</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para><application>PMake</application> needs to know where
|
||||
the shell actually resides, so it can execute it. If
|
||||
you specify this and nothing else,
|
||||
<application>PMake</application> will use the last
|
||||
component of the path and look in its table of the
|
||||
shells it knows and use the specification it finds, if
|
||||
any. Use this if you just want to use a different
|
||||
version of the <application>Bourne</application> or
|
||||
<application>C Shell</application> (yes,
|
||||
<application>PMake</application> knows how to use the
|
||||
<application>C Shell</application> too).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>name=name</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This is the name by which the shell is to be
|
||||
known. It is a single word and, if no other keywords
|
||||
are specified (other than path), it is the name by
|
||||
which <application>PMake</application> attempts to find
|
||||
a specification for it (as mentioned above). You
|
||||
can use this if you would just rather use the C Shell
|
||||
than the <application>Bourne Shell</application>
|
||||
(<literal>.SHELL: name=csh</literal> will do it).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>quiet=echo-off</literal> command</term>
|
||||
|
||||
<listitem>
|
||||
<para>As mentioned before, <application>PMake</application>
|
||||
actually controls whether commands are printed by
|
||||
introducing commands into the shell's input stream.
|
||||
This keyword, and the next two, control what those commands
|
||||
are. The <literal>quiet</literal> keyword is the command
|
||||
used to turn echoing off. Once it is turned off, echoing is
|
||||
expected to remain off until the <literal>echo-on</literal>
|
||||
command is given.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>echo=echo-on</literal> command</term>
|
||||
|
||||
<listitem>
|
||||
<para>The command <application>PMake</application>
|
||||
should give to turn echoing back on again.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>filter=printed echo-off</literal> command</term>
|
||||
|
||||
<listitem>
|
||||
<para>Many shells will echo the
|
||||
<literal>echo-off</literal> command when it is given.
|
||||
This keyword tells <application>PMake</application> in what
|
||||
format the shell actually prints the <literal>echo-off</literal>
|
||||
command. Wherever <application>PMake</application>
|
||||
sees this string in the shell's output, it will
|
||||
delete it and any following whitespace, up to and
|
||||
including the next newline. See the example at the
|
||||
end of this section for more details.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>echoFlag=flag</literal> to turn echoing on</term>
|
||||
|
||||
<listitem>
|
||||
<para>Unless a target has been marked
|
||||
<literal>.SILENT</literal>, <application>PMake</application>
|
||||
wants to start the shell running with echoing on. To do
|
||||
this, it passes this flag to the shell as one of its
|
||||
arguments. If either this or the next flag begins with a
|
||||
<literal>-</literal>, the flags will be passed to the
|
||||
shell as separate arguments. Otherwise, the two will
|
||||
be concatenated (if they are used at the same time, of
|
||||
course).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>errFlag=flag</literal> to turn error checking on</term>
|
||||
|
||||
<listitem>
|
||||
<para>Likewise, unless a target is marked
|
||||
<literal>.IGNORE</literal>,
|
||||
<application>PMake</application> wishes error-checking
|
||||
to be on from the very start. To this end, it will pass
|
||||
this flag to the shell as an argument. The same
|
||||
rules for an initial <literal>-</literal> apply as for
|
||||
the <literal>echoFlag</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>check=command</literal> to turn error checking on</term>
|
||||
|
||||
<listitem>
|
||||
<para>Just as for echo-control, error-control is achieved
|
||||
by inserting commands into the shell's input stream.
|
||||
This is the command to make the shell check for errors.
|
||||
It also serves another purpose if the shell does not
|
||||
have error-control as commands, but I will get into that
|
||||
in a minute. Again, once error checking has been turned
|
||||
on, it is expected to remain on until it is turned off
|
||||
again.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>ignore=command</literal>to turn error checking off</term>
|
||||
|
||||
<listitem>
|
||||
<para>This is the command <application>PMake</application>
|
||||
uses to turn error checking off. It has another use if
|
||||
the shell does not do errorcontrol, but I will tell you
|
||||
about that...now.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>hasErrCtl=yes</literal> or <literal>no</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This takes a value that is either
|
||||
<literal>yes</literal> or <literal>no</literal>. Now
|
||||
you might think that the existence of the check and
|
||||
ignore keywords would be enough to tell
|
||||
<application>PMake</application> if the shell can do
|
||||
error-control, but you would be wrong. If
|
||||
<literal>hasErrCtl</literal> is <literal>yes</literal>,
|
||||
<application>PMake</application> uses the check and
|
||||
ignore commands in a straight-forward manner. If this
|
||||
is no, however, their use is rather different. In this
|
||||
case, the check command is used as a template, in which
|
||||
the string <literal>%s</literal> is replaced by the
|
||||
command that is about to be executed, to produce a
|
||||
command for the shell that will echo the command to be
|
||||
executed. The ignore command is also used as a template,
|
||||
again with <literal>%s</literal> replaced by the command
|
||||
to be executed, to produce a command that will
|
||||
execute the command to be executed and ignore any error
|
||||
it returns. When these strings are used as templates,
|
||||
you must provide newline(s) (<literal>\n</literal>) in
|
||||
the appropriate place(s).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>The strings that follow these keywords may be enclosed in
|
||||
single or double quotes (the quotes will be stripped off) and
|
||||
may contain the usual C backslash-characters
|
||||
(<literal>\n</literal> is newline, <literal>\r</literal> is
|
||||
return, <literal>\b</literal> is backspace,
|
||||
<literal>\'</literal> escapes a single-quote inside
|
||||
single-quotes, <literal>\"</literal> escapes a double-quote
|
||||
inside double-quotes). Now for an example.</para>
|
||||
|
||||
<para>This is actually the contents of the <shx.mk> system
|
||||
makefile, and causes <application>PMake</application>
|
||||
to use the <application>Bourne Shell</application> in such a way
|
||||
that each command is printed as it is executed. That is, if
|
||||
more than one command is given on a line, each will be
|
||||
printed separately. Similarly, each time the body of a loop
|
||||
is executed, the commands within that loop will be printed,
|
||||
etc. The specification runs like this:</para>
|
||||
|
||||
<programlisting>#
|
||||
# This is a shell specification to have the Bourne shell echo
|
||||
# the commands just before executing them, rather than when it reads
|
||||
# them. Useful if you want to see how variables are being expanded, etc.
|
||||
#
|
||||
.SHELL : path=/bin/sh \
|
||||
quiet="set -" \
|
||||
echo="set -x" \
|
||||
filter="+ set - " \
|
||||
echoFlag=x \
|
||||
errFlag=e \
|
||||
hasErrCtl=yes \
|
||||
check="set -e" \
|
||||
ignore="set +e"</programlisting>
|
||||
|
||||
<para>It tells <application>PMake</application> the following:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The shell is located in the file
|
||||
<filename>/bin/sh</filename>. It need not tell
|
||||
<application>PMake</application> that the name of the
|
||||
shell is sh as <application>PMake</application> can
|
||||
figure that out for itself (it is the last component of the
|
||||
path).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The command to stop echoing is set <literal>-</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The command to start echoing is set <option>-x</option>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>When the echo off command is executed, the shell
|
||||
will print <literal>+</literal> set <literal>-</literal>
|
||||
(The <literal>+</literal> comes from using the
|
||||
<option>-x</option> flag (rather than the
|
||||
<option>-v</option> flag <application>PMake</application>
|
||||
usually uses)). <application>PMake</application> will
|
||||
remove all occurrences of this string from the output, so
|
||||
you do not notice extra commands you did not put
|
||||
there.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The flag the <application>Bourne Shell</application>
|
||||
will take to start echoing in this way is the
|
||||
<option>-x</option> flag. The <application>Bourne
|
||||
Shell</application> will only take its flag arguments
|
||||
concatenated as its first argument, so neither this nor
|
||||
the errFlag specification begins with a
|
||||
<literal>-</literal>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The flag to use to turn error-checking on from the
|
||||
start is <option>-e</option>.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The shell can turn error-checking on and off, and
|
||||
the commands to do so are <literal>set +e</literal> and
|
||||
<literal>set -e</literal>, respectively.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>I should note that this specification is for
|
||||
<application>Bourne Shells</application>
|
||||
that are not part of Berkeley &unix;, as shells from Berkeley
|
||||
do not do error control. You can get a similar effect,
|
||||
however, by changing the last three lines to be:</para>
|
||||
|
||||
<programlisting>hasErrCtl=no \
|
||||
check="echo \"+ %s\"\n" \
|
||||
ignore="sh -c '%s || exit 0\n"</programlisting>
|
||||
|
||||
<para>This will cause <application>PMake</application> to execute
|
||||
the two commands:</para>
|
||||
|
||||
<programlisting>echo "+ cmd"
|
||||
sh -c 'cmd || true'</programlisting>
|
||||
|
||||
<para>for each command for which errors are to be ignored. (In
|
||||
case you are wondering, the thing for ignore tells the shell
|
||||
to execute another shell without error checking on and
|
||||
always exit 0, since the ||<literal/> causes the
|
||||
exit 0 to be executed only if the first command exited
|
||||
non-zero, and if the first command exited zero, the shell
|
||||
will also exit zero, since that is the last command it
|
||||
executed).</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="compatibility">
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>There are three (well, 3 1/2) levels of
|
||||
backwards-compatibility built into
|
||||
<application>PMake</application>. Most makefiles will need none
|
||||
at all. Some may need a little bit of work to operate correctly
|
||||
when run in parallel. Each level encompasses the previous
|
||||
levels (e.g. <option>-B</option> (one shell per command) implies
|
||||
<option>-V</option>). The three levels are described in the
|
||||
following three sections.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="defcon3">
|
||||
<title>DEFCON 3 – Variable Expansion</title>
|
||||
|
||||
<para>As noted before, <application>PMake</application> will not
|
||||
expand a variable unless it knows of a value for it. This can
|
||||
cause problems for makefiles that expect to leave variables
|
||||
undefined except in special circumstances (e.g. if more flags
|
||||
need to be passed to the C compiler or the output from a text
|
||||
processor should be sent to a different printer). If the
|
||||
variables are enclosed in curly braces
|
||||
(<literal>${PRINTER}</literal>), the shell will let them pass.
|
||||
If they are enclosed in parentheses, however, the shell will
|
||||
declare a syntax error and the make will come to a grinding
|
||||
halt.</para>
|
||||
|
||||
<para>You have two choices: change the makefile to define the
|
||||
variables (their values can be overridden on the command line,
|
||||
since that is where they would have been set if you used
|
||||
<application>Make</application>, anyway) or always give the
|
||||
<option>-V</option> flag (this can be done with the
|
||||
<buildtarget>.MAKEFLAGS</buildtarget> target, if you want).</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="defcon2">
|
||||
<title>DEFCON 2 – The Number of the Beast</title>
|
||||
|
||||
<para>Then there are the makefiles that expect certain commands,
|
||||
such as changing to a different directory, to not affect
|
||||
other commands in a target's creation script. You can solve
|
||||
this is either by going back to executing one shell per
|
||||
command (which is what the <option>-B</option> flag forces
|
||||
<application>PMake</application> to do), which
|
||||
slows the process down a good bit and requires you to use
|
||||
semicolons and escaped newlines for shell constructs, or by
|
||||
changing the makefile to execute the offending command(s) in
|
||||
a subshell (by placing the line inside parentheses), like
|
||||
so:</para>
|
||||
|
||||
<programlisting>install :: .MAKE
|
||||
(cd src; $(.PMAKE) install)
|
||||
(cd lib; $(.PMAKE) install)
|
||||
(cd man; $(.PMAKE) install)</programlisting>
|
||||
|
||||
<para>This will always execute the three makes (even if the
|
||||
<option>-n</option>
|
||||
flag was given) because of the combination of the
|
||||
<literal>::</literal>
|
||||
operator and the <literal>.MAKE</literal> attribute.
|
||||
Each command will change to the proper directory to perform
|
||||
the install, leaving the main shell in the directory in
|
||||
which it started.</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="defcon1">
|
||||
<title>DEFCON 1 – Imitation is the Not the Highest Form of
|
||||
Flattery</title>
|
||||
|
||||
<para>The final category of makefile is the one where every command
|
||||
requires input, the dependencies are incompletely specified, or
|
||||
you simply cannot create more than one target at a time, as
|
||||
mentioned earlier. In addition, you may not have the time or
|
||||
desire to upgrade the makefile to run smoothly with
|
||||
<application>PMake</application>. If you are the conservative
|
||||
sort, this is the compatibility mode for you. It is entered
|
||||
either by giving <application>PMake</application> the
|
||||
<option>-M</option> flag (for <application>Make</application>),
|
||||
or by executing <application>PMake</application> as
|
||||
<command>make.</command> In either case,
|
||||
<application>PMake</application> performs things exactly like
|
||||
<application>Make</application> (while still supporting most
|
||||
of the nice new features <application>PMake</application>
|
||||
provides). This includes:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>No parallel execution.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Targets are made in the exact order specified by the
|
||||
makefile. The sources for each target are made in strict
|
||||
left-to-right order, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A single Bourne shell is used to execute each command,
|
||||
thus the shell's <varname>$$</varname> variable is
|
||||
useless, changing directories does not work across command
|
||||
lines, etc.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>If no special characters exist in a command line,
|
||||
<application>PMake</application> will break the command
|
||||
into words itself and execute the command directly,
|
||||
without executing a shell first. The characters that
|
||||
cause <application>PMake</application> to execute a shell
|
||||
are: <literal>#</literal>, <literal>=</literal>,
|
||||
<literal>|</literal>, <literal>^</literal>,
|
||||
<literal>(</literal>, <literal>)</literal>,
|
||||
<literal>{</literal>, <literal>}</literal>,
|
||||
<literal>;</literal>, <literal>&</literal>,
|
||||
<literal>></literal>, <literal><</literal>,
|
||||
<literal>*</literal>, <literal>?</literal>,
|
||||
<literal>[</literal>, <literal>]</literal>,
|
||||
<literal>:</literal>, <literal>$</literal>,
|
||||
<literal>`</literal>, and <literal>\</literal>. You should
|
||||
notice that these are all the characters that are given
|
||||
special meaning by the shell (except <literal>'</literal>
|
||||
and <literal>,</literal> which
|
||||
<application>PMake</application> deals with all by its
|
||||
lonesome).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The use of the null suffix is turned off.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section xml:id="theway">
|
||||
<title>The Way Things Work</title>
|
||||
|
||||
<para>When <application>PMake</application> reads the makefile, it
|
||||
parses sources and targets into nodes in a graph. The graph is
|
||||
directed only in the sense that <application>PMake</application>
|
||||
knows which way is up. Each node contains not only links to all
|
||||
its parents and children (the nodes that depend on it and those
|
||||
on which it depends, respectively), but also a count of the
|
||||
number of its children that have already been processed.</para>
|
||||
|
||||
<para>The most important thing to know about how
|
||||
<application>PMake</application> uses this graph is that the
|
||||
traversal is breadth-first and occurs in two passes.</para>
|
||||
|
||||
<para>After <application>PMake</application> has parsed the
|
||||
makefile, it begins with the nodes the user has told it to make
|
||||
(either on the command line, or via a
|
||||
<buildtarget>.MAIN</buildtarget> target, or by the target being
|
||||
the first in the file not labeled with the
|
||||
<literal>.NOTMAIN</literal> attribute) placed in a queue. It
|
||||
continues to take the node off the front of the queue, mark it
|
||||
as something that needs to be made, pass the node to
|
||||
<literal>Suff_FindDeps</literal> (mentioned earlier) to find any
|
||||
implicit sources for the node, and place all the node's children
|
||||
that have yet to be marked at the end of the queue. If any of
|
||||
the children is a <buildtarget>.USE</buildtarget> rule, its
|
||||
attributes are applied to the parent, then its commands are
|
||||
appended to the parent's list of commands and its children are
|
||||
linked to its parent. The parent's unmade children counter is
|
||||
then decremented (since the <buildtarget>.USE</buildtarget> node
|
||||
has been processed). You will note that this allows a
|
||||
<buildtarget>.USE</buildtarget> node to have children that are
|
||||
<buildtarget>.USE</buildtarget> nodes and the rules will be
|
||||
applied in sequence. If the node has no children, it is placed
|
||||
at the end of another queue to be examined in the second pass.
|
||||
This process continues until the first queue is empty.</para>
|
||||
|
||||
<para>At this point, all the leaves of the graph are in the
|
||||
examination queue. <application>PMake</application> removes the
|
||||
node at the head of the queue and sees if it is out-of-date. If
|
||||
it is, it is passed to a function that will execute the commands
|
||||
for the node asynchronously. When the commands have completed,
|
||||
all the node's parents have their unmade children counter
|
||||
decremented and, if the counter is then 0, they are placed on
|
||||
the examination queue. Likewise, if the node is up-to-date.
|
||||
Only those parents that were marked on the downward pass are
|
||||
processed in this way. Thus <application>PMake</application>
|
||||
traverses the graph back up to the nodes the user instructed it
|
||||
to create. When the examination queue is empty and no shells
|
||||
are running to create a target, <application>PMake</application>
|
||||
is finished.</para>
|
||||
|
||||
<para>Once all targets have been processed,
|
||||
<application>PMake</application> executes the commands attached
|
||||
to the <buildtarget>.END</buildtarget> target, either explicitly
|
||||
or through the use of an ellipsis in a shell script. If there
|
||||
were no errors during the entire process but there are still
|
||||
some targets unmade (<application>PMake</application> keeps a
|
||||
running count of how many targets are left to be made), there is
|
||||
a cycle in the graph. <application>PMake</application> does a
|
||||
depth-first traversal of the graph to find all the targets that
|
||||
were not made and prints them out one by one.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
PMake - A Tutorial
|
||||
|
||||
$FreeBSD$
|
||||
-->
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para><application>PMake</application> is a program for creating other
|
||||
programs, or anything else you can think of for it to do. The basic idea
|
||||
behind <application>PMake</application> is that, for any given system, be
|
||||
it a program or a document or whatever, there will be some files that
|
||||
depend on the state of other files (on when they were last modified).
|
||||
<application>PMake</application> takes these dependencies, which you must
|
||||
specify, and uses them to build whatever it is you want it to
|
||||
build.</para>
|
||||
|
||||
<para><application>PMake</application> is almost fully-compatible with
|
||||
<application>Make</application>, with which you may already be familiar.
|
||||
<application>PMake</application>'s most important feature is its ability
|
||||
to run several different jobs at once, making the creation of systems
|
||||
considerably faster. It also has a great deal more functionality than
|
||||
<application>Make</application>.</para>
|
||||
|
||||
<para>This tutorial is divided into three main sections corresponding to
|
||||
basic, intermediate and advanced <application>PMake</application> usage.
|
||||
If you already know <application>Make</application> well, you will only
|
||||
need to skim <xref linkend="basics"/> (there are some aspects of
|
||||
<application>PMake</application> that I consider basic to its use that did
|
||||
not exist in <application>Make</application>).
|
||||
Things in <xref linkend="shortcuts"/> make life much easier, while those in
|
||||
<xref linkend="gods"/> are strictly for those who know what they are doing.
|
||||
<xref linkend="glossary"/> has definitions for the jargon I use and
|
||||
<xref linkend="answers"/> contains possible solutions to the problems
|
||||
presented throughout the tutorial.</para>
|
||||
</chapter>
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!--
|
||||
$FreeBSD$
|
||||
-->
|
||||
<legalnotice xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="legalnotice">
|
||||
<para>All rights reserved.</para>
|
||||
|
||||
<para>This code is derived from software contributed to Berkeley
|
||||
by Adam de Boor.</para>
|
||||
|
||||
<para>Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Neither the name of the University nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written
|
||||
permission.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<important>
|
||||
<para>THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.</para>
|
||||
</important>
|
||||
</legalnotice>
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue