summaryrefslogtreecommitdiff
path: root/sys/doc/mk.ms
diff options
context:
space:
mode:
authoraiju <aiju@phicode.de>2011-07-18 11:01:22 +0200
committeraiju <aiju@phicode.de>2011-07-18 11:01:22 +0200
commit8c4c1f39f4e369d7c590c9d119f1150a2215e56d (patch)
treecd430740860183fc01de1bc1ddb216ceff1f7173 /sys/doc/mk.ms
parent11bf57fb2ceb999e314cfbe27a4e123bf846d2c8 (diff)
added /sys/doc
Diffstat (limited to 'sys/doc/mk.ms')
-rw-r--r--sys/doc/mk.ms1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/sys/doc/mk.ms b/sys/doc/mk.ms
new file mode 100644
index 000000000..1a556e9b6
--- /dev/null
+++ b/sys/doc/mk.ms
@@ -0,0 +1,1533 @@
+.HTML "Maintaining Files on Plan 9 with Mk
+.TL
+Maintaining Files on Plan 9 with Mk
+.AU
+Andrew G. Hume
+andrew@research.att.com
+Bob Flandrena
+bobf@plan9.bell-labs.com
+.AB
+.PP
+.CW Mk
+is a tool
+for describing and maintaining dependencies between
+files.
+It is similar to the
+UNIX program
+.CW make ,
+but provides several extensions.
+.CW Mk\fR'\fPs
+flexible rule specifications, implied
+dependency derivation, and parallel
+execution of maintenance actions are
+well-suited to the Plan 9 environment.
+Almost all Plan 9 maintenance procedures
+are automated using
+.CW mk .
+.AE
+.NH 1
+Introduction
+.PP
+This document describes how
+.CW mk ,
+a program functionally similar to
+.CW make
+[Feld79],
+is used to maintain dependencies between
+files in Plan 9.
+.CW Mk
+provides several extensions to the
+capabilities of its predecessor that work
+well in Plan 9's distributed, multi-architecture
+environment. It
+exploits the power of multiprocessors by executing
+maintenance actions in parallel and interacts with
+the Plan 9 command interpreter
+.CW rc
+to provide a powerful set of maintenance tools.
+It accepts pattern-based dependency specifications
+that are not limited to describing
+rules for program construction.
+The result is a tool that is flexible enough to
+perform many maintenance tasks including
+database maintenance,
+hardware design, and document production.
+.PP
+This document begins by discussing
+the syntax of the control file,
+the pattern matching capabilities, and
+the special rules for maintaining archives.
+A brief description of
+.CW mk\fR'\fPs
+algorithm for deriving dependencies
+is followed by a discussion
+of the conventions used to resolve ambiguous
+specifications. The final sections
+describe parallel execution
+and special features.
+.PP
+An earlier paper [Hume87]
+provides a detailed discussion of
+.CW mk\fR'\fPs
+design and an appendix summarizes
+the differences between
+.CW mk
+and
+.CW make .
+.NH 1
+The \f(CWMkfile\fP
+.PP
+.CW Mk
+reads a file describing relationships among files
+and executes commands to bring the files up to date.
+The specification file, called a
+.CW mkfile ,
+contains three types of statements:
+assignments, includes, and rules.
+Assignment and include statements are similar
+to those in C.
+Rules specify dependencies between a
+.I target
+and its
+.I prerequisites .
+When the target and prerequisites are files, their
+modification times determine if they
+are out of date. Rules often contain a
+.I recipe ,
+an
+.I rc (1)
+script that produces the target from
+the prerequisites.
+.PP
+This simple
+.CW mkfile
+produces an executable
+from a C source file:
+.P1
+CC=pcc
+f1: f1.c
+ $CC -o f1 f1.c
+.P2
+The first line assigns the name of the portable ANSI/POSIX compiler
+to the
+.CW mk
+variable
+.CW CC ;
+subsequent references of the form
+.CW $CC
+select this compiler.
+The only rule specifies a dependence between the target file
+.CW f1
+and the prerequisite file
+.CW f1.c .
+If the target does not exist or if the
+prerequisite has been modified more recently than
+the target,
+.CW mk
+passes the recipe to
+.CW rc
+for execution. Here,
+.CW f1.c
+is compiled and loaded to produce
+.CW f1 .
+.PP
+The native Plan 9 environment
+requires executables for
+all architectures, not only the current one.
+The Plan 9 version of the same
+.CW mkfile
+looks like:
+.P1
+</$objtype/mkfile
+
+f1: f1.$O
+ $LD $LDFLAGS -o f1 f1.$O
+f1.$O: f1.c
+ $CC $CFLAGS f1.c
+.P2
+The first line is an include statement
+that replaces itself with the contents of the file
+.CW /$objtype/mkfile .
+The variable
+.CW $objtype
+is inherited from the environment and
+contains the name of the target architecture.
+The prototype
+.CW mkfile
+for that architecture defines architecture-specific variables:
+.CW CC
+and
+.CW LD
+are the names of the compiler and loader,
+.CW O
+is the code character of the architecture.
+The rules compile the source file into an object
+file and invoke the loader to produce
+.CW f1 .
+Invoking
+.CW mk
+from the command line as follows
+.P1
+% objtype=mips mk
+vc -w f1.c
+vl $LDFLAGS -o f1 f1.k
+%
+.P2
+produces the
+.CW mips
+executable of program
+.CW f1
+regardless of the current architecture type.
+.PP
+We can extend the
+.CW mkfile
+to build two programs:
+.P1
+</$objtype/mkfile
+ALL=f1 f2
+
+all:V: $ALL
+
+f1: f1.$O
+ $LD $LDFLAGS -o f1 f1.$O
+f1.$O: f1.c
+ $CC $CFLAGS f1.c
+f2: f2.$O
+ $LD $LDFLAGS -o f2 f2.$O
+f2.$O: f2.c
+ $CC $CFLAGS f2.c
+.P2
+The target
+.CW all ,
+modified by the
+.I attribute
+.CW V ,
+builds both programs.
+The attribute identifies
+.CW all
+as a dummy target that is
+not related to a file of the same name;
+its precise effect is explained later.
+This example describes cascading dependencies:
+the first target depends on another which depends on a third and
+so on.
+Here, individual rules build each
+program; later we'll see how to do this with a
+general rule.
+.NH 1
+Variables and the environment
+.PP
+.CW Mk
+does not distinguish between its
+internal variables and
+.CW rc
+variables in the environment.
+When
+.CW mk
+starts, it imports each environment variable into a
+.CW mk
+variable of the same name. Before executing a recipe,
+.CW mk
+exports all variables, including those
+inherited from the environment,
+to the environment in which
+.CW rc
+executes the recipe.
+.PP
+There are several ways for a
+variable to take a value.
+It can be set with an assignment statement,
+inherited from the environment, or specified
+on the command line.
+.CW Mk
+also maintains several special internal variables
+that are described in
+.I mk (1).
+Assignments have the following decreasing order of precedence:
+.LP
+.in .7i
+1) Command line assignment
+.br
+2) Assignment statement
+.br
+3) Imported from the environment
+.br
+4) Implicitly set by \f(CWmk\fP
+.in 0
+.LP
+For example, a command line assignment overrides
+a value imported from the environment.
+.PP
+All variable values are strings. They can be
+used for pattern matching and
+comparison but not for arithmetic.
+A
+.I list
+is a string containing several values separated by
+white space. Each member is
+handled individually during pattern matching,
+target selection, and prerequisite evaluation.
+.PP
+A
+.I namelist
+is a list produced by
+transforming the members of an existing list.
+The transform applies a pattern to each member,
+replacing each matched string with a new string,
+much as in the substitute command in
+.I sam (1)
+or
+.I ed (1).
+The syntax is
+.P1
+${\fIvar\fP:A%B=C%D}
+.P2
+where
+.I var
+is a variable.
+The pattern
+.CW A%B
+matches a member beginning with the string
+.I A
+and ending with the string
+.I B
+with any string in between;
+it behaves like the regular expression
+.CW A.*B .
+When a member of the
+.I var
+list
+matches this pattern,
+the string
+.I C
+replaces
+.I A ,
+.I D
+replaces
+.I B ,
+and the matched string replaces itself.
+Any of
+.I A ,
+.I B ,
+.I C ,
+or
+.I D
+may be the empty string. In effect, a namelist is
+generated by applying the
+.I ed (1)
+substitute command
+.P1
+ s/\fIA\fP(.*)\fIB\fP/\fIC\fP\e1\fID\fP/
+.P2
+to each member of a variable list.
+.PP
+Namelists are useful for generating
+a list based on a predictable transformation.
+For example,
+.P1
+ SRC=a.c b.c c.c
+ OBJ=${SRC:%.c=%.v}
+.P2
+assigns the list \f(CW(a.v b.v c.v)\fP to
+.CW OBJ .
+A namelist may be used anywhere a variable is allowed
+except in a recipe.
+.PP
+Command output is assigned to a variable
+using the normal
+.CW rc
+syntax:
+.P1
+ var=`{rc command}
+.P2
+The command executes in an environment populated
+with previously assigned variables, including those
+inherited from
+.CW mk\fR'\fPs
+execution environment.
+The command may
+be arbitrarily complex; for example,
+.P1
+ TARG=`{ls -d *.[cy] | sed 's/..$//'}
+.P2
+assigns a list of the C and yacc source files in the current
+directory, stripped of their suffix, to the variable
+.CW TARG .
+.NH 1
+The include statement
+.PP
+The include statement
+replaces itself with the contents of a file.
+It is functionally similar to the C
+.CW #include
+statement but uses a different syntax:
+.P1
+ <\fIfilename\fP
+.P2
+The contents of the file are evaluated
+as they are read.
+An include statement may be used anywhere except
+in a recipe.
+.PP
+Unlike
+.CW make ,
+.CW mk
+has no built-in rules. Instead,
+the include statement allows generic rules
+to be imported from a prototype
+.CW mkfile ;
+most Plan 9
+.CW mkfiles
+use this approach [Flan95].
+.NH 1
+Rules
+.PP
+A rule has four elements: targets,
+prerequisites, attributes, and a recipe.
+It has the form:
+.P1
+\fItargets\fP:\fIattributes\fP:\fIprerequisites\fP
+ \fIrecipe\fP
+.P2
+The first line, containing the
+targets, attributes, and prerequisites is
+the
+.I "rule header" ;
+it
+must begin at the left margin.
+The recipe contains zero or more lines,
+each of which begins with white space.
+One or more targets must be specified but the
+attributes, prerequisites, and recipe are optional.
+A rule specifies
+a dependency between the target(s) and its prerequisite(s),
+the recipe brings the target(s)
+up to date with the prerequisite(s) and
+attributes modify
+.CW mk\fR'\fPs
+evaluation of the dependency.
+.PP
+Normally the target is a file that depends
+on one or more prerequisite files.
+.CW Mk
+compares the modification times of each target
+and each prerequisite; a target is considered out of date
+when it does not exist or when a prerequisite has been modified
+more recently.
+When a target is out of date,
+.CW mk
+executes the
+recipe to bring it up to date.
+When the recipe completes,
+the modification time of the target is checked and
+used in later dependency evaluations.
+If the recipe does not update the target,
+evaluation continues with the out of date target.
+.PP
+A prerequisite of one rule
+may be the target of another. When
+this happens, the rules cascade
+to define a multi-step procedure.
+For example,
+an executable target depends on prerequisite
+object files, each of which is a target
+in a rule with a C source file as the prerequisite.
+.CW Mk
+follows a chain of dependencies until it encounters
+a prerequisite that is not a target of another rule
+or it finds a target that
+is up to date. It then
+executes the recipes in reverse order to produce
+the desired target.
+.PP
+The rule header is evaluated when the rule is read.
+Variables are replaced by their values, namelists are
+generated, and
+commands are replaced by their
+output at this time.
+.PP
+Most attributes modify
+.CW mk\fR'\fPs
+evaluation of a rule.
+An attribute is usually a single letter but some
+are more complicated.
+This paper only discusses commonly used attributes;
+see
+.I mk (1)
+for a complete list.
+.PP
+The
+.CW V
+attribute identifies a
+.I virtual
+target;
+that is, a target that is not a file.
+For example,
+.P1
+clean:V:
+ rm *.$O $O.out
+.P2
+removes executables and compiler intermediate files.
+The target is virtual because it does not refer to a file named
+.CW clean .
+Without the attribute, the recipe would not be
+executed if a file named
+.CW clean
+existed.
+The
+.CW Q
+attribute
+silences the printing of a recipe before
+execution.
+It is useful when the output of a recipe is
+similar to the recipe:
+.P1
+default:QV:
+ echo 'No default target; use mk all or mk install'
+.P2
+.PP
+The recipe is an
+.CW rc
+script. It is optional but when it is
+missing, the rule is handled specially, as described later.
+Unlike
+.CW make ,
+.CW mk
+executes recipes without interpretation.
+After
+stripping the first white space character from each line
+it passes the entire recipe to
+.CW rc
+on standard input.
+Since
+.CW mk
+does not interpret a recipe,
+escape conventions are exactly those of
+.CW rc .
+Scripts for
+.CW awk
+and
+.CW sed
+commands can be embedded exactly as they would
+be entered from the command line.
+.CW Mk
+invokes
+.CW rc
+with the
+.CW -e
+flag, which causes
+.CW rc
+to stop if any command
+in the recipe exits with a non-zero status; the
+.CW E
+attribute overrides this behavior and allows
+.CW rc
+to continue executing in the face of errors.
+Before a recipe is executed, variables are exported
+to the environment where they are available to
+.CW rc .
+Commands in the recipe may not read from
+standard input because
+.CW mk
+uses it internally.
+.PP
+References to a variable can yield different
+values depending on the location of the
+reference in the
+.CW mkfile .
+.CW Mk
+resolves variable references
+in assignment statements and rule headers
+when the statement is read. Variable references
+in recipes are evaluated by
+.CW rc
+when the recipe is executed; this
+happens after the entire
+.CW mkfile
+has been read. The value of a variable in a recipe
+is the last value assigned in the file. For example,
+.P1
+STRING=all
+
+all:VQ:
+ echo $STRING
+STRING=none
+.P2
+produces the message
+.CW none .
+A variable assignment in a recipe
+does not affect the value of the variable in the
+.CW mkfile
+for two reasons.
+First,
+.CW mk
+does not import values from
+the environment when a recipe completes;
+one recipe cannot pass a value through
+the environment to another recipe.
+Second, no recipe is executed until
+.CW mk
+has completed its evaluation, so even if a variable
+were changed,
+it would not affect the dependency evaluation.
+.NH 1
+Metarules
+.PP
+A
+.I metarule
+is a rule based on a pattern.
+The pattern selects a class of target(s) and
+identifies related prerequisites.
+.CW Mk
+metarules may select targets and prerequisites
+based on any criterion that can be described by a pattern, not just
+the suffix transformations associated with program
+construction.
+.PP
+Metarule patterns are either
+.I intrinsic
+or regular expressions conforming to the
+syntax of
+.I regexp (6).
+The intrinsic patterns are shorthand
+for common regular expressions.
+The intrinsic pattern
+.CW %
+matches one or more of anything; it is equivalent to
+the regular expression
+.CW `.+' .
+The other intrinsic pattern,
+.CW & ,
+matches one or more of any characters except \f(CW`/'\fP
+and \f(CW`.'\fP.
+It matches a portion of a path and is
+equivalent to the regular expression
+.CW `[^./]+' .
+An intrinsic pattern in a prerequisite references
+the string matched by the same intrinsic pattern in the target.
+For example, the rule
+.P1
+ %.v: %.c
+.P2
+says that a file ending in
+.CW .v
+depends on a file of the same name with a
+.CW .c
+suffix:
+.CW foo.v
+depends on
+.CW foo.c ,
+.CW bar.v
+depends on
+.CW bar.c ,
+and so on.
+The string matched by an intrinsic pattern in the target
+is supplied to the recipe in the variable
+.CW $stem .
+Thus the rule
+.P1
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+.P2
+creates an object file for the target architecture from
+a similarly named C source file. If several object
+files are out of date, the rule is applied repeatedly and
+.CW $stem
+refers to each file in turn.
+Since there is only one
+.CW stem
+variable, there can only be one
+.CW %
+or
+.CW &
+pattern in a target;
+the pattern
+.CW %-%.c
+is illegal.
+.PP
+Metarules simplify the
+.CW mkfile
+for building programs
+.CW f1
+and
+.CW f2 :
+.P1
+</$objtype/mkfile
+
+ALL=f1 f2
+
+all:V: $ALL
+
+%: %.$O
+ $LD -o $target $prereq
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+clean:V:
+ rm -f $ALL *.[$OS]
+.P2
+(The variable
+.CW $OS
+is a list of code characters for all architectures.)
+Here, metarules specify
+compile and load steps for all C source files.
+The loader rule relies on two internal variables
+set by
+.CW mk
+during evaluation of the rule:
+.CW $target
+is the name of the target(s) and
+.CW $prereq
+the name of all prerequisite(s).
+Metarules allow this
+.CW mkfile
+to be easily extended; a new program
+is supported by adding its name to the third line.
+.PP
+A regular expression metarule must have an
+.CW R
+attribute.
+Prerequisites may reference matching substrings in
+the target using the form
+.CW \e\fIn\fP
+where
+.I n
+is a digit from 1 to 9 specifying the
+.I n th
+parenthesized sub-expression. In a recipe,
+.CW $stem\fIn\fP
+is the equivalent reference.
+For example, a compile rule could be
+specified using regular expressions:
+.P1
+(.+)\e.$O:R: \e1.c
+ $CC $CFLAGS $stem1.c
+.P2
+Here,
+.CW \e1
+and
+.CW $stem1
+refer to the name of the target object file without the
+suffix. The variable
+.CW $stem
+associated with an intrinsic pattern is undefined
+in a regular expression metarule.
+.NH 1
+Archives
+.PP
+.CW Mk
+provides a special mechanism for maintaining an archive.
+An archive member is referenced using the form
+.CW \fIlib\fP(\fIfile\fP)
+where
+.I lib
+is the name of the archive and
+.I file
+is the name of the member. Two rules define the
+dependency between an object file and its membership
+in an archive:
+.P1
+$LIB(foo.8):N: foo.8
+$LIB: $LIB(foo.8)
+ ar rv $LIB foo.8
+.P2
+The first rule establishes a dependency between the
+archive member and the object file.
+Normally,
+.CW mk
+detects an error when a target does not exist and the rule
+contains no recipe; the
+.CW N
+attribute overrides this behavior because the subsequent rule
+updates the member.
+The second
+rule establishes the dependency between the member and
+the archive; its recipe inserts the member
+into the archive.
+This two-step specification allows the modification time
+of the archive
+to represent the state of its members. Other rules
+can then specify the archive as a prerequisite instead of
+listing each member.
+.PP
+A metarule generalizes library maintenance:
+.P1
+LIB=lib.a
+OBJS=etoa.$O atoe.$O ebcdic.$O
+
+$LIB(%):N: %
+$LIB: ${OBJS:%=$LIB(%)}
+ ar rv $LIB $OBJS
+.P2
+The namelist prerequisite of the
+.CW $LIB
+target generates archive member names for each object file name;
+for example,
+.CW etoa.$O
+becomes
+.CW lib.a(etoa.$O) .
+This formulation always updates all members.
+This is acceptable for a small archive, but may
+be slow for a big one.
+The rule
+.P1
+$LIB: ${OBJS:%=$LIB(%)}
+ ar rv $LIB `{membername $newprereq}
+.P2
+only updates out of date object files.
+The internal variable
+.CW $newprereq
+contains the names of the out of
+date prerequisites. The
+.CW rc
+script
+.CW membername
+transforms an archive member specification into a file name:
+it translates
+.CW lib.a(etoa.$O)
+into
+.CW etoa.$O .
+.PP
+The
+.CW mkfile
+.P1
+</$objtype/mkfile
+LIB=lib.a
+OBJS=etoa.$O atoe.$O ebcdic.$O
+
+prog: main.$O $LIB
+ $LD -o $target $prereq
+
+$LIB(%):N: %
+$LIB: ${OBJS:%=$LIB(%)}
+ ar rv $LIB $OBJS
+.P2
+builds a program by loading it with a library.
+.NH 1
+Evaluation algorithm
+.PP
+For each target of interest,
+.CW mk
+uses the rules in a
+.CW mkfile
+to build a data
+structure called a dependency graph. The nodes of
+the graph represent targets and prerequisites;
+a directed arc
+from one node to another indicates that
+the file associated with the first node depends
+on the file associated with the second.
+When the
+.CW mkfile
+has been completely read, the graph is analyzed.
+In the first step, implied dependencies are resolved by
+computing the
+.I "transitive closure"
+of the graph.
+This calculation extends the graph to include all
+targets that are potentially
+derivable from the rules in the
+.CW mkfile .
+Next the graph is checked for cycles;
+.CW make
+accepts cyclic dependencies, but
+.CW mk
+does not allow them.
+Subsequent steps
+prune subgraphs that are irrelevant for producing the
+desired target and verify that there is only one way
+to build it.
+The recipes associated with the
+nodes on the longest path between the
+target and an out of date prerequisite
+are then executed in reverse order.
+.PP
+The transitive closure calculation is sensitive to
+metarules; the patterns often select many potential targets
+and cause the graph to grow rapidly.
+Fortunately,
+dependencies associated with the desired target
+usually form a small part of the graph, so, after
+pruning, analysis is tractable.
+For example, the rules
+.P1
+%: x.%
+ recipe1
+x.%: %.k
+ recipe2
+%.k: %.f
+ recipe3
+.P2
+produce a graph with four nodes for each file in the
+current directory.
+If the desired target is
+.CW foo ,
+.CW mk
+detects the dependency between it
+and the original file
+.CW foo.f
+through intermediate dependencies on
+.CW foo.k
+and
+.CW x.foo .
+Nodes associated with other files are deleted during pruning because
+they are irrelevant to the production of
+.CW foo .
+.PP
+.CW Mk
+avoids infinite cycles by evaluating
+each metarule once.
+Thus, the rule
+.P1
+%: %.z
+ cp $prereq $prereq.z
+.P2
+copies the prerequisite file once.
+.NH 1
+Conventions for evaluating rules
+.PP
+There must be only one
+way to build each target. However, during evaluation
+metarule patterns often select potential targets that
+conflict with the
+targets of other rules.
+.CW Mk
+uses several conventions to resolve ambiguities
+and to select the proper dependencies.
+.PP
+When a target selects more than one rule,
+.CW mk
+chooses a regular rule
+over a metarule.
+For example, the
+.CW mkfile
+.P1
+</$objtype/mkfile
+
+FILES=f1.$O f2.$O f3.$O
+
+prog: $FILES
+ $LD -o $target $prereq
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+
+f2.$O: f2.c
+ $CC f2.c
+.P2
+contains two rules that could build
+.CW f2.$O .
+.CW Mk
+selects the last rule because its target,
+.CW f2.$O ,
+is explicitly specified, while the
+.CW %.$O
+rule is a metarule. In effect,
+the explicit rule for
+.CW f2.$O
+overrides the general rule for building object files from
+C source files.
+.PP
+When a rule has a target and prerequisites but no recipe,
+those prerequisites are added to all other rules with
+recipes that have the same target.
+All prerequisites, regardless of where they were specified, are
+exported to the recipe in variable
+.CW $prereq .
+For example, in
+.P1
+</$objtype/mkfile
+
+FILES=f1.$O f2.$O f3.$O
+
+prog: $FILES
+ $LD -o $target $prereq
+
+%.$O: hdr.h
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+.P2
+the second rule adds
+.CW hdr.h
+as a prerequisite of the compile metarule;
+an object file produced from a C source file
+depends on
+.CW hdr.h
+as well as the source file. Notice that the recipe of
+the compile rule uses
+.CW $stem.c
+instead of
+.CW $prereq
+because the latter specification would attempt to compile
+.CW hdr.h .
+.PP
+When a target is virtual and there is no other rule with
+the same target,
+.CW mk
+evaluates each prerequisite.
+For example, adding the rule
+.P1
+all:V: prog
+.P2
+to the preceding example builds the executable
+when either
+.CW prog
+or
+.CW all
+is the specified target. In effect, the
+.CW all
+target is an alias for
+.CW prog .
+.PP
+When two rules have identical rule headers and both have
+recipes, the later rule replaces the former one.
+For example,
+if a file named
+.CW mkrules
+contains
+.P1
+$O.out: $OFILES
+ $LD $LFLAGS $OFILES
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+.P2
+the
+.CW mkfile
+.P1
+OFILES=f1.$O f2.$O f3.$O
+
+<mkrules
+
+$O.out: $OFILES
+ $LD $LFLAGS -l $OFILES -lbio -lc
+.P2
+overrides the general loader rule with a special
+rule using a non-standard library search sequence.
+A rule is neutralized by overriding it with a rule
+with a null recipe:
+.P1
+<mkrules
+
+$O.out:Q: $OFILES
+ ;
+.P2
+The
+.CW Q
+attribute suppresses the printing of the semicolon.
+.PP
+When a rule has no prerequisites, the recipe is executed
+only when the target does not exist. For example,
+.P1
+marker:
+ touch $target
+.P2
+defines a rule to manage a marker file.
+If the file exists, it is considered up to date
+regardless of its modification time.
+When a virtual target has no prerequisites the
+recipe is always executed.
+The
+.CW clean
+rule is of this type:
+.P1
+clean:V:
+ rm -f [$OS].out *.[$OS]
+.P2
+When a rule without prerequisites has multiple targets, the
+extra targets are aliases for the rule.
+For example, in
+.P1
+clean tidy nuke:V:
+ rm -f [$OS].out *.[$OS]
+.P2
+the
+rule can be invoked by any of three names.
+The first rule in a
+.CW mkfile
+is handled specially:
+when
+.CW mk
+is invoked without a command line target
+all targets of the first non-metarule are built.
+If that rule has multiple targets, the recipe
+is executed once for each target; normally, the recipe
+of a rule with multiple targets is only executed once.
+.PP
+A rule applies to a target only when its prerequisites
+exist or can be derived. More than one rule may have the
+same target as long as only one rule with a recipe
+remains applicable after the dependency evaluation completes.
+For example, consider a program built from C
+and assembler source files. Two rules produce
+object files:
+.P1
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+%.$O: %.s
+ $AS $AFLAGS $stem.s
+.P2
+As long as there are not two source files with names like
+.CW \fIfoo\fP.c
+and
+.CW \fIfoo\fP.s ,
+.CW mk
+can unambiguously select the proper rule.
+If both files exist,
+the rules are ambiguous
+and
+.CW mk
+exits with an error message.
+.PP
+In Plan 9, many programs consist of portable code stored
+in one directory and architecture-specific source stored in
+another.
+For example, the
+.CW mkfile
+.P1
+</$objtype/mkfile
+
+FILES=f1.$O f2.$O f3.$O f3.$O
+
+prog: $FILES
+ $LD -o $target $prereq
+
+%.$O: %.$c
+ $CC $CFLAGS $stem.c
+
+%.$O: ../port/%.c
+ $CC $CFLAGS ../port/$stem.c
+.P2
+builds the program named
+.CW prog
+using portable code in directory
+.CW ../port
+and architecture-specific code in the current directory.
+As long as the
+names of the C source files in
+.CW ../port
+do not conflict with the names of files in the current directory,
+.CW mk
+selects the appropriate rule to build the object file.
+If like-named files exist in both directories, the
+specification is ambiguous and an explicit target
+must be specified to resolve the ambiguity.
+For example,
+adding the rule
+.P1
+f2.$O: f2.c
+ $CC $CFLAGS $f2.c
+.P2
+to the previous
+.CW mkfile
+uses the architecture-specific version of
+.CW f2.c
+instead of the portable one.
+Here, the explicit rule unambiguously
+documents which of the
+like-named source files is used to build the program.
+.PP
+.CW Mk\fR'\fP s
+heuristics can produce unintended results
+when rules are not carefully specified.
+For example, the rules that build
+object files from C or assembler source files
+.P1
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+%.$O: %.s
+ $AS $AFLAGS $stem.s
+.P2
+illustrate a subtle pratfall.
+Adding a header file dependency to the compile rule
+.P1
+%.$O: %.c hdr.h
+ $CC $CFLAGS $stem.c
+.P2
+produces the error message
+.P1
+.CW "don't know how to make '\fIfile\fP.c'"
+.P2
+when \fIfile\fP.s is an assembler
+source file.
+This occurs because
+.CW \fIfile\fP.s
+satisfies the assemble rule and
+.CW hdr.h
+satisfies the compile rule, so
+either rule can potentially produce the target.
+When a prerequisite exists or can be
+derived,
+all other prerequisites in that
+rule header must exist or be derivable; here,
+the existence of
+.CW hdr.h
+forces the evaluation of a C source file.
+Specifying the dependencies in different
+rules avoids this interpretation:
+.P1
+%.$O: hdr.h
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+.P2
+Although
+.CW hdr.h
+is an additional prerequisite of the compile rule,
+the two rules are evaluated independently and
+the existence of the C source file is not linked
+to the existence of the header file.
+However, this specification describes a different
+dependency. Originally, only object
+files derived from C files depended on
+.CW hdr.h ;
+now all object files, including those built
+from assembler source, depend on the header file.
+.PP
+Metarule patterns should be as restrictive as possible to
+prevent conflicts with other rules.
+Consider the
+.CW mkfile
+.P1
+</$objtype/mkfile
+BIN=/$objtype/bin
+PROG=foo
+
+install:V: $BIN/$PROG
+
+%: %.c
+ $CC $stem.c
+ $LD -o $target $stem.$O
+
+$BIN/%: %
+ mv $stem $target
+.P2
+The first target builds an executable
+in the local directory; the second
+installs it in the directory
+of executables for the architecture.
+Invoking
+.CW mk
+with the
+.CW install
+target produces:
+.P1 0
+mk: ambiguous recipes for /mips/bin/foo:
+/mips/bin/foo <-(mkfile:8)- /mips/bin/foo.c <-(mkfile:12)- foo.c
+/mips/bin/foo <-(mkfile:12)- foo <-(mkfile:8)- foo.c
+.P2
+The prerequisite of the
+.CW install
+rule,
+.CW $BIN/$PROG ,
+matches both metarules because the
+.CW %
+pattern matches everything.
+The
+.CW &
+pattern restricts the compile rule to files in the
+current directory and avoids the conflict:
+.P1
+&: &.c
+ $CC $stem.c
+ $LD -o $target $stem.$O
+.P2
+.NH 1
+Missing intermediates
+.PP
+.CW Mk
+does not build a missing intermediate file if a target
+is up to date with the prerequisites of the intermediate.
+For example,
+when an executable is up to date with its source file,
+.CW mk
+does not compile the source to create a missing object file.
+The evaluation only applies
+when a target is considered up to date by pretending that the
+intermediate exists. Thus, it does not apply
+when the intermediate is a command line target
+or when it has no prerequisites.
+.PP
+This capability is useful for
+maintaining archives. We can modify the archive
+update recipe to remove object files after
+they are archived:
+.P1
+$LIB(%):N: %
+$LIB: ${OBJS:%=$LIB(%)}
+ names=`{membername $newprereq}
+ ar rv $LIB $names
+ rm -f $names
+.P2
+A subsequent
+.CW mk
+does not remake the object files as long as the members
+of the archive remain up to date with the source files.
+The
+.CW -i
+command line option overrides this behavior
+and causes all intermediates to be built.
+.NH 1
+Alternative out-of-date determination
+.PP
+Sometimes the modification time is not useful
+for deciding when a target and prerequisite are out of date.
+The
+.CW P
+attribute replaces the default mechanism with the result of
+a command. The command immediately follows the attribute
+and is repeatedly executed with each
+target and each prerequisite as its arguments;
+if its exit status is non-zero, they are considered out of date
+and the recipe is executed. Consider the
+.CW mkfile
+.P1
+foo.ref:Pcmp -s: foo
+ cp $prereq $target
+.P2
+The command
+.P1
+cmp -s foo.ref foo
+.P2
+is executed and if
+.CW foo.ref
+differs from
+.CW foo ,
+the latter file is copied to the former.
+.NH 1
+Parallel processing
+.PP
+When possible,
+.CW mk
+executes recipes in parallel.
+The variable
+.CW $NPROC
+specifies the maximum number of simultaneously executing
+recipes.
+Normally it is imported from the environment,
+where the system has set it to the number of available processors.
+It can be decreased by assigning a new
+value and can be set to 1 to force single-threaded recipe execution.
+This is necessary when several targets access
+a common resource such as
+a status file or data base.
+When there is no dependency between targets,
+.CW mk
+assumes the
+recipes can be
+executed concurrently.
+Normally, this allows
+multiple prerequisites to be built simultaneously;
+for example, the object file prerequisites of
+a load rule can be produced by compiling the source files in parallel.
+.CW Mk
+does not define the order of execution of independent recipes.
+When the prerequisites of a rule are not independent,
+the dependencies between them should be specified in a rule or the
+.CW mkfile
+should be single-threaded.
+For example, the archive update rules
+.P1
+$LIB(%):N: %
+$LIB: ${OBJS:%=$LIB(%)}
+ ar rv $LIB `{membername $newprereq}
+.P2
+compile source files in parallel but update
+all members of the archive at once.
+It is a mistake to merge the two rules
+.P1
+$LIB(%): %
+ ar rv $LIB $stem
+.P2
+because an
+.CW ar
+command is executed for every
+member of the library. Not only is this
+inefficient, but the archive is updated
+in parallel, making interference likely.
+.PP
+The
+.CW $nproc
+environment variable contains a number associated
+with the processor executing a recipe.
+It can be used to create unique
+names when the
+recipe may be executing simultaneously on several processors.
+Other maintenance tools provide mechanisms to control recipe
+scheduling explicitly [Cmel86], but
+.CW mk\fR'\fPs
+general rules are sufficient for all but the most unusual cases.
+.NH 1
+Deleting target files on errors
+.PP
+The
+.CW D
+attribute
+causes
+.CW mk
+to remove the target file when a
+recipe terminates prematurely.
+The error message describing the
+termination condition warns
+of the deletion.
+A partially built file is doubly dangerous:
+it is not only wrong, but is also
+considered to be up to date so
+a subsequent
+.CW mk
+will not rebuild it. For example,
+.P1
+pic.out:D: mk.ms
+ pic $prereq | tbl | troff -ms > $target
+.P2
+produces the message
+.P1
+.CW "mk: pic mk.ms | ... : exit status=rc 685: deleting 'pic.out'"
+.P2
+if any program in the recipe exits with an error status.
+.NH 1
+Unspecified dependencies
+.PP
+The
+.CW -w
+command line flag forces the
+files following the flag to be treated
+as if they were just modified.
+We can use this flag with a command that selects files
+to force a build based on the selection criterion.
+For example, if the declaration of
+a global variable named
+.I var
+is changed in a header file,
+all source files that reference
+it can be rebuilt with the command
+.P1
+$ mk -w`{grep -l \fIvar\fP *.[cyl]}
+.P2
+.NH 1
+Conclusion
+.PP
+There are many programs related to
+.CW make ,
+each choosing a different balance between
+specialization and generality.
+.CW Mk
+emphasizes generality but allows
+customization through its pattern specifications and
+include facilities.
+.PP
+Plan 9 presents a difficult maintenance environment
+with its heterogeneous
+architectures and languages.
+.CW Mk\fR'\fPs
+flexible specification language and simple
+interaction with
+.CW rc
+work well in this environment.
+As a result,
+Plan 9 relies on
+.CW mk
+to automate almost all maintenance.
+Tasks as diverse as updating the
+network data base, producing the manual,
+or building a release are expressed as
+.CW mk
+procedures.
+.NH 1
+References
+.LP
+[Cmel86] R. F. Cmelik,
+``Concurrent Make: A Distributed Program in Concurrent C'',
+AT&T Bell Laboratories Technical Report, 1986.
+.LP
+[Feld79] S. I. Feldman,
+``Make \(em a program for maintaining computer programs'',
+.I
+Software Practice & Experience ,
+.R
+1979
+Vol 9 #4,
+pp. 255-266.
+.LP
+[Flan95] Bob Flandrena,
+``Plan 9 Mkfiles'',
+this volume.
+.LP
+[Hume87] A. G. Hume,
+``Mk: A Successor to Make'',
+.I
+USENIX Summer Conf. Proc.,
+.R
+Phoenix, Az.
+.NH 1
+Appendix: Differences between
+.CW make
+and
+.CW mk
+.PP
+The differences between
+.CW mk
+and
+.CW make
+are:
+.IP \(bu 3n
+.CW Make
+builds targets when it needs them, allowing systematic use of side effects.
+.CW Mk
+constructs the entire dependency graph before building any target.
+.IP \(bu
+.CW Make
+supports suffix rules and
+.CW %
+metarules.
+.CW Mk
+supports
+.CW %
+and regular expression metarules.
+(Older versions of
+.CW make
+support only suffix rules.)
+.IP \(bu
+.CW Mk
+performs transitive closure on metarules,
+.CW make
+does not.
+.IP \(bu
+.CW Make
+supports cyclic dependencies,
+.CW mk
+does not.
+.IP \(bu
+.CW Make
+evaluates recipes one line at a time, replacing variables by their values and
+executing some commands internally.
+.CW Mk
+passes the entire recipe to the shell without
+interpretation or internal execution.
+.IP \(bu
+.CW Make
+supports parallel execution of single-line recipes when building
+the prerequisites for specified targets.
+.CW Mk
+supports parallel execution of all recipes.
+(Older versions of
+.CW make
+did not support parallel execution.)
+.IP \(bu
+.CW Make
+uses special targets (beginning with a period)
+to indicate special processing.
+.CW Mk
+uses attributes to modify rule evaluation.
+.IP \(bu
+.CW Mk
+supports virtual
+targets that are independent of the file system.
+.IP \(bu
+.CW Mk
+allows non-standard out-of-date determination,
+.CW make
+does not.
+.PP
+It is usually easy to convert a
+.CW makefile
+to or from an equivalent
+.CW mkfile .