HTML "Plan 9 Mkfiles
TL
Plan 9 Mkfiles
AU
Bob Flandrena
[email protected]
SH
Introduction
LP
Every Plan 9 source directory contains a file, called
CW mkfile ,
specifying the rules for building the executable or
library that is the product of the directory.
I Mk (1)
interprets the rules in the file, calculates
the dependencies, and executes an
I rc (1)
script to construct the product.
If necessary components are supplied by
neighboring directories or sub-directories, the mkfiles in those
directories are first executed to build the components
before the local construction proceeds.
LP
Most application source directories produce one of
four types of product:
a single executable, several
executables, a local library, or
a system library.
Four generic
mkfiles
define the normal rules
for building each type of product.  The simplest
mkfiles need only
list the components
and include the appropriate
generic
mkfile
to do the work.
More complex
mkfiles
may supply additional rules
to augment, modify, or override the generic rules.
SH
Using a Mkfile
LP
To build a product, change to the directory containing
its source and invoke
I mk
with the appropriate target as an argument.
All mkfiles provide the following standard targets:
TS
lw(1i) lw(4.5i).
\f(CWall\fP     T{
Build a local version of the product or products for the
current architecture.  If the product is a single program,
the result is stored in file
CW $O.out .
If the directory produces multiple executables, they are
stored in the files named
CW $O.\fIprogname,\fP
where
I progname
is the name of each executable.
A product may be built for a different architecture by
prefacing the
CW mk
command with
\f(CWobjtype=\fP\fIarchitecture\fP,
where
I architecture
is the name of the target architecture.
Directories producing system
libraries always operate directly on the installed version of the
library; in this case the target
CW all
is equivalent to the target
CW install .
T}
\f(CWinstall\fP T{
Build and install the product or products for the current
architecture.
T}
\f(CWinstallall\fP      T{
Build and install the product or products for all architectures.
T}
\f(CWclean\fP   T{
Rid the directory and its subdirectories of the by-products of
the build process.  Intermediate files that are easily reproduced
(e.g., object files,
CW yacc
intermediates, target executables) are always
removed.  Complicated intermediates, such as local libraries, are
usually preserved.
T}
\f(CWnuke\fP    T{
Remove all intermediates from the directory and any subdirectories.
This target guarantees that a subsequent build for the
architecture is performed
from scratch.
T}
TE
LP
If no target is specified on the
CW mk
command line, the
CW all
target is built by default.  In a directory
producing multiple executables, there is
no default target.
LP
In addition to the five standard targets,
additional targets may be supplied by each
generic mkfile or by the directory's mkfile.
LP
The environment variable
CW NPROC
is set by the system to the number of
available processors.
Setting
this variable, either in the environment or in
a mkfile, controls the amount of parallelism in
the build.  For example, the command
P1
       NPROC=1 mk
P2
restricts a build to a single thread of execution.
SH
Creating a Mkfile
LP
The easiest way to build a new mkfile is to copy and modify
an existing mkfile of the same type.
Failing that, it is usually possible to create a new
mkfile with minimal effort, since the appropriate
generic mkfile predefines the rules that do all the work.
In the simplest and most common cases, the new mkfile
need only define a couple of variables and include the appropriate
architecture-specific
and generic mkfiles.
SH The Generic Mkfiles
LP
There are four generic mkfiles containing commonly
used rules for building a product:
CW mkone ,
CW mkmany ,
CW mklib ,
and
CW mksyslib .
These rules
perform such actions as compiling C source files,
loading object files, archiving libraries, and
installing executables in the
CW bin
directory of the appropriate architecture.
The generic mkfiles are stored in directory
CW /sys/src/cmd .
Mkfile
CW mkone
builds a single executable,
CW mkmany
builds several executables from the source in a single
directory, and
CW mklib
and
\f(CWmksyslib\fP,
maintain local and system libraries, respectively.
The rules in the generic mkfiles are driven by
the values of variables, some of which must be
set by the product mkfile and some of which are
supplied by the generic mkfile.  Variables in the
latter class include:
TS
center;
ri ci li
rw(1i) cw(0.5i) lw(2i).
Variable        Default Meaning
sp .5
\f(CWCFLAGS\fP  \f(CW-FVw\fP    C compiler flags
\f(CWLDFLAGS\fP         Loader flags
\f(CWYFLAGS\fP  \f(CW-d\fP      Yacc flags
\f(CWAFLAGS\fP          Assembler flags
TE
LP
The following variables are set by the product mkfile
and used by the generic mkfile.
Any may be empty depending on the specific product being
made.
TS
center;
lw(1i) lw(2.5i).
\f(CWTARG\fP    Name(s) of the executable(s) to be built
\f(CWLIB\fP     Library name(s)
\f(CWOFILES\fP  Object files
\f(CWHFILES\fP  Header files included by all source files
\f(CWYFILES\fP  \f(CWYacc\fP input files
\f(CWBIN\fP     Directory where executables are installed
TE
SH
Mkfile Organization
LP
All
mkfiles
share the following common structure:
P1
</$objtype/mkfile       # \f1architecture-dependent definitions\fP
sp
\fIvariable definitions\fP              # TARG\f1, \fPOFILES\f1, \fPHFILES\f1, etc.\fP
sp
</sys/src/cmd/\fIgeneric\fP     # mkone\f1, \fPmkmany\f1, \fPmklib\f1, or \fPmksyslib
sp
\fIvariable overrides\fP                # CFLAGS\f1, \fPobjtype\f1, etc.\fP
sp
\fIextra rules\fP                       # \f1overrides, augmented rules, additional targets\fP
P2
Note that the architecture-dependent mkfiles include file
CW /sys/src/mkfile.proto
for system-wide variables that are common to all architectures.
LP
The variables driving the expansion of the generic mkfile
may be specified in any order as long as they are defined
before the inclusion of the generic mkfile.  The value
of a variable may be changed by assigning a new value
following the inclusion of the generic mkfile, but the
effects are sometimes counter-intuitive.
Such variable assignments do not apply to the target and
prerequisite portions of any previously defined rules;
the new values only apply to the recipes of rules preceding
the assignment statement and
to all parts of any rules following it.
LP
The rules supplied by the generic mkfile may
be overridden or augmented.  The new rules must
be specified after the inclusion of the generic
mkfile.  If the target and prerequisite portion
of the rule exactly match the target and prerequisite
portion of a previously defined rule and the new rule contains
a recipe, the new rule replaces the old one.
If the target of a new rule exactly matches the
target of a previous rule and one or more new
prerequisites are specified and the new rule contains
no recipe, the new prerequisites are added to the prerequisites
of the old rule.
LP
Following sections discuss
each generic mkfile in detail.
SH
Mkone
LP
The
CW mkone
generic mkfile contains rules for building
a single executable from one or more files
in a directory.
The variable
CW TARG
specifies the name of the executable and
variables
CW OFILES
and
CW YFILES
specify the object files and
CW yacc
source files used to build it.
CW HFILES
contains the names of the local header files
included in all source files.
CW BIN
is the name of the directory where the executable
is installed.
CW LIB
contains the names of local libraries used by the
linker.  This variable is rarely needed
as libraries referenced by a
CW #pragma
directive in an associated header file, including
all system libraries, are automatically
searched by the loader.
LP
If
CW mk
is executed without a target, the
CW all
target is built; it
produces an executable in
CW $O.out .
Variable
CW HFILES
identifies the header files that
are included in all or most or
the C source files.  Occasionally,
a program has other header files
that are only used in some
source files.  A
header can be added to the prerequisites for
those object files by adding a rule of
the following form following the inclusion of generic mkfile
CW mkone :
P1
file.$O:        header.h
P2
LP
The mkfile for a directory producing a single
executable using the normal set of rules is
trivial: a list of some files followed by the
inclusion of
I mkone.
For example,
CW /sys/src/cmd/diff/mkfile
contains:
P1
< /$objtype/mkfile

TARG=diff
OFILES=\e
       diffdir.$O\e
       diffio.$O\e
       diffreg.$O\e
       main.$O\e

HFILES=diff.h

BIN=/$objtype/bin
</sys/src/cmd/mkone
P2
The more complex mkfile in
CW /sys/src/cmd/awk
overrides compiler and loader variables to
select the ANSI/POSIX Computing Environment with appropriately
defined command line variables.  It also overrides
the default
CW yacc
rule to place the output soure in file
CW awkgram.c
and the
CW clean
and
CW nuke
rules, so it can remove the non-standard intermediate
files.  Finally, the last three rules build a version of
CW maketab
appropriate for the architecture where the
CW mk
is being
run and then executes it to create source file
CW proctab.c :
P1
</$objtype/mkfile

TARG=awk
OFILES=re.$O\e
       lex.$O\e
       main.$O\e
       parse.$O\e
       proctab.$O\e
       tran.$O\e
       lib.$O\e
       run.$O\e
       awkgram.$O\e

HFILES=awk.h\e
       y.tab.h\e
       proto.h\e

YFILES=awkgram.y

BIN=/$objtype/bin
</sys/src/cmd/mkone
CFLAGS=-c -D_REGEXP_EXTENSION -D_RESEARCH_SOURCE \e
       -D_BSD_EXTENSION -DUTF
YFLAGS=-S -d -v
CC=pcc
LD=pcc
cpuobjtype=`{sed -n 's/^O=//p' /$cputype/mkfile}

y.tab.h awkgram.c:      $YFILES
       $YACC -o awkgram.c $YFLAGS $prereq

clean:V:
       rm -f *.[$OS] [$OS].out [$OS].maketab y.tab.? y.debug\e
                y.output $TARG

nuke:V:
       rm -f *.[$OS] [$OS].out [$OS].maketab y.tab.? y.debug\e
                y.output awkgram.c $TARG

proctab.c:      $cpuobjtype.maketab
       ./$cpuobjtype.maketab >proctab.c

$cpuobjtype.maketab:    y.tab.h maketab.c
       objtype=$cputype
       mk maketab.$cputype

maketab.$cputype:V:     y.tab.h maketab.$O
       $LD -o $O.maketab maketab.$O
P2
SH
Mkmany
LP
The
CW mkmany
generic mkfile builds several
executables from the files in a
directory.  It differs from the operation of
CW mkone
in three respects:
CW TARG
specifies the names of all executables,
there is no default command-line target,
and additional rules allow a single executable to
be built or installed.
LP
The
CW TARG
variable specifies the names of all
executables produced by the mkfile.  The
rules assume the name of each executable is also
the name of the file containing its
CW main
function.
CW OFILES
specifies files containing
common subroutines loaded with all executables.
Consider the mkfile:
P1
</$objtype/mkfile

TARG=alpha beta
OFILES=common.$O
BIN=/$objtype/bin
</sys/src/cmd/mkmany
P2
It assumes the main functions for executables
CW alpha
and
CW beta
are in files
CW alpha.$O
and
CW beta.$O
and that both programs use the subroutines
in file
CW common.$O .
The
CW all
target builds all executables, leaving each in
a file with a name of the form
CW $O.\fIprogname\fP
where
I progname
is the name of the executable.  In this
example the
CW all
target produces executables
CW $O.alpha
and
CW $O.beta .
LP
The
CW mkmany
rules provide additional
targets for building a single
executable:
TS
lw(1i) lw(3.8i).
\f(CW$O.progname\fP     T{
Builds executable
\f(CW$O.\fP\fIprogname\fP
in the current directory.  When the target
architecture is not the current architecture
the
CW mk
command
must be prefixed with the customary
CW objtype=\fIarchitecture\fP
assignment to select the proper compilers and loaders.
T}
\f(CWprogname.install\fP        T{
Installs executable
I progname
for the target architecture.
T}
\f(CWprogname.installall\fP     T{
Installs executable
I progname
for all architectures.
T}
TE
SH
Mklib
LP
The
CW mklib
generic mkfile builds a local library.
Since this form of mkfile constructs no
executable, the
CW TARG
and
CW BIN
variables are not needed.  Instead, the
CW LIB
variable specifies the library
to be built or updated.  Variable
CW OFILES
contains the names of the object files to be archived
in the library.  The use of variables
CW YFILES
and
CW HFILES
does not change.  When possible, only the
out-of-date members of the library are updated.
LP
The variable
CW LIBDIR
contains the name of the directory where the
library is installed; by default it selects
the current directory.  It can be overridden
by assigning the new directory name after the
point where
CW mklib
is included.
LP
The
CW clean
target removes object files and
CW yacc
intermediate files but does not touch the
library.  The
CW nuke
target removes the library as well as the
files removed by the
CW clean
target.  The command
RS
CW "mk -s clean all"
RE
causes the existing library to be updated, or
created if it doesn't already exist.  The command
RS
CW "mk -s nuke all"
RE
forces the library to be rebuilt from scratch.
LP
The mkfile from
CW /sys/src/cmd/upas/libString
contains the following specifications to
build the local library
CW libString.a$O
for the object architecture referenced by
CW $O\fR\:\fP
P1
</$objtype/mkfile

LIB=libString.a$O
OFILES= s_alloc.$O\e
       s_append.$O\e
       s_array.$O\e
       s_copy.$O\e
       s_getline.$O\e
       s_grow.$O\e
       s_nappend.$O\e
       s_parse.$O\e
       s_read.$O\e
       s_read_line.$O\e
       s_tolower.$O\e

</sys/src/cmd/mklib

nuke:V:
       mk clean
       rm -f libString.a[$OS]
P2
The override of the rule for target
CW nuke
removes the libraries for all architectures as
opposed to the default recipe for this target
which removes the library for the current architecture.
SH
Mksyslib
LP
The
CW mksyslib
generic mkfile is similar to the
CW mklib
mkfile except that it operates on a system library
instead of a local library.
The
CW install
and
CW all
targets are the same; since there is no local copy of
the library, all updates are performed on the
installed library.
The rule for the
CW nuke
target is identical to that of the
CW clean
target; unlike the
CW nuke
target for local libraries,
the library is never removed.
LP
No attempt is made to determine if individual library
members are up-to-date; all members of a
library are always updated.
Special targets support manipulation of a single
object file; the target
CW objfile
updates file
CW objfile\f(CW.$O\fP
in the library of the current architecture and the target
CW objfile.all
updates
CW objfile\f(CW.$O\fP
in the libraries of all architectures.
SH
Overrides
LP
The rules provided by a generic mkfile or
the variables used to control the evaluation
of those rules may be overridden in most
circumstances.  Overrides
must be specified in the product mkfile
after the point where the generic
mkfile is included; in general, variable
and rule overrides occupy the end of a
product mkfile.
LP
The value of a variable is overridden by
assigning a new value to the variable.
Most variable overrides modify the
values of flags or the names of commands executed
in recipes.  For example, the default value of
CW CFLAGS
is often overridden or augmented and
the ANSI/POSIX Computing Environment is selected by
setting the
CW CC
and
CW LD
variables to
CW pcc.
LP
Modifying rules is trickier than modifying
variables.  Additional constraints can be added
to a rule by specifying the target and
the new prerequisite.  For example,
P1
%.$O:   header.h
P2
adds file
CW header.h
the set of prerequisites for all object files.
There is no mechanism for adding additional
commands to an existing recipe; if a
recipe is unsatisfactory, the rule and its recipe
must be completely overridden.
A rule is overridden only when the replacement rule
matches the target and prerequisite portions
of the original rule exactly.  The recipe
associated with the new rule
then replaces the recipe of the original rule.
For example,
CW /sys/src/cmd/lex/mkfile
overrides the default
CW installall
rule to perform the normal loop on all
architectures and then copy a prototype file
to the system library directory.
P1
</$objtype/mkfile

TARG=lex
OFILES=lmain.$O\e
       y.tab.$O\e
       sub1.$O\e
       sub2.$O\e
       header.$O\e

HFILES=ldefs.h\e

YFILES=parser.y\e

BIN=/$objtype/bin
</sys/src/cmd/mkone

installall:V:
       for(objtype in $CPUS)
               mk install
       cp ncform /sys/lib/lex
P2
Another way to perform the same override is to
add a dependency to the default
CW installall
rule that executes an additional rule to
install the prototype file:
P1
installall:V:   ncform.install

ncform.install:V:
       cp ncform /sys/lib/lex
P2
SH
Special Tricks
LP
Two special cases
require extra deviousness.
LP
In the first, a file needed to build an
executable is generated by a program that,
in turn, is built from a source file that
is not part of the product.  In this case,
the
executable must be built for the
target architecture, but the intermediate
executable must be built for the architecture
CW mk
is executing on.  The intermediate executable
is built by recursively invoking
CW  mk
with the appropriate target and the
executing architecture as the target
architecture.  When that
CW mk
completes, the intermediate is
executed to generate the source file to
complete the build for the target architecture.
The earlier example of
CW /sys/src/cmd/awk/mkfile
illustrates this technique.
LP
Another awkward situation
occurs when a directory contains
source to build an executable as
well as source for auxiliary executables
that are not to be installed.  In this case
the
CW mkmany
generic rules are inappropriate, because
all executables would be built and installed.
Instead, use the
CW mkone
generic file to build the primary executable
and provide extra targets to
build the auxiliary files.  This
approach is also useful when the auxiliary
files are not executables;
CW /sys/src/cmd/spell/mkfile
augments the default rules to build and install the
CW spell
executable with
elaborate rules to generate
and maintain the auxiliary spelling lists.