.TH PMAKE 1 "$Date: 1995/03/11 04:17:46 $" "Pmake 2.1 (ICSI)" .so tmac.ansp .de Pm .ie \\n(.$ .IR PMake \\$1 .el .I PMake .. .if n .nr #D 3n .if t .nr #D .5i .if n .ds -> \-> .if t .ds -> \(-> .de DS \" Real Display-Start macro. It actually works! .sp .5v .nf .in +\\n(#Du .. .de DE \" Real Display-End macro. .in .fi .sp .5v .. .SH NAME pmake \- create programs in parallel .SH SYNOPSIS .HP .fi .B pmake [\c .B \-d .I what\c ] [\c .B \-e\c ] [\c .B \-f .I makefile\c ] [\c .B \-h\c ] [\c .B \-i\c ] [\c .B \-k\c ] [\c .B \-l\c ] [\c .B \-n\c ] [\c .B \-p .I #\c ] [\c .B \-q\c ] [\c .B \-r\c ] [\c .B \-s\c ] [\c .B \-t\c ] [\c .B \-x\c ] [\c .B \-v\c ] [\c .B \-B\c ] [\c .B \-C\c ] [\c .B \-D .I variable\c ] [\c .B \-I .I directory\c ] [\c .B \-J .I #\c ] [\c .B \-L .I #\c ] [\c .B \-M\c ] [\c .B \-P\c ] [\c .B \-R .I when\c ] [\c .B \-S\c ] [\c .B \-V\c ] [\c .B \-W\c ] [\c .B \-X\c ] [\c .B \-Z .I c\c ] [\c .IB VAR1 = value1\c ] [\c .IB VAR2 = value2 ...\c ] [\c .I targ1\c ] [\c .I targ2 ...\c ] .AR .AS \-I directory .AP \-d what Specify what modules should print debugging information. .I what is a string of letters from the following set: .br .B a \- archive searching, .br .B c \- conditional evaluation, .br .B d \- directory searching, .br .B j \- job scheduling, .br .B m \- make dependencies, .br .B p \- makefile parsing, .br .B q \- job queue maintenance, .br .B r \- remote execution .br .B s \- suffix processing, .br .B t \- target list maintenance, .br .B v \- variable assignments, .br .B \e* \- all of the above. .AP \-e "\&" Specify that environment variables override macro assignments within makefiles. .AP \-f makefile Specify a different makefile to read than the standard ``Makefile'' or ``makefile''. If .I makefile is "-", reads from standard input. .AP \-h "\&" Prints out help information. .AP \-i "\&" ``Ignore errors'' -- ignore non-zero exit statuses of commands. .AP \-k "\&" ``Keepgoing'' -- if an error is encountered, keep working on those parts of the input graph that are not affected by the error. .AP \-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, .B \-l will turn it off, and vice versa. Note that this locking will not prevent \fIyou\fP from invoking PMake twice in the same place -- if you own the lock file, PMake will warn you about it but continue to execute. .AP \-n "\&" ``No execute'' -- do not execute commands. Just print the ones that would be executed. .AP \-p "#" Tell .Pm 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. .AP \-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. .AP \-r "\&" ``Remove built-in rules'' -- do not parse the built-in rules given in the system makefile. .AP \-s "\&" ``Silence'' -- do not echo commands as they are executed. .AP \-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. .AP \-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. .AP \-v "\&" ``System V'' -- invokes compatibility functions suitable for acting like the System V version of Make. This implies .BR \-B , and .B \-V and turns off directory locking. Locking may be turned back on again by giving the .B \-l flag after .BR \-v . .AP \-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. .AP \-C "\&" ``Non-compatible'' -- turns off all compatibility specified up to the point at which .B \-C is encountered. .AP \-D variable Defines the given variable to be .B 1 in the global context. .AP \-I directory Specify another directory in which to look for #include'd makefiles. This flag may be repeated as many times as necessary. .AP \-J # Specify the maximum number of jobs to run at once on all machines. .AP \-L # Specify the maximum number of jobs to run locally. A negative argument sets a limits equal to the absolute value, but also directs .Pm to run jobs locally as long as the limit is not exceeded. Usually .Pm tries to export jobs before resorting to local execution. .AP \-M "\&" Be as much like Make as possible. No parallel execution. Old-style variable expansion. One shell per command. Etc. .AP \-P "\&" ``Don't use Pipes'' -- see the section on .BR OUTPUT . .AP \-R when ``Recheck targets'' -- possible values are .BR always , .BR never , and .B locals (default for NFS based systems where remote target updates are not immediately visible locally). .AP \-S "\&" ``Stop on error'' -- tells .Pm to stop as soon as a command returns a non-zero exit status, overriding the .B \-k option. .AP \-V "\&" ``Do old-style variable expansion'' -- expands an unknown variable to the empty string. .AP \-W "\&" Don't print warning messages. .AP \-X "\&" ``No Export'' -- prohibits exportation. \-x and \-X should not be used in the same command. .AP \-Z c Modifies makefile parsing to use .I 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. .AP VAR=value "\&" Set the value of the variable .B VAR to the given value. This supersedes any value assigned to the variable in the makefile. See .BR VARIABLES . .SH "LOCAL NOTE" This version of .Pm does .BR make (1) compatible variable expansion (see .B \-V option) by default. This allows processing most standard makefiles without modification. Beware of the way subshells are created, though, and use the .B \-B option if full compatibility is an issue. To process true Pmakefiles use the .B \-C option. .SH DESCRIPTION .Pm 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, .B Makefile and .BR 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 .Pm , please refer to .I PMake -- A Tutorial\c (available in this distribution). There are four basic types of lines in a makefile: .RS .IP 1) File dependency specifications .IP 2) Creation commands .IP 3) Variable assignments .IP 4) Comments, include statements and conditional directives .RE 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. .SH 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: .RS .IP ":" 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. .IP "!" 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. .IP "::" 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 .Pm is interrupted, unlike for the other two operators. .RE For example: .DS a : a.o b.o c.o b ! d.o e.o c :: f.o command1 a : g.o b ! h.o c :: command2 .DE 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 .DS {a,b,c}.o .DE will expand to .DS a.o b.o c.o .DE regardless of whether these three files exist, while .DS [abc].o .DE will only expand to this if all three files exist. The resulting expansion is in directory order, not alphabetically sorted as in the shell. .SH 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 .I 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 .Pm 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 .Pm is done processing everything it needs to process. If you were to say, .DS a.o : a.c cc -c a.c ... @echo "All done" .DE 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 .Pm 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 .DS echo "All done" All done .DE so .Pm 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 .Pm ). 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, .Pm 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 .B \-i or .B \-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.) .SH VARIABLES .Pm has the ability to save text in variables to be recalled later at your convenience. Variables in .Pm are used much like variables in .IR sh (1) and, by tradition, consist of all upper-case letters. They are assigned- and appended-to using lines of the form .DS \fIVARIABLE\fP \fB=\fP \fIvalue\fP \fIVARIABLE\fP \fB+=\fP \fIvalue\fP .DE respectively, while being conditionally assigned-to (if not already defined) and assigned-to with expansion by lines of the form .DS \fIVARIABLE\fP \fB?=\fP \fIvalue\fP \fIVARIABLE\fP \fB:=\fP \fIvalue\fP .DE Finally, .DS \fIVARIABLE\fP \fB!=\fP \fIcommand\fP .DE will execute .I command using the prevailing .B 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. .Pm 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 .B CFLAGS to the string ``\-I/sprite/src/lib/libc \-O'' you would place a line .DS CFLAGS = \-I/sprite/src/lib/libc \-O .DE in the makefile and use the word .B $(CFLAGS) wherever you would like the string ``\-I/sprite/src/lib/libc \-O'' to appear. To pass a string of the form ``$(\fIname\fP)'' or ``${\fIname\fP}'' through to the shell (e.g. to tell it to substitute one of its variables), you can use ``$$(\fIname\fP)'' and ``$${\fIname\fP}'', respectively, or, as long as the \fIname\fP is not a .Pm variable, you can just place the string in directly, as .Pm will not expand a variable it doesn't know, unless it is given one of the three compatibility flags .BR \-V , .BR \-B , or .BR \-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. \fBCOMMANDS\fP, above). There are four different types of variables at which .Pm 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 .Pm 's environment, as passed by your login shell. The .B \-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. \fINothing.\fP Makefile variables that also exist in the environment have their changed values re-exported to the environment of commands invoked by .Pm . An exception is the .B 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: .RS .IP ".TARGET (@)" The name of the target. .IP ".OODATE (?)" The list of sources for this target that were deemed out-of-date. .IP ".ALLSRC (>)" The list of all sources for this target. .IP ".PREFIX (*)" 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. .RE 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'', `` This is very similar to the C compiler's file-inclusion facility, right down to the syntax. What follows the .B #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 .B \-I arguments, followed by the system directory, is searched for a file of the given name. If the file is found, .Pm starts taking input from that file as if it were part of the original makefile. When the end of the file is reached, .Pm 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 .IR 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. .SS include \fImakefile\fP .SS -include \fImakefile\fP The second form includes .I makefile if present, and does not generate an error otherwise. . .SS "if [!] \fIexpr\fP [ \fIop\fP \fIexpr\fP ... ]" .SS ifdef [!] \fIvariable\fP [\fIop\fP \fIvariable\fP...] .SS ifndef [!] \fIvariable\fP [\fIop\fP \fIvariable\fP...] .SS ifmake [!] \fItarget\fP [\fIop\fP \fItarget\fP...] .SS ifnmake [!] \fItarget\fP [\fIop\fP \fItarget\fP...] 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, .I op may be either \fB||\fP (logical \s-2OR\s0) or \fB&&\fP (logical \s-2AND\s0). .B && has a higher precedence than .BR || . As in C, .Pm will evaluate an expression only as far as necessary to determine its value. I.e. if the left side of an .B && is false, the expression is false and vice versa for .BR || . Parentheses may be used as usual to change the order of evaluation. One other boolean operator is provided: \fB!\fP (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. .I Expr can be one of several things. Four functions are provided, each of which takes a different sort of argument. The function .B 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. \fBFILES\fP) to specify the sort of system on which .Pm is being run. These are intended to make makefiles more portable. Any variable may be used as the argument of the .B defined function. The .B make function is given the name of a target in the makefile and evaluates to true if the target was given on .Pm 's command-line or as a source for the .B .MAIN target before the line containing the conditional. The .B exists function takes a file name, which file is searched for on the system search path (as defined by .B .PATH targets (see below)). It evaluates true if the file is found. .B empty takes a variable expansion specification (minus the dollar sign) as its argument. If the resulting expansion is empty, this evaluates true. .B target takes a target name as an argument and evaluates to true if the target has been defined. .I 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, .Pm encounters some word it does not recognize, it applies one of either .I make or .I defined to it, depending on the form of ``if'' used. E.g. ``#ifdef'' will apply the .I defined function, while ``#ifnmake'' will apply the negation of the .I 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 .B #else or an .B #endif line is encountered. .SS else 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. .SS "elif [!] \fIexpr\fP [ \fIop\fP \fIexpr\fP ... ]" .SS elifdef [!] \fIvariable\fP [\fIop\fP \fIvariable\fP...] .SS elifndef [!] \fIvariable\fP [\fIop\fP \fIvariable\fP...] .SS elifmake [!] \fItarget\fP [\fIop\fP \fItarget\fP...] .SS elifnmake [!] \fItarget\fP [\fIop\fP \fItarget\fP...] 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. .SS endif .B #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 .B #endif was encountered). .SS undef 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. .SH TARGET ATTRIBUTES In .Pm , files can have certain ``attributes.'' These attributes cause .Pm 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: .nr pw \w'.EXPORTSAME 'u .IP .DONTCARE \n(pwu 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. .IP .OPTIONAL \n(pwu The same as .B .DONTCARE (for compatibility with BSD make). .IP .EXEC \n(pwu This causes the marked target's shell script to always be executed (unless the .B \-n or .B \-t flag is given), but appear invisible to any targets that depend on it. .IP .EXPORT \n(pwu 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. .IP .EXPORTSAME \n(pwu 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. .IP .EXPORT=\fIattribute\fP \n(pwu Each such dependency specifies that the target creation commands should only be exported to machines having .I attribute among their characteristics. Available attributes are entirely site-dependent, and their syntax depends on the underlying exportation system (see .IR export (1)). This feature is typically used to specify minimum resource requirements for memory, disk space, software licenses, etc. If the target marked with .B .EXPORT= attributes cannot be exported, and the local host does not match the attributes specified, .Pm 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. .IP .IGNORE \n(pwu Giving a target the .B .IGNORE attribute causes PMake to ignore errors from any of the target's commands, as if they all had `\-' before them. .IP .INVISIBLE \n(pwu This allows you to specify one target as a source for another without the one affecting the other's local variables. .IP .JOIN \n(pwu 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 .B .TARGET variable and all the local variables of any target that depends on it, is replaced by the value of its .B .ALLSRC variable. Another aspect of the .JOIN attribute is it keeps the target from being created if the .B \-t flag was given. .IP .MAKE \n(pwu The .B .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 .B \-n or .B \-t flag. .br In compatibility .RB ( \-M ) mode, all commands that expand the .B MAKE variable are also considered recursive make invocations. .IP .NOEXPORT \n(pwu Forces the target to be created locally, even if you've given .Pm the .B "\-L 0" flag. .IP .NOTMAIN \n(pwu Normally, if you do not specify a target to make in any other way, .Pm 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 .BR .NOTMAIN . .IP .PRECIOUS \n(pwu 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, .Pm will leave it alone .IP .RESTART \n(pwu Tells .Pm to restart commands that exit with a non-zero status, instead of aborting. Using this feature .Pm 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 .RB ( \-B ) mode only the failed command is restarted; in Make .RB ( \-M ) mode the attribute has no effect. .br Commands may also be restarted by the exportation system if it detects that a remote job was evicted from its importing host. .IP .SILENT \n(pwu Marking a target with this attribute keeps its commands from being printed when they're executed. .IP .USE \n(pwu By giving a target this attribute, you turn the target into .Pm '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 .BR .USE ) of the source. If the target already has commands, the .B .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. .SH 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: .nr pw \w'.MAKEFLAGS 'u .IP .BEGIN \n(pwu .Ix 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. .IP .DEFAULT \n(pwu This is sort of a .USE rule for any target (that was used only as a source) that .Pm can't figure out any other way to create. Only the shell script is used. The .B .IMPSRC variable of a target that inherits .B .DEFAULT 's commands is set to the target's own name. .IP .END \n(pwu This serves a function similar to .BR .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 ``.\|.\|.''. .IP .EXPORT \n(pwu The sources for this target are passed to the exportation system compiled into .Pm . Some systems will use these sources to configure themselves. You should ask your system administrator about this. .br Special source keywords include: .BR SAME , to make .B .EXPORTSAME the default; and .BR USELOCAL , to always check the local host for availability before exporting a command (similar to a negative .B \-L option value). .br On systems that allow the selection of remote hosts by attributes, other sources for .B .EXPORT are interpreted as attributes that should be used globally (see the description for .B .EXPORT= sources above). .br Specifying .B .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. .IP .IGNORE \n(pwu This target marks each of its sources with the .B .IGNORE attribute. If you don't give it any sources, then it is like giving the .B \-i flag. .IP .INCLUDES \n(pwu 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 .B .SUFFIXES (see below). Any suffix so marked will have the directories on its search path (see .B .PATH , below) placed in the .B .INCLUDES variable, each preceded by a .B \-I flag. The .B .h suffix is already marked in this way in the system makefile. .IP .INTERRUPT \n(pwu When PMake is interrupted, it will execute the commands in the script for this target, if it exists. .IP .LIBS \n(pwu This does for libraries what .B .INCLUDES does for include files, except the flag used is .BR \-L , as required by those linkers that allow you to tell them where to find libraries. The variable used is .BR .LIBS . .IP .MAIN \n(pwu 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. .IP .MAKEFLAGS \n(pwu 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 .B \-f and .B \-r flags have no effect. .IP .NULL \n(pwu This allows you to specify what suffix .Pm 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.\|.\|.). .br If no sources are given, .Pm 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. .IP .ORDER \n(pwu This target constrains .Pm 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 .B .ORDER targets themselves. .Pm will silently fail to create targets that cannot be created under any allowed ordering, such as when a cyclic ordering is specified. .IP .PATH \n(pwu 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. .IP .PATH\fIsuffix\fP \n(pwu This does a similar thing to .BR .PATH , but it does it only for files with the given suffix. The suffix must have been defined already. .IP .PRECIOUS \n(pwu Gives the .B .PRECIOUS attribute to each source on the dependency line, unless there are no sources, in which case the .B .PRECIOUS attribute is given to every target in the file. .IP .RECURSIVE \n(pwu Applies the .B .MAKE attribute to all its sources. It does nothing if you don't give it any sources. .IP .RESTART \n(pwu This target marks each of its sources with the .B .RESTART attribute. No effect if no sources are given. .IP .SHELL \n(pwu Tells .Pm to use some other shell than the Bourne Shell. The sources for the target are organized as \fIkeyword\fP\fB=\fP\fIvalue\fP strings. If a \fIvalue\fP contains whitespace, it may be surrounded by double-quotes to make it a single word. The possible sources are: .RS .IP "\fBpath=\fP\fIpath\fP" 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). .IP "\fBname=\fP\fIname\fP" 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 .BR 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 .BR ".SHELL: name=csh" '' will do it). .IP "\fBquiet=\fP\fIecho-off command\fP" The command .Pm should send to stop the shell from printing its commands. Once echoing is off, it is expected to remain off until explicitly turned on. .IP "\fBecho=\fP\fIecho-on command\fP" The command PMake should give to turn echoing back on again. .IP "\fBfilter=\fP\fIprinted echo-off command\fP" 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. .IP "\fBechoFlag=\fP\fIflag to turn echoing on\fP" 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. .IP "\fBerrFlag=\fP\fIflag to turn error checking on\fP" Flag to give the shell to turn error checking on at the start. .IP "\fBcheck=\fP\fIcommand to turn error checking on\fP" 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". .IP "\fBignore=\fP\fIcommand to turn error checking off\fP" The command to turn error checking off or the command to execute a command ignoring any errors. "%s" takes the place of the command. .IP "\fBhasErrCtl=\fP\fIyes or no\fP" This takes a value that is either .B yes or .BR 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. .RE .IP "\&" \n(pwu 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 .B .SHELL target without dependencies reverts to the default shell. .IP .Pm also supports the traditional .B SHELL make variable. ``\c .BI SHELL= shell \c \&'' is equivalent to ``\c .BI ".SHELL: path=" shell \c \&.'' Similarly, ``\c .BR "#undef SHELL" '' is equivalent to ``\c .BR .SHELL: '' without dependencies. Conversely, a .B .SHELL target implicitly sets the .B SHELL variable value to the shell path. .IP .SILENT \n(pwu Applies the .B .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 .B \-s flag. .IP .SUFFIXES \n(pwu This is used to give new file suffixes for PMake to handle. Each source is a suffix PMake should recognize. If you give a .B .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 .DS \fIattribute\fP : \fIsources\fP .DE applies the .I attribute to all the targets listed as .I sources except as noted above. .SH THE POWER OF SUFFIXES One of the best aspects of both .I Make and .Pm 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. .Pm 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 .B .PATH target. .SS TRANSFORMATION RULES 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 .Pm 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. .BR 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 .Pm . 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: .RS .IP ".IMPSRC (<)" The name/path of the source from which the target is to be transformed (the ``implied'' source). .RE For example, given the following makefile: .DS a.out : a.o b.o $(CC) $(.ALLSRC) .DE and a directory containing the files a.o, a.c and b.c, .Pm 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. .Pm , unlike .I 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, .Pm 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, .Pm would use the path .q \*(-> .l \*(-> .o instead of .q \*(-> .l \*(-> .c \*(-> .o. Once an existing file is found, .Pm 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? .Pm uses the order in which the suffixes were given on the .B .SUFFIXES line to decide between transformations: whichever suffix came first, wins. So if the three suffixes were declared .DS \&.SUFFIXES : .o .q .r .DE the .q \*(-> .o transformation would be applied. Similarly, if they were declared as .DS \&.SUFFIXES : .o .r .q .DE 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 .B .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 .BR .SUFFIXES -only line, mentioned earlier, will do. .SH SEARCH PATHS .Pm 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 .B .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 .DS \&.PATH : RCS .DE would tell .Pm 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. .DS \&.PATH.h : h /usr/include .DE 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 .B .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 .B \-I flags similar to those used by .Pm . If a search path is given for any suffix used as a source for the .B .INCLUDES target, the variable .B $(.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 .B \-L flags. Directories on the search path for a suffix which was the source of the .B .LIBS target will be placed in the .B $(.LIBS) variable ready to be passed to the compiler. .SH LIBRARIES AND ARCHIVES Two other special forms of sources are recognized by .Pm . Any source that begins with the characters ``-l'' or ends in a suffix that is a source for the .B .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 .B \-L flag when linking, the name of the library (i.e. its ``-l'' form) is used in all local variables. .Pm 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 .B \-t flag, .Pm 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. .Pm 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: .DS \fIarchive\fP(\fImember\fP [\fImember\fP...]) .DE 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, .I member specifications may also take the form .BI ( symbol )\c \&, identifying the object file within the library that defines the name .IR symbol . This requires that the library already exist and have a table of contents built in (as built by .IR ranlib (1)). If an archive member has no commands associated with it, .Pm 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, .Pm attempts to find sources for the file ``procFork.o,'' even if it doesn't exist. If such sources exist, .Pm 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: .IP ".ARCHIVE (!) The path to the archive file. .IP ".MEMBER (%) The actual member name (literally the part in parentheses). .IP ".TARGET" The path to the file which will be archived, if it is only a source, or the same as the .B .MEMBER variable if it is also a target. .IP @ is a synonym for .B .ARCHIVE in rules for archive members, to maintain compatibility with other make programs. (In other contexts .B @ is the same as .BR .TARGET .) Using the transformations already in the system makefile, a makefile for a library might look something like this: .DS 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) .DE You might be wondering, at this point, why I did not define the .o \*(-> .a transformation like this: .DS \&.o.a : ar r $(.ARCHIVE) $(.TARGET) ... rm -f $(.TARGET) .DE 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 .Pm 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). .SH 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 .Pm 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. .Pm 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 .B \-P flag is given to .Pm . .SH PARALLELISM As mentioned before, .Pm 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 .Pm , 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 .IR Make . In addition, the use of .Pm 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 .B \-J and .B \-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 .Pm recompiled. .SH BACKWARD-COMPATIBILITY .Pm was designed to be as backwards-compatible with .I Make as possible. In spite of this, however, there are a few major differences which may cause problems when using old makefiles: .IP 1) The variable substitution, as mentioned earlier, is very different and will cause problems unless the makefile is converted or the .B \-V flag is given. .IP 2) Because targets are created in parallel, certain sequences which depend on the sources of a target being created sequentially will fail miserably. E.g.: .DS prod : $(PROGRAM) clean .DE 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 .Pm with the .B \-M flag. One other possible conflict arises because .Pm 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 .IR 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 .Pm execute each command in a single shell by giving it the .B \-B flag. .SH FILES .PD 0 .TP 25n Makefile .TP makefile default input file .TP /usr/share/mk default system makefile directory .TP /usr/share/mk/system.mk System makefile (the built-in rules) .PD .SH ENVIRONMENT .PD 0 .TP 25n .B PMAKE Flags PMake should always use when invoked. .TP .B MAKEFLAGS Portable Make flags (without hyphens or spaces) .TP .B MAKEOBJDIR Subdirectory to build in. .TP .B MAKESYSPATH Search path for system makefiles. .PD .SH 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. .SH SEE ALSO .IR make (1) for a more complete explanation of the lower-case flags to .Pm . .br .IR export (1) and .IR customs (8) for details regarding the locally available exportation system. .SH KEYWORDS make, transformation .SH AUTHOR .na Adam de Boor, adam@bsw.uu.net (...!uunet!bsw!adam). .br Bugfixes and enhancements by Andreas Stolcke (stolcke@icsi.berkeley.edu).