Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/main.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* make - maintain and update programs
26
*
27
* history
28
*
29
* 1970's pre-make (research)
30
* .
31
* .
32
* 1976 make S. I. Feldman
33
* . .
34
* . .
35
* . .
36
* . .
37
* 1978 augmented-make . E. G. Bradford
38
* . . . .
39
* . . . .
40
* . . . .
41
* . . . .
42
* 1979 build . . . V. B. Erickson, J. F. Pellegrin
43
* . . . .
44
* . . . .
45
* 1984 . . V8-make S. I. Feldman
46
* . . . .
47
* . . . .
48
* . . . .
49
* . . . .
50
* . . . .
51
* . . . .
52
* . . . .
53
* 1985 . nmake . G. S. Fowler
54
* . . . .
55
* . . . .
56
* . . . .
57
* 1986 LC-nmake . . J. E. Shopiro, M. S. Freeland
58
* . . . .
59
* . . . mk A. G. Hume
60
* . . . . .
61
* 1987 . nmake . . G. S. Fowler
62
* . . . .
63
* (1.4) . . .
64
* . . . .
65
* . . . .
66
* . . . .
67
* 1988 nmake . G. S. Fowler
68
* . .
69
* (2.0) .
70
* . .
71
* 1990 (2.1) .
72
* . .
73
* 1991 (2.2) .
74
* . .
75
* 1992 (2.3) .
76
* . .
77
* 1993 (3.0) .
78
* . .
79
* 1994 (3.1) .
80
* . .
81
* 1995 (3.2) . AT&T Bell Labs
82
* . .
83
* 1996 (3.3) . AT&T Research (Lucent split)
84
* . .
85
* 1997 (3.4) . AT&T Research
86
* . .
87
* 1998 (3.5) . AT&T Research
88
* . .
89
* 1999 (3.6) . AT&T Research
90
* . .
91
* 2000 (4.0) . AT&T Research
92
* . .
93
* 2001 (4.1) . AT&T Research
94
* 2002 (4.2) . AT&T Research
95
* 2003 (4.3) . AT&T Research
96
* 2004 (4.4) . AT&T Research
97
* 2005 (5.0) . AT&T Research
98
* 2006 (5.1) . AT&T Research
99
* 2007 (5.2) . AT&T Research
100
* 2008 (5.3) . AT&T Research
101
* 2009 (5.4) . AT&T Research
102
* 2010 (5.5) . AT&T Research
103
* 2011 (5.6) . AT&T Research
104
* 2012 (5.7) . AT&T Research
105
*
106
* command line arguments are of three types
107
*
108
* make [ [ option ] [ script ] [ target ] ... ]
109
*
110
* options are described in options.h
111
*
112
* debug trace levels are controlled by error_info.trace
113
* debug level n enables tracing for all levels less than or equal to n
114
* levels 4 and higher are conditionally compiled with DEBUG!=0
115
* if debug level < 20 then all levels are disabled during early bootstrap
116
* if debug level = 1 then all levels are disabled until after .INIT is made
117
*
118
* level trace
119
* 0 no trace
120
* 1 basic make trace
121
* 2 major actions
122
* 3 option settings, make object files
123
* 4 state variables
124
* 5 directory and archive scan, some OPT_explain'ations
125
* 6 coshell commands and messages
126
* 7 makefile input lines
127
* 8 lexical analyzer states
128
* 9 metarules applied
129
* 10 variable expansions
130
* 11 bindfile() trace
131
* 12 files added to hash
132
* 13 new atoms
133
* 14 hash table usage
134
* ...
135
* 20 bootstrap trace
136
*
137
* state.questionable registry (looks like it should go but not sure)
138
*
139
* 0x00000001 *temporary*
140
* 0x00000002 *temporary*
141
* 0x00000004 *temporary* disable bind_p "- ..." and "... ..." virtual logic
142
* 0x00000008 1996-10-11 meta rhs prefix dir check even if rhs has prefix
143
* 0x00000010 1994-01-01 old out of date if prereq in higher view
144
* 0x00000020 1994-01-01 old scan advance logic
145
* 0x00000040 2001-10-20 foiled alias still allows bind (!1994-08-11)
146
* 0x00000080 1994-08-11 don't catrule() ../.. dir prefixes in bindfile()
147
* 0x00000100 1994-10-01 metaclose() recursion even if rule.action!=0
148
* 0x00000200 1994-11-11 disable generate() % transformation check
149
* 0x00000400 1995-01-19 forceread even if global
150
* 0x00000800 1995-07-17 D_global if not P_target in bindfile()
151
* 0x00001000 1995-07-17 less agressive aliasing in bindfile()
152
* 0x00002000 1995-07-17 less agressive putbound() in bindalias()
153
* 0x00004000 1995-11-11 P_target && D_dynamic does not imply generated
154
* 0x00008000 1996-02-29 :P=D: returns at most one dir per item
155
* 0x00010000 1996-10-11 don't alias check path suffixes in bindfile()
156
* 0x00020000 1998-11-11 don't force require_p make() recheck
157
* 0x00040000 1999-09-07 generate() intermediates only if (sep & LT)
158
* 0x00080000 1999-11-19 disable touch steady state loop
159
* 0x00100000 2000-02-14 apply metarule even if dir on unbound lhs
160
* 0x00200000 2000-09-08 0x00100000 implied if !P_implicit
161
* 0x00400000 2001-02-14 allow P_archive to break job deadlock
162
* 0x00800000 2001-10-05 disable early r->status=FAILED when errors!=0
163
* 0x01000000 2002-10-02 $(>) doesn't check min(rule.time,state.time)
164
* 0x02000000 2002-12-04 don't inhibit .UNBIND of M_bind rules
165
* 0x04000000 2004-01-20 don't include triggered time==0 targets in :T=F:
166
* 0x08000000 2004-10-01 metaget does not assume % target for ... : % .NULL
167
* 0x10000000 2007-01-08 :P=D: alias check
168
* 0x20000000 2007-06-15 disable :W: . alias check
169
* 0x40000000 2007-06-20 don't include intermediate makefile dirs in :W:
170
* 0x80000000 2007-08-28 don't force reassoc bindalias()
171
*
172
* state.test registry (conditionally compiled with DEBUG!=0)
173
*
174
* 0x00000001 *temporary*
175
* 0x00000002 *temporary*
176
* 0x00000004 *temporary*
177
* 0x00000008 bindfile() directory prune trace
178
* 0x00000010 expand() trace
179
* 0x00000020 force external archive table of contents generation
180
* 0x00000040 bindalias() trace
181
* 0x00000080 scan state trace
182
* 0x00000100 statetime() trace
183
* 0x00000200 staterule() view trace
184
* 0x00000400 more staterule() view trace
185
* 0x00000800 mergestate() trace
186
* 0x00001000 job status trace
187
* 0x00002000 dump Vmheap stats on exit
188
* 0x00004000 dump atom address with name
189
* 0x00008000 force state file garbage collection
190
* 0x00010000 alarm status trace
191
* 0x00020000 close internal.openfd before job exec
192
* 0x00040000 set failed state|metarule event to staterule event
193
* 0x00080000 replace ' ' with '?' instead of FILE_SPACE
194
* 0x00100000 scan action trace
195
*/
196
197
#include "make.h"
198
#include "options.h"
199
200
#include <sig.h>
201
#include <stak.h>
202
#include <vecargs.h>
203
#include <vmalloc.h>
204
205
#define settypes(c,t) for(s=c;*s;settype(*s++,t))
206
207
#ifndef PATHCHECK
208
#define PATHCHECK IDNAME
209
#endif
210
211
/*
212
* global initialization -- external engine names are defined in initrule()
213
*/
214
215
Internal_t internal; /* internal rules and vars */
216
State_t state; /* program state */
217
Tables_t table; /* hash table info */
218
char null[] = ""; /* null string */
219
char tmpname[MAXNAME];/* temporary name buffer */
220
short ctypes[UCHAR_MAX+1];/* istype() character types */
221
222
/*
223
* user error message intercept
224
*/
225
226
static int
227
intercept(Sfio_t* sp, int level, int flags)
228
{
229
register Rule_t* r;
230
char* m;
231
char* s;
232
char* t;
233
char* e;
234
int n;
235
int i;
236
Sfio_t* tmp;
237
238
NoP(sp);
239
NoP(flags);
240
if ((state.mam.level = level) > 0 && !state.hold && (r = internal.error) && (r->property & (P_functional|P_target)) == (P_functional|P_target) && !state.compileonly && !state.interrupt && (m = stakptr(0)) && (n = staktell()) > 0)
241
{
242
/*
243
* make the error trap
244
*/
245
246
state.hold = m;
247
while (*m && *m != ':')
248
m++;
249
while (isspace(*++m));
250
n -= m - state.hold;
251
tmp = sfstropen();
252
sfprintf(tmp, "%d %-.*s", level, n, m);
253
s = sfstruse(tmp);
254
255
/*
256
* return [ level | - ] [ message ]
257
* level is new level or - to retain old
258
* omitted message means it has been printed
259
*/
260
261
if (t = call(r, s))
262
{
263
i = strtol(t, &e, 0);
264
if (e > t)
265
{
266
t = e;
267
level = i;
268
}
269
else if (*t == '-')
270
t++;
271
while (isspace(*t))
272
t++;
273
}
274
if (!t || !*t)
275
{
276
level |= ERROR_OUTPUT;
277
message((-1, "suppressed %s message: `%-.*s'", level == 1 ? "warning" : "error", n, m));
278
}
279
sfstrclose(tmp);
280
state.hold = 0;
281
}
282
return level;
283
}
284
285
/*
286
* make entry point
287
*/
288
289
int
290
main(int argc, char** argv)
291
{
292
register char* s;
293
register Rule_t* r;
294
register List_t* p;
295
int i;
296
int args;
297
int trace;
298
char* t;
299
char* buf;
300
char* tok;
301
Var_t* v;
302
Stat_t st;
303
Stat_t ds;
304
Sfio_t* tmp;
305
306
/*
307
* initialize dynamic globals
308
*/
309
310
version = strdup(fmtident(version));
311
setlocale(LC_ALL, "");
312
error_info.id = idname;
313
error_info.version = version;
314
error_info.exit = finish;
315
error_info.auxilliary = intercept;
316
if (pathcheck(PATHCHECK, error_info.id, NiL))
317
return 1;
318
error(-99, "startup");
319
settypes("*?[]", C_MATCH);
320
settypes("+-|=", C_OPTVAL);
321
settypes(" \t\n", C_SEP);
322
settype(0, C_SEP);
323
settypes(" \t\v\n:+&=;\"\\", C_TERMINAL);
324
settype(0, C_TERMINAL);
325
settypes("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_", C_ID1|C_ID2|C_VARIABLE1|C_VARIABLE2);
326
settypes(".", C_VARIABLE1|C_VARIABLE2);
327
settypes("0123456789", C_ID2|C_VARIABLE2);
328
329
/*
330
* close garbage fd's -- we'll be tidy from this point on
331
* 3 may be /dev/tty on some systems
332
* 0..9 for user redirection in shell
333
* 10..19 left open by bugs in some shells
334
* error_info.fd interited from parent
335
* any close-on-exec fd's must have been done on our behalf
336
*/
337
338
i = 3;
339
if (isatty(i))
340
i++;
341
for (; i < 20; i++)
342
if (i != error_info.fd && !fcntl(i, F_GETFD, 0))
343
close(i);
344
345
/*
346
* allocate the very temporary buffer streams
347
*/
348
349
internal.met = sfstropen();
350
internal.nam = sfstropen();
351
internal.tmp = sfstropen();
352
internal.val = sfstropen();
353
internal.wrk = sfstropen();
354
tmp = sfstropen();
355
sfstrrsrv(tmp, 2 * MAXNAME);
356
357
/*
358
* initialize the code and hash tables
359
*/
360
361
initcode();
362
inithash();
363
364
/*
365
* set the default state
366
*/
367
368
state.alias = 1;
369
state.exec = 1;
370
state.global = 1;
371
state.init = 1;
372
#if DEBUG
373
state.intermediate = 1;
374
#endif
375
state.io[0] = sfstdin;
376
state.io[1] = sfstdout;
377
state.io[2] = sfstderr;
378
state.jobs = 1;
379
state.pid = getpid();
380
state.readstate = MAXVIEW;
381
state.scan = 1;
382
state.start = CURTIME;
383
state.stateview = -1;
384
state.tabstops = 8;
385
state.targetview = -1;
386
#if BINDINDEX
387
state.view[0].path = makerule(".");
388
#else
389
state.view[0].path = ".";
390
#endif
391
state.view[0].pathlen = 1;
392
state.writeobject = state.writestate = "-";
393
394
/*
395
* pwd initialization
396
*
397
* for project management, if . is group|other writeable
398
* then change umask() for similar write protections
399
*/
400
401
buf = sfstrbase(tmp);
402
internal.pwd = (s = getcwd(buf, MAXNAME)) ? strdup(s) : strdup(".");
403
internal.pwdlen = strlen(internal.pwd);
404
if (stat(".", &st))
405
error(3, "cannot stat .");
406
if (S_ISDIR(st.st_mode) && (st.st_mode & (S_IWGRP|S_IWOTH)))
407
umask(umask(0) & ~(st.st_mode & (S_IWGRP|S_IWOTH)));
408
409
/*
410
* set some variable default values
411
*/
412
413
hashclear(table.var, HASH_ALLOCATE);
414
setvar(external.make, argv[0], V_import);
415
t = "lib/make";
416
setvar(external.lib, strdup((s = pathpath(t, argv[0], PATH_EXECUTE, buf, SF_BUFSIZE)) ? s : t), V_import);
417
setvar(external.pwd, internal.pwd, V_import);
418
setvar(external.version, version, V_import);
419
hashset(table.var, HASH_ALLOCATE);
420
421
/*
422
* read the environment
423
*/
424
425
readenv();
426
if (v = getvar(external.nproc))
427
state.jobs = (int)strtol(v->value, NiL, 0);
428
if ((v = getvar(external.pwd)) && !streq(v->value, internal.pwd))
429
{
430
if (!stat(v->value, &st) && !stat(internal.pwd, &ds) && st.st_ino == ds.st_ino && st.st_dev == ds.st_dev)
431
{
432
free(internal.pwd);
433
internal.pwd = strdup(v->value);
434
internal.pwdlen = strlen(v->value);
435
}
436
else
437
{
438
v->property &= ~V_import;
439
v->property |= V_free;
440
v->value = strdup(internal.pwd);
441
}
442
}
443
444
/*
445
* initialize the internal rule pointers
446
*/
447
448
initrule();
449
450
/*
451
* read the static initialization script
452
*/
453
454
sfputr(tmp, initstatic, -1);
455
parse(NiL, sfstruse(tmp), "initstatic", NiL);
456
457
/*
458
* check and read the args file
459
*/
460
461
if (s = colonlist(tmp, external.args, 1, ' '))
462
{
463
i = fs3d(0);
464
tok = tokopen(s, 1);
465
while (s = tokread(tok))
466
if (vecargs(vecfile(s), &argc, &argv) >= 0)
467
break;
468
else if (errno != ENOENT)
469
error(1, "cannot read args file %s", s);
470
tokclose(tok);
471
fs3d(i);
472
}
473
state.argf = newof(0, int, argc, 0);
474
475
/*
476
* set the command line options
477
* read the command line assignments
478
* mark the command line scripts and targets
479
*/
480
481
state.init = 0;
482
state.readonly = 1;
483
state.argv = argv;
484
state.argc = argc;
485
if ((args = scanargs(state.argc, state.argv, state.argf)) < 0)
486
return 1;
487
state.readonly = 0;
488
state.init = 1;
489
if (state.base)
490
state.readstate = 0;
491
if (state.compileonly)
492
{
493
state.forceread = 1;
494
state.virtualdot = 0;
495
}
496
497
/*
498
* tone down the bootstrap noise
499
*/
500
501
if ((trace = error_info.trace) == -1)
502
error_info.trace = 0;
503
504
/*
505
* check explicit environment overrides
506
*/
507
508
if (s = colonlist(tmp, external.import, 1, ' '))
509
{
510
tok = tokopen(s, 1);
511
while (s = tokread(tok))
512
{
513
if (i = *s == '!')
514
s++;
515
if (v = getvar(s))
516
{
517
if (i)
518
v->property &= ~V_import;
519
else
520
v->property |= V_readonly;
521
}
522
}
523
tokclose(tok);
524
}
525
526
/*
527
* set up the traps
528
*/
529
530
inittrap();
531
532
/*
533
* announce the version
534
*/
535
536
if (error_info.trace < 0)
537
{
538
errno = 0;
539
error(error_info.trace, "%s [%d %s]", version, state.pid, timestr(state.start));
540
}
541
542
/*
543
* initialize the views
544
*/
545
546
state.global = 0;
547
state.user = 1;
548
initview();
549
550
/*
551
* check for mam
552
*/
553
554
if (state.mam.out)
555
{
556
if (!state.mam.statix || *state.mam.label)
557
error_info.write = mamerror;
558
if (state.mam.regress || state.regress)
559
{
560
sfprintf(state.mam.out, "%sinfo mam %s %05d\n", state.mam.label, state.mam.type, state.mam.parent);
561
if (state.mam.regress)
562
sfprintf(state.mam.out, "%sinfo start regression\n", state.mam.label);
563
}
564
else
565
{
566
sfprintf(state.mam.out, "%sinfo mam %s %05d 1994-07-17 %s\n", state.mam.label, state.mam.type, state.mam.parent, version);
567
if (!state.mam.statix || *state.mam.label)
568
{
569
sfprintf(state.mam.out, "%sinfo start %lu\n", state.mam.label, CURTIME);
570
if (!state.mam.root || streq(state.mam.root, internal.pwd))
571
sfprintf(state.mam.out, "%sinfo pwd %s\n", state.mam.label, internal.pwd);
572
else
573
sfprintf(state.mam.out, "%sinfo pwd %s %s\n", state.mam.label, state.mam.root, mamname(makerule(internal.pwd)));
574
buf = sfstrbase(tmp);
575
if (state.fsview && !mount(NiL, buf, FS3D_GET|FS3D_ALL|FS3D_SIZE(sfstrsize(tmp)), NiL))
576
sfprintf(state.mam.out, "%sinfo view %s\n", state.mam.label, buf);
577
}
578
}
579
}
580
581
/*
582
* read the dynamic initialization script
583
*/
584
585
if ((i = error_info.trace) > -20)
586
error_info.trace = 0;
587
sfputr(tmp, initdynamic, -1);
588
parse(NiL, sfstruse(tmp), "initdynamic", NiL);
589
error_info.trace = i;
590
state.user = 0;
591
state.init = 0;
592
593
/*
594
* read the explicit makefiles
595
* readfile() handles the base and global rules
596
*
597
* NOTE: internal.tmplist is used to handle the effects of
598
* load() on internal list pointers
599
*/
600
601
compref(NiL, 0);
602
if (p = internal.makefiles->prereqs)
603
{
604
p = internal.tmplist->prereqs = listcopy(p);
605
for (; p; p = p->next)
606
readfile(p->rule->name, COMP_FILE, NiL);
607
freelist(internal.tmplist->prereqs);
608
internal.tmplist->prereqs = 0;
609
}
610
611
/*
612
* if no explicit makefiles then try external.{convert,files}
613
*/
614
615
if (!state.makefile)
616
{
617
int sep;
618
Sfio_t* exp;
619
Sfio_t* imp;
620
621
exp = 0;
622
imp = sfstropen();
623
sep = 0;
624
s = 0;
625
if (*(t = getval(external.convert, VAL_PRIMARY)))
626
{
627
sfputr(tmp, t, 0);
628
sfstrrsrv(tmp, MAXNAME);
629
tok = tokopen(sfstrbase(tmp), 0);
630
while (s = tokread(tok))
631
{
632
if (!exp)
633
exp = sfstropen();
634
if (t = colonlist(exp, s, 0, ' '))
635
{
636
t = tokopen(t, 0);
637
while (s = tokread(t))
638
{
639
if (readfile(s, COMP_INCLUDE|COMP_DONTCARE, NiL))
640
break;
641
if (sep)
642
sfputc(imp, ',');
643
else
644
sep = 1;
645
sfputr(imp, s, -1);
646
}
647
tokclose(t);
648
if (s)
649
break;
650
}
651
if (!(s = tokread(tok)))
652
break;
653
}
654
tokclose(tok);
655
sfstrseek(tmp, 0, SEEK_SET);
656
}
657
if (!s && (s = colonlist(tmp, external.files, 1, ' ')))
658
{
659
tok = tokopen(s, 1);
660
while (s = tokread(tok))
661
{
662
if (readfile(s, COMP_INCLUDE|COMP_DONTCARE, NiL))
663
break;
664
if (sep)
665
sfputc(imp, ',');
666
else
667
sep = 1;
668
sfputr(imp, s, -1);
669
}
670
tokclose(tok);
671
}
672
if (!s)
673
{
674
/*
675
* this readfile() pulls in the default base rules
676
* that might resolve any delayed self-documenting
677
* options in optcheck()
678
*/
679
680
if (readfile("-", COMP_FILE, NiL))
681
optcheck(1);
682
if (*(s = sfstruse(imp)))
683
error(state.errorid ? 1 : 3, "a makefile must be specified when %s omitted", s);
684
else
685
error(state.errorid ? 1 : 3, "a makefile must be specified");
686
}
687
sfstrclose(imp);
688
if (exp)
689
sfstrclose(exp);
690
}
691
692
/*
693
* validate external command line options
694
*/
695
696
optcheck(1);
697
698
/*
699
* check for listing of variable and rule definitions
700
*/
701
702
if (state.list)
703
{
704
dump(sfstdout, 0);
705
return 0;
706
}
707
708
/*
709
* check if makefiles to be compiled
710
*/
711
712
if (state.compile && !state.virtualdot && state.writeobject)
713
{
714
/*
715
* make the compinit trap
716
*/
717
718
if (r = getrule(external.compinit))
719
{
720
state.reading = 1;
721
maketop(r, P_dontcare|P_foreground, NiL);
722
state.reading = 0;
723
}
724
if (state.exec && state.objectfile)
725
{
726
message((-2, "compiling makefile input into %s", state.objectfile));
727
compile(state.objectfile, NiL);
728
}
729
730
/*
731
* make the compdone trap
732
*/
733
734
if (r = getrule(external.compdone))
735
{
736
state.reading = 1;
737
maketop(r, P_dontcare|P_foreground, NiL);
738
state.reading = 0;
739
}
740
}
741
742
/*
743
* makefile read cleanup
744
*/
745
746
if (state.compileonly)
747
return 0;
748
compref(NiL, 0);
749
sfstrclose(tmp);
750
state.compile = COMPILED;
751
if (state.believe)
752
{
753
if (!state.maxview)
754
state.believe = 0;
755
else if (state.fsview)
756
error(3, "%s: option currently works in 2d only", optflag(OPT_believe)->name);
757
}
758
759
/*
760
* read the state file
761
*/
762
763
readstate();
764
765
/*
766
* place the command line targets in internal.args
767
*/
768
769
if (internal.main->dynamic & D_dynamic)
770
dynamic(internal.main);
771
internal.args->prereqs = p = 0;
772
for (i = args; i < state.argc; i++)
773
if (state.argf[i] & ARG_TARGET)
774
{
775
List_t* q;
776
777
q = cons(makerule(state.argv[i]), NiL);
778
if (p)
779
p = p->next = q;
780
else
781
internal.args->prereqs = p = q;
782
}
783
784
/*
785
* the engine bootstrap is complete -- start user activities
786
*/
787
788
state.user = 1;
789
790
/*
791
* make the makeinit trap
792
*/
793
794
if (r = getrule(external.makeinit))
795
maketop(r, P_dontcare|P_foreground, NiL);
796
797
/*
798
* read the command line scripts
799
*/
800
801
for (i = args; i < state.argc; i++)
802
if (state.argf[i] & ARG_SCRIPT)
803
{
804
state.reading = 1;
805
parse(NiL, state.argv[i], "command line script", NiL);
806
state.reading = 0;
807
}
808
809
/*
810
* freeze the parameter files and candidate state variables
811
*/
812
813
state.user = 2;
814
candidates();
815
816
/*
817
* make the init trap
818
*/
819
820
if (r = getrule(external.init))
821
maketop(r, P_dontcare|P_foreground, NiL);
822
823
/*
824
* internal.args default to internal.main
825
*/
826
827
if (!internal.args->prereqs && internal.main->prereqs)
828
internal.args->prereqs = listcopy(internal.main->prereqs);
829
830
/*
831
* turn up the volume again
832
*/
833
834
if (!error_info.trace)
835
error_info.trace = trace;
836
837
/*
838
* make the prerequisites of internal.args
839
*/
840
841
if (internal.args->prereqs)
842
while (internal.args->prereqs)
843
{
844
/*
845
* we explicitly allow internal.args modifications
846
*/
847
848
r = internal.args->prereqs->rule;
849
internal.making->prereqs = internal.args->prereqs;
850
internal.args->prereqs = internal.args->prereqs->next;
851
internal.making->prereqs->next = 0;
852
maketop(r, 0, NiL);
853
}
854
else if (state.makefile)
855
error(3, "%s: a main target must be specified", state.makefile);
856
857
/*
858
* finish up
859
*/
860
861
finish(0);
862
return 0;
863
}
864
865
/*
866
* clean up and exit
867
*/
868
869
void
870
finish(int n)
871
{
872
Rule_t* r;
873
int i;
874
875
/*
876
* old error intercept
877
*/
878
879
if (!state.hold && (r = internal.error) && (r->property & (P_target|P_functional)) == P_target)
880
{
881
state.hold = null;
882
if (n && error_info.errors && !state.compileonly && !state.interrupt)
883
{
884
if (r->status == NOTYET)
885
maketop(r, P_dontcare|P_foreground, NiL);
886
state.hold = 0;
887
if (r->status == EXISTS)
888
{
889
r->status = NOTYET;
890
return;
891
}
892
}
893
}
894
895
/*
896
* children exit without cleanup
897
*/
898
899
if (getpid() != state.pid)
900
_exit(n);
901
unparse(0);
902
switch (state.finish)
903
{
904
905
case 0:
906
/*
907
* disable listing and wait for any jobs to finish
908
*/
909
910
state.finish++;
911
alarm(0);
912
state.list = 0;
913
message((-1, "%s cleanup", state.interrupt ? "interrupt" : n > 0 ? "error" : "normal"));
914
complete(NiL, NiL, NiL, 0);
915
/*FALLTHROUGH*/
916
917
case 1:
918
/*
919
* make the done trap
920
*/
921
922
state.finish++;
923
if (!state.compileonly && (r = getrule(external.done)))
924
maketop(r, P_dontcare, NiL);
925
/*FALLTHROUGH*/
926
927
case 2:
928
/*
929
* make the makedone trap
930
*/
931
932
state.finish++;
933
if (!state.compileonly && (r = getrule(external.makedone)))
934
maketop(r, P_dontcare, NiL);
935
/*FALLTHROUGH*/
936
937
case 3:
938
/*
939
* wait for any job(s) to finish
940
*/
941
942
state.finish++;
943
complete(NiL, NiL, NiL, 0);
944
/*FALLTHROUGH*/
945
946
case 4:
947
/*
948
* put all jobs in foreground and save state
949
*/
950
951
state.finish++;
952
state.jobs = 0;
953
savestate();
954
/*FALLTHROUGH*/
955
956
case 5:
957
/*
958
* clean up temporaries
959
*/
960
961
state.finish++;
962
remtmp(1);
963
/*FALLTHROUGH*/
964
965
case 6:
966
/*
967
* drop the coshell
968
*/
969
970
state.finish++;
971
drop();
972
/*FALLTHROUGH*/
973
974
case 7:
975
/*
976
* dump
977
*/
978
979
state.finish++;
980
if (state.test & 0x00002000)
981
{
982
Vmstat_t vs;
983
984
vmstat(Vmheap, &vs);
985
error(0, "vm region %lu segments %lu busy %lu:%lu:%lu free %lu:%lu:%lu", vs.extent, vs.n_seg, vs.n_busy, vs.s_busy, vs.m_busy, vs.n_free, vs.s_free, vs.m_free);
986
}
987
dump(sfstdout, error_info.trace <= -14);
988
/*FALLTHROUGH*/
989
990
case 8:
991
/*
992
* final output
993
*/
994
995
state.finish++;
996
if (state.errors && state.keepgoing && !n)
997
n = 1;
998
if (state.mam.out)
999
{
1000
if (state.mam.regress)
1001
sfprintf(state.mam.out, "%sinfo finish regression\n", state.mam.label);
1002
else if (state.mam.dynamic || *state.mam.label)
1003
sfprintf(state.mam.out, "%sinfo finish %lu %d\n", state.mam.label, CURTIME, n);
1004
}
1005
for (i = 0; i < elementsof(state.io); i++)
1006
if (state.io[i] != sfstdin && state.io[i] != sfstdout && state.io[i] != sfstderr)
1007
sfclose(state.io[i]);
1008
if (state.errors && state.keepgoing)
1009
error(2, "*** %d action%s failed", state.errors, state.errors == 1 ? null : "s");
1010
message((-1, "%s exit", state.interrupt ? "interrupt" : n ? "error" : "normal"));
1011
break;
1012
1013
}
1014
if (state.interrupt)
1015
{
1016
n = 3;
1017
signal(state.interrupt, SIG_DFL);
1018
kill(getpid(), state.interrupt);
1019
pause();
1020
}
1021
exit(n);
1022
}
1023
1024