shithub: riscv

ref: 28f4567ba615c4036c079021392825757ef2a008
dir: /sys/doc/mkfiles.ms/

View raw version
.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.