summaryrefslogtreecommitdiff
path: root/sys/doc/mk.ms
blob: 1a556e9b69a82c7555a9bb7524c2cf5f755d8773 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
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 .