Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bmake/compat.c
39475 views
1
/* $NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $ */
2
3
/*
4
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
5
* All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Adam de Boor.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
/*
36
* Copyright (c) 1988, 1989 by Adam de Boor
37
* Copyright (c) 1989 by Berkeley Softworks
38
* All rights reserved.
39
*
40
* This code is derived from software contributed to Berkeley by
41
* Adam de Boor.
42
*
43
* Redistribution and use in source and binary forms, with or without
44
* modification, are permitted provided that the following conditions
45
* are met:
46
* 1. Redistributions of source code must retain the above copyright
47
* notice, this list of conditions and the following disclaimer.
48
* 2. Redistributions in binary form must reproduce the above copyright
49
* notice, this list of conditions and the following disclaimer in the
50
* documentation and/or other materials provided with the distribution.
51
* 3. All advertising materials mentioning features or use of this software
52
* must display the following acknowledgement:
53
* This product includes software developed by the University of
54
* California, Berkeley and its contributors.
55
* 4. Neither the name of the University nor the names of its contributors
56
* may be used to endorse or promote products derived from this software
57
* without specific prior written permission.
58
*
59
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69
* SUCH DAMAGE.
70
*/
71
72
/*
73
* This file implements the full-compatibility mode of make, which makes the
74
* targets without parallelism and without a custom shell.
75
*
76
* Interface:
77
* Compat_MakeAll Initialize this module and make the given targets.
78
*/
79
80
#ifdef HAVE_CONFIG_H
81
# include "config.h"
82
#endif
83
#include <sys/types.h>
84
#include <sys/stat.h>
85
#include "wait.h"
86
87
#include <errno.h>
88
#include <signal.h>
89
90
#include "make.h"
91
#include "dir.h"
92
#include "job.h"
93
#ifdef USE_META
94
# include "meta.h"
95
#endif
96
#include "metachar.h"
97
#include "pathnames.h"
98
99
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
100
MAKE_RCSID("$NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $");
101
102
static GNode *curTarg;
103
static pid_t compatChild;
104
static int compatSigno;
105
106
/*
107
* Delete the file of a failed, interrupted, or otherwise duffed target,
108
* unless inhibited by .PRECIOUS.
109
*/
110
static void
111
CompatDeleteTarget(GNode *gn)
112
{
113
if (!GNode_IsPrecious(gn) &&
114
(gn->type & OP_PHONY) == 0) {
115
const char *file = GNode_VarTarget(gn);
116
if (!opts.noExecute && unlink_file(file) == 0)
117
Error("*** %s removed", file);
118
}
119
}
120
121
/*
122
* Interrupt the creation of the current target and remove it if it ain't
123
* precious. Then exit.
124
*
125
* If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED.
126
*
127
* XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've
128
* left the logic alone for now. - dholland 20160826
129
*/
130
static void
131
CompatInterrupt(int signo)
132
{
133
if (curTarg != NULL) {
134
CompatDeleteTarget(curTarg);
135
if (signo == SIGINT && !GNode_IsPrecious(curTarg)) {
136
GNode *gn = Targ_FindNode(".INTERRUPT");
137
if (gn != NULL)
138
Compat_Make(gn, gn);
139
}
140
}
141
142
if (signo == SIGQUIT)
143
_exit(signo);
144
145
/*
146
* If there is a child running, pass the signal on.
147
* We will exist after it has exited.
148
*/
149
compatSigno = signo;
150
if (compatChild > 0) {
151
KILLPG(compatChild, signo);
152
} else {
153
bmake_signal(signo, SIG_DFL);
154
kill(myPid, signo);
155
}
156
}
157
158
static void
159
DebugFailedTarget(const char *cmd, const GNode *gn)
160
{
161
const char *p = cmd;
162
debug_printf("\n*** Failed target: %s\n*** Failed command: ",
163
gn->name);
164
165
/*
166
* Replace runs of whitespace with a single space, to reduce the
167
* amount of whitespace for multi-line command lines.
168
*/
169
while (*p != '\0') {
170
if (ch_isspace(*p)) {
171
debug_printf(" ");
172
cpp_skip_whitespace(&p);
173
} else {
174
debug_printf("%c", *p);
175
p++;
176
}
177
}
178
debug_printf("\n");
179
}
180
181
static bool
182
UseShell(const char *cmd MAKE_ATTR_UNUSED)
183
{
184
#if defined(FORCE_USE_SHELL) || !defined(MAKE_NATIVE)
185
/*
186
* In a non-native build, the host environment might be weird enough
187
* that it's necessary to go through a shell to get the correct
188
* behaviour. Or perhaps the shell has been replaced with something
189
* that does extra logging, and that should not be bypassed.
190
*/
191
return true;
192
#else
193
/*
194
* Search for meta characters in the command. If there are no meta
195
* characters, there's no need to execute a shell to execute the
196
* command.
197
*
198
* Additionally variable assignments and empty commands
199
* go to the shell. Therefore treat '=' and ':' like shell
200
* meta characters as documented in make(1).
201
*/
202
203
return needshell(cmd);
204
#endif
205
}
206
207
static int
208
Compat_Spawn(const char **av)
209
{
210
int pid = FORK_FUNCTION();
211
if (pid < 0)
212
Fatal("Could not fork");
213
214
if (pid == 0) {
215
#ifdef USE_META
216
if (useMeta)
217
meta_compat_child();
218
#endif
219
(void)execvp(av[0], (char *const *)UNCONST(av));
220
execDie("exec", av[0]);
221
}
222
return pid;
223
}
224
225
/*
226
* Execute the next command for a target. If the command returns an error,
227
* the node's made field is set to ERROR and creation stops.
228
*
229
* Input:
230
* cmdp Command to execute
231
* gn Node from which the command came
232
* ln List node that contains the command
233
*
234
* Results:
235
* true if the command succeeded.
236
*/
237
bool
238
Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
239
{
240
char *cmdStart; /* Start of expanded command */
241
char *volatile bp;
242
bool silent; /* Don't print command */
243
bool doIt; /* Execute even if -n */
244
volatile bool errCheck; /* Check errors */
245
WAIT_T reason; /* Reason for child's death */
246
WAIT_T status; /* Description of child's death */
247
pid_t retstat; /* Result of wait */
248
const char **av; /* Arguments for the child process */
249
char **volatile mav; /* Copy of the argument vector for freeing */
250
bool useShell; /* True if command should be executed using a
251
* shell */
252
const char *cmd = cmdp;
253
char cmd_file[MAXPATHLEN];
254
size_t cmd_len;
255
int parseErrorsBefore;
256
257
silent = (gn->type & OP_SILENT) != OP_NONE;
258
errCheck = !(gn->type & OP_IGNORE);
259
doIt = false;
260
261
parseErrorsBefore = parseErrors;
262
cmdStart = Var_SubstInTarget(cmd, gn);
263
if (parseErrors != parseErrorsBefore) {
264
free(cmdStart);
265
return false;
266
}
267
268
if (cmdStart[0] == '\0') {
269
free(cmdStart);
270
return true;
271
}
272
cmd = cmdStart;
273
LstNode_Set(ln, cmdStart);
274
275
if (gn->type & OP_SAVE_CMDS) {
276
GNode *endNode = Targ_GetEndNode();
277
if (gn != endNode) {
278
/*
279
* Append the expanded command, to prevent the
280
* local variables from being interpreted in the
281
* scope of the .END node.
282
*
283
* A probably unintended side effect of this is that
284
* the expanded command will be expanded again in the
285
* .END node. Therefore, a literal '$' in these
286
* commands must be written as '$$$$' instead of the
287
* usual '$$'.
288
*/
289
Lst_Append(&endNode->commands, cmdStart);
290
goto register_command;
291
}
292
}
293
if (strcmp(cmdStart, "...") == 0) {
294
gn->type |= OP_SAVE_CMDS;
295
register_command:
296
Parse_RegisterCommand(cmdStart);
297
return true;
298
}
299
300
for (;;) {
301
if (*cmd == '@')
302
silent = !DEBUG(LOUD);
303
else if (*cmd == '-')
304
errCheck = false;
305
else if (*cmd == '+')
306
doIt = true;
307
else if (!ch_isspace(*cmd))
308
/* Ignore whitespace for compatibility with gnu make */
309
break;
310
cmd++;
311
}
312
313
if (cmd[0] == '\0')
314
goto register_command;
315
316
useShell = UseShell(cmd);
317
318
if (!silent || !GNode_ShouldExecute(gn)) {
319
printf("%s\n", cmd);
320
fflush(stdout);
321
}
322
323
if (!doIt && !GNode_ShouldExecute(gn))
324
goto register_command;
325
326
DEBUG1(JOB, "Execute: '%s'\n", cmd);
327
328
cmd_len = strlen(cmd);
329
if (cmd_len > MAKE_CMDLEN_LIMIT)
330
useShell = true;
331
else
332
cmd_file[0] = '\0';
333
334
if (useShell) {
335
static const char *shargv[5];
336
337
Cmd_Argv(cmd, cmd_len, shargv, cmd_file, sizeof(cmd_file),
338
errCheck && shellErrFlag != NULL, DEBUG(SHELL));
339
av = shargv;
340
bp = NULL;
341
mav = NULL;
342
} else {
343
Words words = Str_Words(cmd, false);
344
mav = words.words;
345
bp = words.freeIt;
346
av = (void *)mav;
347
}
348
349
#ifdef USE_META
350
if (useMeta)
351
meta_compat_start();
352
#endif
353
354
Var_ReexportVars(gn);
355
Var_ExportStackTrace(gn->name, cmd);
356
357
compatChild = Compat_Spawn(av);
358
free(mav);
359
free(bp);
360
361
/* XXX: Memory management looks suspicious here. */
362
/* XXX: Setting a list item to NULL is unexpected. */
363
LstNode_SetNull(ln);
364
365
#ifdef USE_META
366
if (useMeta)
367
meta_compat_parent(compatChild);
368
#endif
369
370
/* The child is off and running. Now all we can do is wait... */
371
while ((retstat = wait(&reason)) != compatChild) {
372
if (retstat > 0)
373
JobReapChild(retstat, reason, false); /* not ours? */
374
if (retstat == -1 && errno != EINTR)
375
break;
376
}
377
378
if (retstat < 0)
379
Fatal("error in wait: %d: %s", retstat, strerror(errno));
380
381
if (WIFSTOPPED(reason)) {
382
status = WSTOPSIG(reason);
383
} else if (WIFEXITED(reason)) {
384
status = WEXITSTATUS(reason);
385
#if defined(USE_META) && defined(USE_FILEMON_ONCE)
386
if (useMeta)
387
meta_cmd_finish(NULL);
388
#endif
389
if (status != 0) {
390
if (DEBUG(ERROR))
391
DebugFailedTarget(cmd, gn);
392
printf("*** Error code %d", status);
393
}
394
} else {
395
status = WTERMSIG(reason);
396
printf("*** Signal %d", status);
397
}
398
399
400
if (!WIFEXITED(reason) || status != 0) {
401
if (errCheck) {
402
#ifdef USE_META
403
if (useMeta)
404
meta_job_error(NULL, gn, false, status);
405
#endif
406
gn->made = ERROR;
407
if (WIFEXITED(reason))
408
gn->exit_status = status;
409
if (opts.keepgoing) {
410
/*
411
* Abort the current target,
412
* but let others continue.
413
*/
414
printf(" (continuing)\n");
415
} else {
416
printf("\n");
417
}
418
if (deleteOnError)
419
CompatDeleteTarget(gn);
420
} else {
421
/*
422
* Continue executing commands for this target.
423
* If we return 0, this will happen...
424
*/
425
printf(" (ignored)\n");
426
status = 0;
427
}
428
fflush(stdout);
429
}
430
431
free(cmdStart);
432
if (cmd_file[0] != '\0')
433
unlink(cmd_file);
434
compatChild = 0;
435
if (compatSigno != 0) {
436
bmake_signal(compatSigno, SIG_DFL);
437
kill(myPid, compatSigno);
438
}
439
440
return status == 0;
441
}
442
443
static void
444
RunCommands(GNode *gn)
445
{
446
StringListNode *ln;
447
448
for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
449
const char *cmd = ln->datum;
450
if (!Compat_RunCommand(cmd, gn, ln))
451
break;
452
}
453
}
454
455
static void
456
MakeInRandomOrder(GNode **gnodes, GNode **end, GNode *pgn)
457
{
458
GNode **it;
459
size_t r;
460
461
for (r = (size_t)(end - gnodes); r >= 2; r--) {
462
/* Biased, but irrelevant in practice. */
463
size_t i = (size_t)random() % r;
464
GNode *t = gnodes[r - 1];
465
gnodes[r - 1] = gnodes[i];
466
gnodes[i] = t;
467
}
468
469
for (it = gnodes; it != end; it++)
470
Compat_Make(*it, pgn);
471
}
472
473
static void
474
MakeWaitGroupsInRandomOrder(GNodeList *gnodes, GNode *pgn)
475
{
476
Vector vec;
477
GNodeListNode *ln;
478
GNode **nodes;
479
size_t i, n, start;
480
481
Vector_Init(&vec, sizeof(GNode *));
482
for (ln = gnodes->first; ln != NULL; ln = ln->next)
483
*(GNode **)Vector_Push(&vec) = ln->datum;
484
nodes = vec.items;
485
n = vec.len;
486
487
start = 0;
488
for (i = 0; i < n; i++) {
489
if (nodes[i]->type & OP_WAIT) {
490
MakeInRandomOrder(nodes + start, nodes + i, pgn);
491
Compat_Make(nodes[i], pgn);
492
start = i + 1;
493
}
494
}
495
MakeInRandomOrder(nodes + start, nodes + i, pgn);
496
497
Vector_Done(&vec);
498
}
499
500
static void
501
MakeNodes(GNodeList *gnodes, GNode *pgn)
502
{
503
GNodeListNode *ln;
504
505
if (Lst_IsEmpty(gnodes))
506
return;
507
if (opts.randomizeTargets) {
508
MakeWaitGroupsInRandomOrder(gnodes, pgn);
509
return;
510
}
511
512
for (ln = gnodes->first; ln != NULL; ln = ln->next) {
513
GNode *cgn = ln->datum;
514
Compat_Make(cgn, pgn);
515
}
516
}
517
518
static bool
519
MakeUnmade(GNode *gn, GNode *pgn)
520
{
521
522
assert(gn->made == UNMADE);
523
524
/*
525
* First mark ourselves to be made, then apply whatever transformations
526
* the suffix module thinks are necessary. Once that's done, we can
527
* descend and make all our children. If any of them has an error
528
* but the -k flag was given, our 'make' field will be set to false
529
* again. This is our signal to not attempt to do anything but abort
530
* our parent as well.
531
*/
532
gn->flags.remake = true;
533
gn->made = BEINGMADE;
534
535
if (!(gn->type & OP_MADE))
536
Suff_FindDeps(gn);
537
538
MakeNodes(&gn->children, gn);
539
540
if (!gn->flags.remake) {
541
gn->made = ABORTED;
542
pgn->flags.remake = false;
543
return false;
544
}
545
546
if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL)
547
Var_Set(pgn, IMPSRC, GNode_VarTarget(gn));
548
549
/*
550
* All the children were made ok. Now youngestChild->mtime contains the
551
* modification time of the newest child, we need to find out if we
552
* exist and when we were modified last. The criteria for datedness
553
* are defined by GNode_IsOODate.
554
*/
555
DEBUG1(MAKE, "Examining %s...", gn->name);
556
if (!GNode_IsOODate(gn)) {
557
gn->made = UPTODATE;
558
DEBUG0(MAKE, "up-to-date.\n");
559
return false;
560
}
561
562
/*
563
* If the user is just seeing if something is out-of-date, exit now
564
* to tell him/her "yes".
565
*/
566
DEBUG0(MAKE, "out-of-date.\n");
567
if (opts.query && gn != Targ_GetEndNode())
568
exit(1);
569
570
/*
571
* We need to be re-made.
572
* Ensure that $? (.OODATE) and $> (.ALLSRC) are both set.
573
*/
574
GNode_SetLocalVars(gn);
575
576
/*
577
* Alter our type to tell if errors should be ignored or things
578
* should not be printed so Compat_RunCommand knows what to do.
579
*/
580
if (opts.ignoreErrors)
581
gn->type |= OP_IGNORE;
582
if (opts.silent)
583
gn->type |= OP_SILENT;
584
585
if (Job_CheckCommands(gn, Fatal)) {
586
if (!opts.touch || (gn->type & OP_MAKE)) {
587
curTarg = gn;
588
#ifdef USE_META
589
if (useMeta && GNode_ShouldExecute(gn))
590
meta_job_start(NULL, gn);
591
#endif
592
RunCommands(gn);
593
curTarg = NULL;
594
} else {
595
Job_Touch(gn, (gn->type & OP_SILENT) != OP_NONE);
596
}
597
} else {
598
gn->made = ERROR;
599
}
600
#ifdef USE_META
601
if (useMeta && GNode_ShouldExecute(gn)) {
602
if (meta_job_finish(NULL) != 0)
603
gn->made = ERROR;
604
}
605
#endif
606
607
if (gn->made != ERROR) {
608
/*
609
* If the node was made successfully, mark it so, update
610
* its modification time and timestamp all its parents.
611
* This is to keep its state from affecting that of its parent.
612
*/
613
gn->made = MADE;
614
if (Make_Recheck(gn) == 0)
615
pgn->flags.force = true;
616
if (!(gn->type & OP_EXEC)) {
617
pgn->flags.childMade = true;
618
GNode_UpdateYoungestChild(pgn, gn);
619
}
620
} else if (opts.keepgoing) {
621
pgn->flags.remake = false;
622
} else {
623
PrintOnError(gn, "\nStop.\n");
624
exit(1);
625
}
626
return true;
627
}
628
629
static void
630
MakeOther(GNode *gn, GNode *pgn)
631
{
632
633
if (Lst_FindDatum(&gn->implicitParents, pgn) != NULL) {
634
const char *target = GNode_VarTarget(gn);
635
Var_Set(pgn, IMPSRC, target != NULL ? target : "");
636
}
637
638
switch (gn->made) {
639
case BEINGMADE:
640
Error("Graph cycles through %s", gn->name);
641
gn->made = ERROR;
642
pgn->flags.remake = false;
643
break;
644
case MADE:
645
if (!(gn->type & OP_EXEC)) {
646
pgn->flags.childMade = true;
647
GNode_UpdateYoungestChild(pgn, gn);
648
}
649
break;
650
case UPTODATE:
651
if (!(gn->type & OP_EXEC))
652
GNode_UpdateYoungestChild(pgn, gn);
653
break;
654
default:
655
break;
656
}
657
}
658
659
/*
660
* Make a target.
661
*
662
* If an error is detected and not being ignored, the process exits.
663
*
664
* Input:
665
* gn The node to make
666
* pgn Parent to abort if necessary
667
*
668
* Output:
669
* gn->made
670
* UPTODATE gn was already up-to-date.
671
* MADE gn was recreated successfully.
672
* ERROR An error occurred while gn was being created,
673
* either due to missing commands or in -k mode.
674
* ABORTED gn was not remade because one of its
675
* dependencies could not be made due to errors.
676
*/
677
void
678
Compat_Make(GNode *gn, GNode *pgn)
679
{
680
if (shellName == NULL) /* we came here from jobs */
681
Shell_Init();
682
683
if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) {
684
if (!MakeUnmade(gn, pgn))
685
goto cohorts;
686
687
/* XXX: Replace with GNode_IsError(gn) */
688
} else if (gn->made == ERROR) {
689
/*
690
* Already had an error when making this.
691
* Tell the parent to abort.
692
*/
693
pgn->flags.remake = false;
694
} else {
695
MakeOther(gn, pgn);
696
}
697
698
cohorts:
699
MakeNodes(&gn->cohorts, pgn);
700
}
701
702
static void
703
MakeBeginNode(void)
704
{
705
GNode *gn = Targ_FindNode(".BEGIN");
706
if (gn == NULL)
707
return;
708
709
Compat_Make(gn, gn);
710
if (GNode_IsError(gn)) {
711
PrintOnError(gn, "\nStop.\n");
712
exit(1);
713
}
714
}
715
716
static void
717
InitSignals(void)
718
{
719
if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN)
720
bmake_signal(SIGINT, CompatInterrupt);
721
if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN)
722
bmake_signal(SIGTERM, CompatInterrupt);
723
if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN)
724
bmake_signal(SIGHUP, CompatInterrupt);
725
if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN)
726
bmake_signal(SIGQUIT, CompatInterrupt);
727
}
728
729
void
730
Compat_MakeAll(GNodeList *targets)
731
{
732
GNode *errorNode = NULL;
733
734
if (shellName == NULL)
735
Shell_Init();
736
737
InitSignals();
738
739
/*
740
* Create the .END node now, to keep the (debug) output of the
741
* counter.mk test the same as before 2020-09-23. This
742
* implementation detail probably doesn't matter though.
743
*/
744
(void)Targ_GetEndNode();
745
746
if (!opts.query)
747
MakeBeginNode();
748
749
/*
750
* Expand .USE nodes right now, because they can modify the structure
751
* of the tree.
752
*/
753
Make_ExpandUse(targets);
754
755
while (!Lst_IsEmpty(targets)) {
756
GNode *gn = Lst_Dequeue(targets);
757
Compat_Make(gn, gn);
758
759
if (gn->made == UPTODATE) {
760
printf("`%s' is up to date.\n", gn->name);
761
} else if (gn->made == ABORTED) {
762
printf("`%s' not remade because of errors.\n",
763
gn->name);
764
}
765
if (GNode_IsError(gn) && errorNode == NULL)
766
errorNode = gn;
767
}
768
769
if (errorNode == NULL) {
770
GNode *endNode = Targ_GetEndNode();
771
Compat_Make(endNode, endNode);
772
if (GNode_IsError(endNode))
773
errorNode = endNode;
774
}
775
776
if (errorNode != NULL) {
777
if (DEBUG(GRAPH2))
778
Targ_PrintGraph(2);
779
else if (DEBUG(GRAPH3))
780
Targ_PrintGraph(3);
781
PrintOnError(errorNode, "\nStop.\n");
782
exit(1);
783
}
784
}
785
786