PMAKE (1)
create programs in parallel
SYNOPSIS
pmake
[\c
-d
what\c
] [\c
-e\c
] [\c
-f
makefile\c
] [\c
-h\c
] [\c
-i\c
] [\c
-k\c
] [\c
-l\c
] [\c
-n\c
] [\c
-p
#\c
] [\c
-q\c
] [\c
-r\c
] [\c
-s\c
] [\c
-t\c
] [\c
-x\c
] [\c
-v\c
] [\c
-B\c
] [\c
-C\c
] [\c
-D
variable\c
] [\c
-I
directory\c
] [\c
-J
#\c
] [\c
-L
#\c
] [\c
-M\c
] [\c
-P\c
] [\c
-R
when\c
] [\c
-S\c
] [\c
-V\c
] [\c
-W\c
] [\c
-X\c
] [\c
-Z
c\c
] [\c
VAR1 = value1\c
] [\c
VAR2 = value2 ...\c
] [\c
targ1\c
] [\c
targ2 ...\c
]
-I directory
-d what
Specify what modules should print debugging information.
what
is a string of letters from the following set:
a
- archive searching,
c
- conditional evaluation,
d
- directory searching,
j
- job scheduling,
m
- make dependencies,
p
- makefile parsing,
q
- job queue maintenance,
r
- remote execution
s
- suffix processing,
t
- target list maintenance,
v
- variable assignments,
\e*
- all of the above.
-e ""
Specify that environment variables override macro assignments within
makefiles.
-f makefile
Specify a different makefile to read than the standard
``Makefile'' or ``makefile''. If
makefile
is "-", reads from standard input.
-h ""
Prints out help information.
-i ""
``Ignore errors'' -- ignore non-zero exit statuses of commands.
-k ""
``Keepgoing'' -- if an error is encountered,
keep working on those parts of the input graph that are not affected by the
error.
-l ""
PMake has the ability to lock a directory against other
people executing it in the same directory (by means of a file called
``LOCK.make'' that it creates and checks for in the directory). This
is a Good Thing because two people doing the same thing in the same place
can be disastrous for the final product (too many cooks and all that).
Whether this locking is the default is up to your system
administrator. If locking is on,
-l
will turn it off, and vice versa. Note that this locking will not
prevent you from invoking PMake twice in the same place -- if
you own the lock file, PMake will warn you about it but continue to execute.
-n ""
``No execute'' -- do not execute commands.
Just print the ones that would be executed.
-p "#"
Tell
if and when to print the input graph.
The number is the bitwise OR of the numbers 1 and 2 with 1 meaning to print the
graph before making anything and 2 meaning to print the graph after making
everything.
-q ""
``Query'' -- do not execute any commands.
Just exit 0 if the given target(s) is (are) up to date and exit non-zero
otherwise.
-r ""
``Remove built-in rules'' -- do not parse the built-in rules given in
the system makefile.
-s ""
``Silence'' -- do not echo commands as they are executed.
-t ""
``Touch targets'' -- rather than executing the commands to create a target,
just change its modification time so it appears up-to-date.
This is dangerous.
-x ""
``Export'' -- causes commands to be exported when in
Make-compatibility mode. Since exporting commands in this mode will
often take longer than running them on the local machine, exportation
is off by default and must be turned on using this flag.
-v ""
``System V'' -- invokes compatibility functions suitable for acting
like the System V version of Make. This implies
-B ,
and
-V
and turns off directory locking. Locking may be turned back on again
by giving the
-l
flag after
-v .
-B ""
``Backwards-compatible'' -- performs as much like Make as possible
(including executing a single shell per command and expanding
variables as Make did) while still performing in parallel.
-C ""
``Non-compatible'' -- turns off all compatibility specified up to the point at
which
-C
is encountered.
-D variable
Defines the given variable to be
1
in the global context.
-I directory
Specify another directory in which to look for #include'd makefiles.
This flag may be repeated as many times as necessary.
-J #
Specify the maximum number of jobs to run at once on all machines.
-L #
Specify the maximum number of jobs to run locally.
A negative argument sets a limits equal to the absolute value,
but also directs
to run jobs locally as long as the limit is not exceeded.
Usually
tries to export jobs before resorting to local execution.
-M ""
Be as much like Make as possible. No parallel execution. Old-style
variable expansion. One shell per command. Etc.
-P ""
``Don't use Pipes'' -- see the section on
OUTPUT .
-R when
``Recheck targets'' -- possible values are
always ,
never ,
and
locals
(default for NFS based systems where remote target updates are not
immediately visible locally).
-S ""
``Stop on error'' --
tells
to stop as soon as a command returns a non-zero exit status, overriding the
-k
option.
-V ""
``Do old-style variable expansion'' -- expands an unknown variable to
the empty string.
-W ""
Don't print warning messages.
-X ""
``No Export'' -- prohibits exportation. -x and -X should not be used
in the same command.
-Z c
Modifies makefile parsing to use
c
as the character introducing #include, conditional and other directives.
Could be set to `.' for 4.4BSD compatibility, or to some unlikely character
to disable directives altogether.
VAR=value ""
Set the value of the variable
VAR
to the given value.
This supersedes any value assigned to the variable in the makefile.
See
VARIABLES .
LOCAL NOTE
This version of
does
make (1)
compatible variable expansion (see
-V
option) by default.
This allows processing most standard makefiles without modification.
Beware of the way subshells are created, though, and use the
-B
option if full compatibility is an issue.
To process true Pmakefiles use the
-C
option.
DESCRIPTION
is a program designed to make the maintenance of other programs much
easier. Its input is a ``makefile'' that specifies which files depend
on which other files and what to do about files that are
``out-of-date.''
If you don't specify a makefile to read,
Makefile
and
makefile ,
in that order,
are looked for and read if they exist.
This manual page is meant to be a reference page only. For a more
thorough description of
please refer to
PMake -- A Tutorial\c
(available in this distribution).
There are four basic types of lines in a makefile:
File dependency specifications
Comments,
include statements and conditional directives
Any line may be continued over multiple lines by ending it with a backslash.
The backslash,
following newline and any initial whitespace on the following line are
compressed into a single space.
DEPENDENCY LINES
On a dependency line, there are targets, sources and an operator.
The targets ``depend'' on the sources and are usually created from them.
Any number of targets and sources may be specified on a dependency
line. All the targets in the line are made to depend on all the sources.
If you run out of room, use a backslash at the end of the line to
continue onto the next one.
Any file may be a target and any file may be a source, but the relationship
between them is determined by the ``operator''
that separates them. Three operators are defined:
A target on the line is considered ``out-of-date''
if any of its sources has been modified
more recently than the target. Sources for a target accumulate over
lines when this operator is used.
Targets will always be re-created, but this will not happen until all
of its sources have been examined and re-created, if necessary.
Sources accumulate over lines as for the colon.
Much like the colon, but acts like the ! operator if no sources are
specified. In addition sources do not accumulate over lines. Rather,
the commands associated with the line (see below) are executed only if
the target is out-of-date with respect to the sources on that line only.
In addition, the target will not be removed if
is interrupted, unlike for the other two operators.
For example:
a : a.o b.o c.o
b ! d.o e.o
c :: f.o
command1
a : g.o
b ! h.o
c ::
command2
specifies that a depends on a.o, b.o, c.o and g.o and will be remade
only if out-of-date with respect to these four files. b depends on
d.o, e.o and h.o and will always be remade, but only after these three
files have been remade. c will be remade with command1 if it is
out-of-date with respect to f.o, as for the colon operator, while
command2 will always be executed.
Targets and sources may also contain standard shell wildcard
characters (?, *, [ and {}), but the ?, *, [ and ] characters may only
be used in the final component of the target or source. If a target or
source contains only curly braces and no other wildcard characters, it
need not describe an existing file. Otherwise, only existing files
will be used. E.g. the pattern
{a,b,c}.o
will expand to
a.o b.o c.o
regardless of whether these three files exist, while
[abc].o
will only expand to this if all three files exist. The resulting
expansion is in directory order, not alphabetically sorted as in the shell.
COMMANDS
Each target has associated with it a sort of shell script made up of a
series of shell commands. The creation script for a target should
immediately follow the dependency line for that target.
Each of the commands in this script
must
be preceded by a tab character.
While any given target
may appear on more than one dependency line, only one of these dependency lines
may be followed by a creation script, unless the "::" operator is used.
One helpful feature of
is the ability to squirrel away commands for a target to be executed when
everything else has been done. To do this, make one of the commands
for the target be just ``...'' (an ellipsis) on a line by itself. The
ellipsis itself won't be executed, of course, but any commands in the
target's script that follow the ellipsis will be saved until
is done processing everything it needs to process.
If you were to say,
a.o : a.c
cc -c a.c
...
@echo "All done"
Then the command ``echo "All done"'' would execute once everything
else had finished. Note that this will only happen if ``a.o'' is found
to be out-of-date.
There is another way in which makefile shell commands differ from
regular shell commands, as illustrated in the above makefile scrap.
The first two characters after the initial tab (and any other
whitespace) are treated specially. If they are any combination of `@'
and `-', (``@'', ``@-'', ``-@'' or ``-''), they cause
to do different things.
In most cases, shell commands are printed to
the screen before they're actually executed. This is to keep you
informed of what's going on. If an `@' appears, however, this echoing
is suppressed. In the case of the echo command, above, this makes
sense. It would look silly to see
echo "All done"
All done
so
allows you to avoid that (this sort of echo control is
only available if you use the Bourne or C shells to execute your
commands, since the commands are echoed by the shell,
not by
).
The other special character is the `-'. Shell commands exit with a
certain ``exit status.'' Normally this status will be 0 if everything
went ok and non-zero if something went wrong. For this reason,
will consider an error to have occurred if one of the commands it
invokes returns a non-zero status. When it detects an error, its usual
action is to stop working, wait for everything in process to finish,
and exit with a non-zero status itself. This behavior can be altered,
however, by means of
-i
or
-k
arguments, or by placing a `-' at the
front of the command.
(Another quick note: the decision of whether to abort a target when
one of its shell commands returns non-zero is left to the shell that
is executing the commands. Some shells allow this ``error-checking''
to be switched on and off at will while others do not.)
VARIABLES
has the ability to save text in variables to be recalled later at your
convenience. Variables in
are used much like variables in
sh (1)
and, by tradition, consist of all upper-case letters.
They are assigned- and appended-to using lines of the form
VARIABLE = value
VARIABLE += value
respectively, while being conditionally assigned-to (if not already
defined) and assigned-to with expansion by lines of the form
VARIABLE ?= value
VARIABLE := value
Finally,
VARIABLE != command
will execute
command
using the prevailing
SHELL
and place the result in the given variable.
Newlines are converted to spaces before the assignment is made, and
a final newline is stripped.
can proceed to process the makefile.
Variables are expanded by enclosing the variable name in either
parentheses or curly braces and preceding the whole thing with a
dollar sign. E.g. to set the variable
CFLAGS
to the string ``-I/sprite/src/lib/libc -O'' you would place a line
CFLAGS = -I/sprite/src/lib/libc -O
in the makefile and use the word
$(CFLAGS)
wherever you would like the string ``-I/sprite/src/lib/libc -O'' to
appear. To pass a string of the form ``$(name)'' or
``${name}'' through to the shell (e.g. to tell it to substitute
one of its variables),
you can use ``$$(name)'' and ``$${name}'',
respectively,
or,
as long as the name is not a
variable,
you can just place the string in directly, as
will not expand a variable it doesn't know, unless it is given one of
the three compatibility flags
-V ,
-B ,
or
-M .
There are two distinct times at which variable substitution occurs:
When parsing a dependency line,
such substitution occurs immediately upon reading the line.
Thus all variables used in dependency lines must be defined before
they appear on any dependency line.
For variables that appear in shell commands,
variable substitution occurs when the command is processed,
i.e. when it is prepared to be passed to the shell or before being
squirreled away for later execution (qv. COMMANDS, above).
There are four different types of variables at which
will look when trying to expand any given variable.
They are (in order of decreasing precedence): (1) variables that are
defined specific to a certain target. These are the so-called
``local'' variables and will only be used when performing variable
substitution on the target's shell script and in dynamic sources (see below
for more details), (2) variables that were defined on the command line,
(3) variables defined in the makefile and (4) those defined in
's
environment, as passed by your login shell.
The
-e
option lets environment variables take precedence over Makefile definitions.
An important side effect of this searching order is that once you
define a variable on the command line, nothing in the makefile can
change it. Nothing.
Makefile variables that also exist in the environment have their changed
values re-exported to the environment of commands invoked by
.
An exception is the
SHELL
variable, which is never either imported nor exported.
As mentioned above,
each target has associated with it as many as seven ``local''
variables. Four of these variables are always set for every target
that must be re-created. Each local variable has a long, meaningful
name and a short, one-character name that exists for backwards-compatibility.
They are:
The list of sources for this target that were deemed out-of-date.
The list of all sources for this target.
The file prefix of the file, with the suffix stripped. This includes
any prepended directory names if VPATH search was required to locate the
file. If the file name has no known suffix it is used unchanged.
Three other ``local'' variables are set only for certain targets under
special circumstances. These are the ``.IMPSRC'', ``.ARCHIVE''
and ``.MEMBER'' variables. When
they are set, how they are used, and what their short forms are are detailed
in later sections.
In addition, for you System V fans, the six variables ``@F'', ``@D'',
``<F'', ``<D'', ``*F'', and ``*D'' are defined to be the same as for the
System V version of Make. If you don't know about these things, be glad.
Four of these local variables may be used in sources on dependency
lines. The variables expand to the proper value for each target on the
line. The variables are ``.TARGET'', ``.PREFIX'', ``.ARCHIVE'', and
``.MEMBER''.
In addition, certain variables are set by or have special meaning to
.
The
.PMAKE
variable is set to the name by which
was invoked, to allow recursive makes to use the same version,
whatever it may be.
All command-line flags given to
are stored in the
.MAKEFLAGS
variable just as they were given. This variable is also exported to
subshells as the
PMAKE
environment variable.
(For compatbility with other make programs, the variables
MAKE
and
MFLAGS
are synonyms for
.PMAKE
and
.MAKEFLAGS ,
respectively.
Also, the variable
MAKEFLAGS
contains a list of flag letters without hyphens or spaces.
It, too, can be used to provide default flags in the
environment, and is reset to contain that subset of
options that is portable among most Make versions:
-e ,
-i ,
-k ,
-n ,
-q ,
-r ,
-s ,
-S ,
and
-t .)
The
SHELL
variable is pre-set to the path of the default shell used for command
execution (the Bourne shell). It can be reset to select a different
shell, or undefined to revert to the default shell.
See the description of the
.SHELL
special target for more details.
The variable
.CURDIR
is set to the path of the directory in which
is executed.
This is especially useful in connection with the
MAKEOBJDIR
environment variable, which can be used to tell
to change to a directory relative to
$(.CURDIR)
and make targets there.
This feature is for compatibility with the 4.4BSD version of
and is mainly used to keep object files for several platforms
separate in a single source tree.
Variable expansion may be modified as for the C shell. A general
expansion specification looks like:
$(variable[:modifier[:...]])
Each modifier begins with a single character, thus:
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 "*"
means 0 or more characters of any sort; "?" is any single character;
"[abcd]" matches any single character that is either `a', `b', `c' or `d'
(there may be any number of characters between the brackets);
[0-9]
matches any single character that is between `0' and `9' (i.e. any
digit. This form may be freely mixed with the other bracket form), and
\e is used to escape any of the characters "*", "?", "[" or ":",
leaving them as regular characters to match themselves in a word.
This is identical to ":M" except it substitutes all words that don't
match the given pattern.
Causes the first occurrence of
search-string
in the variable to be replaced by
replacement-string ,
unless the "g"
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 "^",
the string must match starting at the beginning of the word. If
search-string
ends with a "$",
the string must match to the end of the word (these two may be
combined to force an exact match). If a backslash 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 "$",
not another dollar sign, as is usual.
Note that
search-string
is just a string, not a pattern, so none of the usual
regular-expression/wildcard characters has any special meaning save "^"
and "$".
In the replacement string,
the "&"
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.
Replaces each word in the variable expansion by its last
component (its ``tail'').
This is similar to ":T",
except that every word is replaced by everything but the tail (the
``head'').
":E" replaces each word by its suffix (``extension'').
This replaces each word by everything but the suffix (the ``root'' of
the word).
In addition, PMake supports the System V form of substitution
(string1=string2).
The variable name in a substitution may itself contain variable substitutions
(``computed variable names'').
For example,
FOO = text
BAR = FOO
...
... $($(BAR)) ...
will substitute the value of variable
FOO .
This indirection in substitution is complementary to ``computed assignments,''
where the variable name on the left-hand side of an assignment operator is
itself the result of substitution.
The two assignments in the example above could also be written
BAR = FOO
$(BAR) = text
Note that
will expand an input line only up to an assignment operator and leave
the remainder unexpanded so that it can become part of the variable value.
The assignment operator itself may be the result of a substitution.
COMMENTS, INCLUSION AND CONDITIONALS
Makefile inclusion and conditional structures reminiscent of
the C compiler have also been included in
.
Comments begin with a `#' anywhere but in a shell command and continue
to the end of the line.
If the `#' comes at the beginning of the line, however, the following
keywords are recognized and acted on:
Q "
This is very similar to the C compiler's file-inclusion facility,
right down to the syntax. What follows the
#include
must be a filename enclosed either in double-quotes or angle brackets.
Variables will be expanded between the double-quotes or
angle-brackets. If angle-brackets are used, the system makefile
directory is searched. If the name is enclosed in double-quotes, the
including makefile's directory, followed by all directories given via
-I
arguments, followed by the system directory, is searched for a
file of the given name.
If the file is found,
starts taking input from that file as if it were part of the original
makefile.
When the end of the file is reached,
goes back to the previous file and continues from where it left off.
This facility is recursive up to a depth limited only by the number of open
files allowed to any process at one time.
For compatibility with other versions of
Make ,
the following makefile inclusion directives are also recognized. These
are NOT preceeded by a `#' character; rather, they have to appear as
the first words in a line (not preceeded by a tab character).
Also, the name of the included file is not quoted.
The second form includes
makefile
if present, and does not generate an error otherwise.
These are all the beginnings of conditional constructs in the spirit of
the C compiler.
Conditionals may be nested to a depth of thirty.
In the expressions given above,
op
may be either || (logical \s-2OR\s0) or && (logical
\s-2AND\s0).
&&
has a higher precedence than
|| .
As in C,
will evaluate an expression only as far as necessary to determine its
value. I.e. if the left side of an
&&
is false, the expression is false and vice versa for
|| .
Parentheses may be used as usual to change the order of evaluation.
One other boolean operator is provided: ! (logical negation). It
is of a higher precedence than either the \s-2AND\s0 or \s-2OR\s0 operators,
and may be applied in any of the ``if'' constructs,
negating the given function for ``#if'' or the implicit function for
the other four.
Expr
can be one of several things. Four functions are provided, each of
which takes a different sort of argument.
The function
defined
is used to test for the existence of a variable.
Its argument is, therefore, a variable name.
Certain lower-case variable names (e.g. ``sun'', ``unix'' and
``sprite'') are defined in the system makefile (qv. FILES) to
specify the sort of system on which
is being run. These are intended to make makefiles more portable.
Any variable may be used as the argument of the
defined
function.
The
make
function is given the name of a target in the makefile and evaluates
to true if the target was given on
's
command-line or as a source for the
.MAIN
target before the line containing the conditional.
The
exists
function takes a file name, which file is searched for on the system
search path (as defined by
.PATH
targets (see below)). It evaluates true if the file is found.
empty
takes a variable expansion specification (minus the dollar sign) as
its argument. If the resulting expansion is empty, this evaluates
true.
target
takes a target name as an argument and evaluates to true if the target
has been defined.
Expr
can also be an arithmetic or string comparison, with the left-hand side
being a variable expansion. The standard C relational operators are
allowed, and the usual number/base conversion is performed, with the
exception that octal numbers are not supported. If the right-hand side
of a "==" or "!=" operator begins with a quotation mark, a string
comparison is done between the expanded variable and the text between
the quotation marks. A variable expansion without following relational
operator is expanded and the value processed as a literal according to the
type of conditional (see below).
When, in the course of evaluating one of these conditional
expressions,
encounters some word it does not recognize, it applies one of either
make
or
defined
to it, depending on the form of ``if'' used. E.g. ``#ifdef'' will
apply the
defined
function, while ``#ifnmake'' will apply the negation of the
make
function.
In the context of plain ``#if'' conditional, a numeric literal is
compared against 0, i.e., it is interpreted as a boolean, with a 0
value being false and a non-zero value being true.
Any other literal symbol is treated as a variable name and evaluates
to true if the variable is defined (as with ``#ifdef'').
If the expression following one of these forms evaluates true, the
reading of the makefile continues as before. If it evaluates false,
the following lines are skipped. In both cases, this continues until
either an
#else
or an
#endif
line is encountered.
The #else,
as in the C compiler,
causes the sense of the last conditional to be inverted and the reading of
the makefile to be based on this new value.
I.e. if the previous expression evaluated true,
the parsing of the makefile is suspended until an #endif line is read.
If the previous expression evaluated false,
the parsing of the makefile is resumed.
The ``elif'' constructs are a combination of ``else'' and ``if,'' as
the name implies. If the preceding ``if'' evaluated false, the
expression following the ``elif'' is evaluated and the lines following
it are read or ignored the same as for a regular ``if.''
If the preceding ``if'' evaluated true, however, the ``elif'' is
ignored and all following lines until the ``endif'' (see below) are ignored.
#endif
is used to end a conditional section. If lines were being skipped, the
reading of the makefile resumes. Otherwise, it has no effect (the
makefile continues to be parsed as it was just before the
#endif
was encountered).
Takes the next word on the line as a global variable to be undefined
(only undefines global variables, not command-line variables). If the
variable is already undefined, no message is generated.
TARGET ATTRIBUTES
In
files can have certain ``attributes.''
These attributes cause
to treat the targets in special ways. An attribute is a special word
given as a source to a target on a dependency line.
The words and their functions are given below:
pw \w'.EXPORTSAME 'u
If a target is marked with this attribute and PMake can't figure out
how to create it, it will ignore this fact and assume the file isn't
really needed or actually exists and PMake just can't find it.
The same as
.DONTCARE
(for compatibility with BSD make).
This causes the marked target's shell script to always be executed
(unless the
-n
or
-t
flag is given), but appear invisible to any targets that depend on it.
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 administrator if it is necessary.
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.
Each such dependency specifies that the target creation commands should
only be exported to machines having
attribute
among their characteristics.
Available attributes are entirely site-dependent, and their
syntax depends on the underlying exportation system
(see
export (1)).
This feature is typically used to specify minimum resource requirements
for memory, disk space, software licenses, etc.
If the target marked with
.EXPORT=
attributes cannot be exported, and the local host does not match the
attributes specified,
will try to defer the exportation indefinitely until a suitable remote
host becomes available (or until interrupted). Whether deferment is
possible depends on the exportation system.
Giving a target the
.IGNORE
attribute causes PMake to ignore errors from any of the target's commands, as
if they all had `-' before them.
This allows you to specify one target as a source for another without
the one affecting the other's local variables.
This 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
.TARGET
variable and all the local variables of any target that depends on it,
is replaced by the value of its
.ALLSRC
variable.
Another aspect of the .JOIN attribute is it keeps the target from
being created if the
-t
flag was given.
The
.MAKE
attribute marks its target as being a recursive invocation of PMake.
This forces PMake to execute the script associated with
the target (if it's out-of-date) even if you gave the
-n
or
-t
flag.
In compatibility
( -M )
mode, all commands that expand the
MAKE
variable are also considered recursive make invocations.
Forces the target to be created locally, even if you've given
the
-L 0
flag.
Normally, if you do not specify a target to make in any other way,
will take the first target on the first dependency line of a
makefile as the target to create.
Giving a target this attribute keeps it from this fate.
Targets with names beginning with a `.' are also implicitly marked as
.NOTMAIN .
When PMake is interrupted, it
will attempt to clean up after itself by removing any half-made
targets. If a target has this attribute, however,
will leave it alone
Tells
to restart commands that exit with a non-zero status, instead of aborting.
Using this feature
can be used to manage long-running computations that are performed
by restartable programs that keep their own state.
Between restarts the job may be assigned to different hosts for exportation.
Note that the effect in the case of multiple creation commands depends on the
compatibility mode in effect. In PMake (single-shell) mode the entire
command list is restarted from the top; in backwards
( -B )
mode only the failed command is restarted;
in Make
( -M )
mode the attribute has no effect.
Commands may also be restarted by the exportation system if it detects
that a remote job was evicted from its importing host.
Marking a target with this attribute keeps its commands from being
printed when they're executed.
By giving a target this attribute, you turn the target into
'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
.USE )
of the source.
If the target already has commands, the
.USE
target's commands are added to the end. If more than one .USE-marked
source is given to a target, the rules are applied sequentially.
SPECIAL TARGETS
As there were in Make, so there are certain targets that have special
meaning to PMake. When you use one on a dependency line, it is the
only target that may appear on the left-hand-side of the operator.
The targets are as follows:
pw \w'.MAKEFLAGS 'u
0 def .BEGIN
Any commands attached to this target are executed before anything else
is done. You can use it for any initialization that needs doing.
This is sort of a .USE rule for any target (that was used only as a
source) that
can't figure out any other way to create. Only the shell script is used. The
.IMPSRC
variable of a target that inherits
.DEFAULT 's
commands is set to the target's own name.
This serves a function similar to
.BEGIN :
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 PMake can hang commands you put off
to the end. Thus the script for this target will be executed before
any of the commands you save with the ``.\|.\|.''.
The sources for this target are passed to the exportation system compiled
into
.
Some systems will use these sources to configure
themselves. You should ask your system administrator about this.
Special source keywords include:
SAME ,
to make
.EXPORTSAME
the default;
and
USELOCAL ,
to always check the local host for availability before exporting a command
(similar to a negative
-L
option value).
On systems that allow the selection of remote hosts by attributes,
other sources for
.EXPORT
are interpreted as attributes that should be used globally
(see the description for
.EXPORT=
sources above).
Specifying
.EXPORT
without sources will reset the exportation systems's configuration to a
default state and discard any global attributes.
This is useful to undo the effect of directives written into the system
makefile.
This target marks each of its sources with the
.IGNORE
attribute. If you don't give it any sources, then it is like
giving the
-i
flag.
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
.SUFFIXES
(see below).
Any suffix so marked will have the directories on its search path
(see
.PATH ,
below) placed in the
.INCLUDES
variable, each preceded by a
-I
flag.
The
.h
suffix is already marked in this way in the system makefile.
When PMake is interrupted,
it will execute the commands in the script for this target, if it
exists.
This does for libraries what
.INCLUDES
does for include files, except the flag used is
-L ,
as required by those linkers that allow you to tell them where to find
libraries. The variable used is
.LIBS .
If you didn't give a target (or targets) to create when you invoked
PMake, it will take the sources of this target as the targets to
create.
This target provides a way for you to always specify flags for PMake
when the makefile is used. The flags are just as they would be typed
to the shell,
though the
-f
and
-r
flags have no effect.
This allows you to specify what suffix
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.\|.\|.).
If no sources are given,
reverts to the default which is to have no implicit null suffix at all.
This is useful to undo whatever is defined in the system makefile.
This target constrains
to run creation commands for certain targets sequentially in a specified
order. The sources listed
will be created in the order they are given. Note that this
affects only the targets listed, not their child dependencies, which may
be created in any order unless mentioned in
.ORDER
targets themselves.
will silently fail to create targets that cannot be created under any
allowed ordering, such as when a cyclic ordering is specified.
If you give sources for this target, PMake will take them as
directories 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.
This does a similar thing to
.PATH ,
but it does it only for files with the given suffix. The suffix must
have been defined already.
Gives the
.PRECIOUS
attribute to each source on the dependency line, unless there are no
sources, in which case the
.PRECIOUS
attribute is given to every target in the file.
Applies the
.MAKE
attribute to all its sources. It does nothing if you don't give it any sources.
This target marks each of its sources with the
.RESTART
attribute. No effect if no sources are given.
Tells
to use some other shell than the Bourne Shell.
The sources for the target are organized as
keyword=value strings. If a value contains
whitespace, it may be surrounded by double-quotes to make it a single
word. The possible sources are:
Tells where the shell actually resides. If you specify this and nothing else, PMake will use the
last component of the path to find the specification. Use this if you just
want to use a different version of the Bourne or C Shell (PMake knows
how to use the C Shell too).
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 PMake attempts to find a specification for the
it. You can use this if you would just rather use
the C Shell than the Bourne Shell (``\c
.SHELL: name=csh ''
will do it).
The command
should send to stop the shell from printing its commands. Once echoing
is off, it is expected to remain off until explicitly turned on.
The command PMake should give to turn echoing back on again.
Many shells will echo the echo-off command when it is given. This
keyword tells PMake in what format the shell actually prints the
echo-off command. Wherever PMake sees this string in the shell's
output, it will delete it and any following whitespace, up to and
including the next newline.
The flag to pass to the shell to turn echoing on at the start. If
either this or the next flag begins with a `-', the flags will be
passed to the shell as separate arguments. Otherwise, the two will be
concatenated.
Flag to give the shell to turn error checking on at the start.
The command to make the shell check for errors or to print the command
that's about to be executed (%s indicates where the command to print
should go), if hasErrCtl is "no".
The command to turn error checking off or the command to execute a
command ignoring any errors. "%s" takes the place of the command.
This takes a value that is either
yes
or
no ,
telling how the "check" and "ignore" commands should be used.
NOTE: If this is "no", both the check and ignore commands should
contain a \en at their end if the shell requires a newline before
executing a command.
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. A
.SHELL
target without dependencies reverts to the default shell.
also supports the traditional
SHELL
make variable. ``\c
SHELL= shell \c
''
is equivalent to ``\c
.SHELL: path= shell \c
.''
Similarly, ``\c
#undef SHELL ''
is equivalent to ``\c
.SHELL: ''
without dependencies.
Conversely, a
.SHELL
target implicitly sets the
SHELL
variable value to the shell path.
Applies the
.SILENT
attribute to each of its sources. If there are no sources on the
dependency line, then it is as if you gave PMake the
-s
flag.
This is used to give new file suffixes for PMake to handle. Each
source is a suffix PMake should recognize. If you give a
.SUFFIXES
dependency line with no sources, PMake will forget about all the
suffixes it knew (this also nukes the null suffix).
For those targets that need to have suffixes defined, this is how you do it.
In addition to these targets, a line of the form
attribute : sources
applies the
attribute
to all the targets listed as
sources
except as noted above.
THE POWER OF SUFFIXES
One of the best aspects of both
Make
and
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.
also has the ability to find a file based on its suffix,
supporting different types of files being in different directories.
The former ability derives from the existence of so-called
transformation rules while the latter comes from the specification of
search paths using the
.PATH
target.
A special type of dependency, called a transformation rule, consists
of a target made of
two known suffixes stuck together followed by a shell script to transform a
file of one suffix into a file of the other.
The first suffix is the suffix of the source file and the second is that of
the target file.
E.g. the target ``.c.o,'' followed by commands,
would define a transformation from files with the
``.c'' suffix to those with the ``.o'' suffix.
A transformation rule has no source files associated with it, though
attributes may be given to one in the usual way. These attributes are
then applied to any target that is on the ``target end'' of a
transformation rule.
The suffixes that are concatenated must be already known to
in order for their concatenation to be recognized as a transformation,
i.e. the suffixes must have been the source for a .SUFFIXES target at some
time before the transformation is defined.
Many transformations are defined in the system makefile (qv.
FILES )
and I refer you there for more examples as well as to find what is
already available (you should especially note the various variables
used to contain flags for the compilers, assemblers, etc., used to
transform the files. These variables allow you to customize the
transformations to your own needs without having to redefine them).
A transformation rule may be defined more than once, but only the last
such definition is remembered by
.
This allows you to redefine the transformations in the system makefile if
you wish.
Transformation rules are used only when a target has no commands associated
with it,
both to find any additional files on which it depends and to attempt to
figure out just how to make the target should it end up being out-of-date.
When a transformation is found for a target, another of the seven ``local''
variables mentioned earlier is defined:
The name/path of the source from which the target is to be transformed (the
``implied'' source).
For example,
given the following makefile:
a.out : a.o b.o
$(CC) $(.ALLSRC)
and a directory containing the files a.o, a.c and b.c,
will look at the list of suffixes and transformations given in the
built-in rules and find that the suffixes ``.c'' and ``.o'' are both
known and there is a transformation rule defined from one to the other
with the command ``$(CC) $(CFLAGS) -c $(.IMPSRC).'' Having found
this, it can then check the modification times of both a.c and b.c and
execute the command from the transformation rule as necessary in order
to update the files a.o and b.o.
unlike
Make
before it,
has the ability to apply several transformations to a file even if the
intermediate files do not exist.
Given a directory containing a .o file and a .q file, and transformations
from .q to .l, .l to .c and .c to .o,
will define a transformation from .q \*(-> .o using the three transformation
rules you defined.
In the event of two paths between the same suffixes, the shortest path will be
chosen between the target and the first existing file on the path.
So if there were also a transformation from .l files to .o files,
would use the path .q \*(-> .l \*(-> .o instead
of .q \*(-> .l \*(-> .c \*(-> .o.
Once an existing file is found,
will continue to look at and record transformations until it comes to a
file to which nothing it knows of can be transformed,
at which point it will stop looking and use the path it has already found.
What happens if you have a .o file, a .q file and a .r file, all with
the same prefix, and transformations from .q \*(-> .o and .r \*(-> .o?
Which transformation will be used?
uses the order in which the suffixes were given on the
.SUFFIXES
line to decide between transformations: whichever suffix came first,
wins.
So if the three suffixes were declared
.SUFFIXES : .o .q .r
the .q \*(-> .o transformation would be applied. Similarly, if they were
declared as
.SUFFIXES : .o .r .q
the .r \*(-> .o transformation would be used.
You should keep this in mind when writing such rules.
Note also that because the placing of a suffix on a
.SUFFIXES
line doesn't alter the precedence of previously-defined
transformations,
it is sometimes necessary to clear the whole lot of them out and start
from scratch. This is what the
.SUFFIXES -only
line, mentioned earlier, will do.
SEARCH PATHS
also supports the notion of multiple directories in a more flexible,
easily-used manner than has been available in the past.
You can define a list of directories in which to search for any and
all files that aren't in the current directory by giving the directories
as sources to the
.PATH
target. The search will only be conducted for those files used only as
sources, on the assumption that files used as targets will be created
in the current directory.
The line
.PATH : RCS
would tell
to look for any files it is seeking (including ones made up by means
of transformation rules) in the RCS directory as well as the current
one. Note, however, that this searching is only done if the file is
used only as a source in the makefile. I.e. if the file cannot be
created by commands in the makefile.
A search path specific to files with a given suffix can also be
specified in much the same way.
.PATH.h : h /usr/include
causes the search for header files to be conducted in the h and
/usr/include directory as well as the current one.
When expanding wildcards, these paths are also used. If the pattern
has a recognizable suffix, the search path for that suffix is used.
Otherwise, the path defined with the regular
.PATH
target is used.
When a file is found somewhere other than the current directory, its
name is replaced by its full pathname in any ``local'' variables.
Two types of suffixes are given special attention when a search path is defined
for them. On most systems, the C compiler lets you specify where to
find header files (.h files) by means of
-I
flags similar to those used by
.
If a search path is given for any suffix used as a source for the
.INCLUDES
target, the variable
$(.INCLUDES)
will be set to contain all the directories on the path, in the order
given, in a format which can be passed directly to the C compiler.
Similarly, on some systems, one may give directories to search for
libraries to the compiler by means of
-L
flags.
Directories on the search path for a suffix which was the source of the
.LIBS
target will be placed
in the
$(.LIBS)
variable ready to be passed to the compiler.
LIBRARIES AND ARCHIVES
Two other special forms of sources are recognized by
.
Any source that begins with the characters ``-l'' or ends in a suffix
that is a source for the
.LIBS
target is assumed to be a library, and any source that contains a left
parenthesis in it is considered to be a member (or members) of an archive.
Libraries are treated specially mostly in how they appear in the local
variables of those targets that depend on them. If the system supports the
-L
flag when linking, the name of the library (i.e. its ``-l'' form) is
used in all local variables.
assumes that you will use the $(.LIBS) variable in the appropriate place.
If, however, the system does not have this feature, the name is
expanded to its full pathname before it is placed in any local
variable.
One problem with libraries is they have a table of contents in them
and when the file is touched (so the file's modification time and the
time listed in the table of contents don't match), the library is
declared to be ``out-of-date'' by the linker and the final linking
stage of creating your program fails miserably. To avoid this problem,
when you use the
-t
flag,
updates the time of the table of contents for the library, as well as
the library itself.
The process of creating a library or archive can be a painful one,
what with all the members having to be kept outside the archive as
well as inside it in order to keep them from being recreated.
has been set up, however, to allow you to reference files that are in
an archive in a relatively painless manner.
The specification of an archive member is written as:
archive(member [member...])
Both the open and close parenthesis are required and there may be any
number of members between them (except 0, that is). Members may also
include wildcards characters. When such a source is examined, it is
the modification time of the member, as recorded in the archive, that
is used to determine its datedness.
Instead of filenames,
member
specifications may also take the form
( symbol )\c
, identifying the object file within the library that defines the name
symbol .
This requires that the library already exist and have a table of
contents built in (as built by
ranlib (1)).
If an archive member has no commands associated with it,
goes through a special process to find commands for it.
First, implicit sources are sought using the ``member'' portion of the
specification. So if you have something like
``libcompat.a(procFork.o)'' for a target,
attempts to find sources for the file ``procFork.o,'' even if it
doesn't exist. If such sources exist,
then looks for a transformation rule from the member's suffix to the
archive's (in this case from .o \*(-> .a) and tacks those commands on
as well.
To make these transformations easier to write,
three local variables are defined for the target:
The path to the archive file.
The actual member name (literally the part in parentheses).
The path to the file which will be archived, if it is only a source,
or the same as the
.MEMBER
variable if it is also a target.
is a synonym for
.ARCHIVE
in rules for archive members,
to maintain compatibility with other make programs.
(In other contexts
@
is the same as
.TARGET .)
Using the transformations already in the system makefile, a makefile
for a library might look something like this:
OBJS = procFork.o procExec.o procEnviron.o fsRead.o
.o.a :
...
rm -f $(.MEMBER)
lib.a : lib.a($(OBJS))
ar cru $(.TARGET) $(.OODATE)
ranlib $(.TARGET)
You might be wondering,
at this point,
why I did not define the .o \*(-> .a transformation like this:
.o.a :
ar r $(.ARCHIVE) $(.TARGET)
...
rm -f $(.TARGET)
The reason is simple: you cannot execute ``ar'' on the same file
several times at once. If you try, you end up with a corrupted
archive.
So rather than reduce
to executing only one job at a time, I chose to archive all the
out-of-date files at once (this turns out to be faster anyway).
OUTPUT
When creating targets in parallel,
several shells are executing at once,
each wanting to write its own two cent's worth onto the screen.
This output must be captured by
in some way in order to prevent the screen from being filled with
garbage even more indecipherable than one can already get from these programs.
has two ways of doing this,
one of which provides for much cleaner output and a clear delineation between
the output of different jobs,
the other of which provides a more immediate response so one can tell what is
really happening.
The former is done by notifying the user when the creation of a given target
starts, capturing the output, and transferring it
to the screen when the job finishes,
preceded by an indication as to which job produced the output.
The latter is done by catching the output of the shell (and its children)
and buffering it until an entire line is received, then printing
that line preceded by the name of the job from which the line came.
The name of the job is just the target which is being created by it.
Since I prefer this second method,
it is the one used by default.
The first method will be used if the
-P
flag is given to
.
PARALLELISM
As mentioned before,
attempts to create several targets at once.
On some systems where load balancing or process migration is in
effect, the amount of concurrency which can be used will be much
greater than on others. During the development of
I found that while one could create up to five targets at once on a
Sun 3 without making the machine unusable, attempting the same feat
on a Sun 2 would grind the machine into the dirt, most likely making
the whole process run slower than it would have under
Make .
In addition, the use of
on a multi-user machine (in contrast to a workstation) calls for
judicious use of concurrency to avoid annoying the other users. The
ability to execute tasks in parallel, in combination with the
execution of only one shell per target, brings about decreases in
creation time on the order of 25%-60%.
The
-J
and
-L
flags are used to control the number of shells executing at once and
should be used to find the best level for your machine. Once this is
found, the default level can be set at that point and
recompiled.
BACKWARD-COMPATIBILITY
was designed to be as backwards-compatible with
Make
as possible.
In spite of this, however, there are a few major differences which may
cause problems when using old makefiles:
The variable substitution, as mentioned earlier, is very different and
will cause problems unless the makefile is converted or the
-V
flag is given.
Because targets are created in parallel, certain sequences which
depend on the sources of a target being created sequentially will fail
miserably. E.g.:
prod : $(PROGRAM) clean
This is liable to cause some of the object files to be removed after
having been created during the current invocation (or, at the very
least, the object files will not be removed when the program has been
made), leading to errors in the final linking stage. This problem
cannot even be gotten around by limiting the maximum concurrency to
one, since the traversal of the dependency graph is done in a
breadth-first, rather than a depth-first way. This can only be gotten
around by rewriting the makefile, or by invoking
with the
-M
flag.
One other possible conflict arises because
forks only one shell to execute the commands to re-create a target.
This means that changes of directory, environment, etc., remain in
effect throughout the creation process. It also allows for a more
natural entry of shell constructs, such as the ``for'' and ``while''
loops in the Bourne shell, without the need for backslashes and
semi-colons required by the one-shell-per-command paradigm used by
Make .
This shouldn't pose any serious difficulties (or even any trivial ones
so far as I can see), but should,
in fact,
make life a little easier. It is, however, possible to have
execute each command in a single shell by giving it the
-B
flag.
FILES
Makefile
makefile
/usr/lib/pmake
default system makefile directory
/usr/lib/pmake/system.mk
System makefile (the built-in rules)
ENVIRONMENT
PMAKE
Flags PMake should always use when invoked.
MAKEFLAGS
Portable Make flags (without hyphens or spaces)
MAKEOBJDIR
Subdirectory to build in.
MAKESYSPATH
Search path for system makefiles.
BUGS
Attributes applied to targets that add commands to .END are not preserved.
Add .EXPORTSAME, .NOEXPORT, etc. to .END explicitly to take effect for
the execution of commands following ``...'' lines.
SEE ALSO
- make (1) -
for a more complete explanation of the lower-case flags to export(1) and customs(8) for details regarding the locally available exportation system
KEYWORDS
AUTHOR
Adam de Boor, adam@bsw.uu.net (...!uunet!bsw!adam).
Bugfixes and enhancements by Andreas Stolcke (stolcke@icsi.berkeley.edu).
'' }`
''' $RCSfile$$Revision$$Date$
'''
''' $Log$
'''
Sh
t .Sp
5
\\$1
Sp
t .sp .5v
n .sp
Ip
\\n(.$>=3 .ne \\$3
.ne 3
\\$1
Ve
R
'''
'''
''' Set up \*(-- to give an unbreakable dash;
''' string Tr holds user defined translation string.
''' Bell System Logo is used as a dummy character.
'''
\(*W-|\(bv\*(Tr
n \{\
-- \(*W-
PI pi
(\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
(\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
L" ""
R" ""
''' \*(M", \*(S", \*(N" and \*(T" are the equivalent of
''' \*(L" and \*(R", except that they are used on ".xx" lines,
''' such as .IP and .SH, which do another additional levels of
''' double-quote interpretation
M" """
S" """
N" """""
T" """""
L' '
R' '
M' '
S' '
N' '
T' '
'br\}
{\
-- \(em\|
\*(Tr
L" ``
R" ''
M" ``
S" ''
N" ``
T" ''
L' `
R' '
M' `
S' '
N' `
T' '
PI \(*p
'br\}
|
|