1*7e440d19Scheloha /* $OpenBSD: engine.c,v 1.74 2024/04/09 15:08:21 cheloha Exp $ */
2a6b963c8Sespie /*
3a6b963c8Sespie * Copyright (c) 2012 Marc Espie.
4a6b963c8Sespie *
5a6b963c8Sespie * Extensive code modifications for the OpenBSD project.
6a6b963c8Sespie *
7a6b963c8Sespie * Redistribution and use in source and binary forms, with or without
8a6b963c8Sespie * modification, are permitted provided that the following conditions
9a6b963c8Sespie * are met:
10a6b963c8Sespie * 1. Redistributions of source code must retain the above copyright
11a6b963c8Sespie * notice, this list of conditions and the following disclaimer.
12a6b963c8Sespie * 2. Redistributions in binary form must reproduce the above copyright
13a6b963c8Sespie * notice, this list of conditions and the following disclaimer in the
14a6b963c8Sespie * documentation and/or other materials provided with the distribution.
15a6b963c8Sespie *
16a6b963c8Sespie * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
17a6b963c8Sespie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a6b963c8Sespie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a6b963c8Sespie * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
20a6b963c8Sespie * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a6b963c8Sespie * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a6b963c8Sespie * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a6b963c8Sespie * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a6b963c8Sespie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a6b963c8Sespie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a6b963c8Sespie * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a6b963c8Sespie */
28a6f1883eSespie /*
29a6f1883eSespie * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
30a6f1883eSespie * Copyright (c) 1988, 1989 by Adam de Boor
31a6f1883eSespie * Copyright (c) 1989 by Berkeley Softworks
32a6f1883eSespie * All rights reserved.
33a6f1883eSespie *
34a6f1883eSespie * This code is derived from software contributed to Berkeley by
35a6f1883eSespie * Adam de Boor.
36a6f1883eSespie *
37a6f1883eSespie * Redistribution and use in source and binary forms, with or without
38a6f1883eSespie * modification, are permitted provided that the following conditions
39a6f1883eSespie * are met:
40a6f1883eSespie * 1. Redistributions of source code must retain the above copyright
41a6f1883eSespie * notice, this list of conditions and the following disclaimer.
42a6f1883eSespie * 2. Redistributions in binary form must reproduce the above copyright
43a6f1883eSespie * notice, this list of conditions and the following disclaimer in the
44a6f1883eSespie * documentation and/or other materials provided with the distribution.
45a6f1883eSespie * 3. Neither the name of the University nor the names of its contributors
46a6f1883eSespie * may be used to endorse or promote products derived from this software
47a6f1883eSespie * without specific prior written permission.
48a6f1883eSespie *
49a6f1883eSespie * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50a6f1883eSespie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51a6f1883eSespie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52a6f1883eSespie * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53a6f1883eSespie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54a6f1883eSespie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55a6f1883eSespie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56a6f1883eSespie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57a6f1883eSespie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58a6f1883eSespie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59a6f1883eSespie * SUCH DAMAGE.
60a6f1883eSespie */
61a6f1883eSespie
6232e144d7Sespie #include <sys/types.h>
63a6b963c8Sespie #include <sys/time.h>
6432e144d7Sespie #include <sys/wait.h>
656c2dbbdaSespie #include <assert.h>
6632e144d7Sespie #include <ctype.h>
67a6f1883eSespie #include <errno.h>
68a6f1883eSespie #include <fcntl.h>
691f89b472Sespie #include <limits.h>
7032e144d7Sespie #include <signal.h>
711f89b472Sespie #include <stdint.h>
721f89b472Sespie #include <stdio.h>
731f89b472Sespie #include <stdlib.h>
741f89b472Sespie #include <string.h>
751f89b472Sespie #include <unistd.h>
76a6f1883eSespie #include "defines.h"
77e2e5a33cSespie #include "cmd_exec.h"
78a6f1883eSespie #include "dir.h"
79a6f1883eSespie #include "engine.h"
80a6f1883eSespie #include "arch.h"
81a6f1883eSespie #include "gnode.h"
82a6f1883eSespie #include "targ.h"
83a6f1883eSespie #include "var.h"
84a6f1883eSespie #include "extern.h"
85a6f1883eSespie #include "lst.h"
86a6f1883eSespie #include "timestamp.h"
87438dc521Sespie #include "main.h"
88a6f1883eSespie #include "make.h"
8932e144d7Sespie #include "pathnames.h"
9032e144d7Sespie #include "error.h"
9132e144d7Sespie #include "memory.h"
923d97cd1aSespie #include "buf.h"
931ef353c6Sespie #include "job.h"
94a6b963c8Sespie #include "lowparse.h"
95a6f1883eSespie
96a6f1883eSespie static void MakeTimeStamp(void *, void *);
97fd5a6224Sespie static int rewrite_time(const char *);
981bae8e1fSespie static void list_parents(GNode *, FILE *);
9932e144d7Sespie
100b12bcd0dSespie /* XXX due to a bug in make's logic, targets looking like *.a or -l*
101b12bcd0dSespie * have been silently dropped when make couldn't figure them out.
102b12bcd0dSespie * Now, we warn about them until all Makefile bugs have been fixed.
103b12bcd0dSespie */
104b12bcd0dSespie static bool
drop_silently(const char * s)105b12bcd0dSespie drop_silently(const char *s)
106b12bcd0dSespie {
107b12bcd0dSespie size_t len;
108b12bcd0dSespie
109b12bcd0dSespie if (s[0] == '-' && s[1] == 'l')
110b12bcd0dSespie return true;
111b12bcd0dSespie
112b12bcd0dSespie len = strlen(s);
113b12bcd0dSespie if (len >=2 && s[len-2] == '.' && s[len-1] == 'a')
114b12bcd0dSespie return true;
115b12bcd0dSespie return false;
116b12bcd0dSespie }
117b12bcd0dSespie
118a6f1883eSespie bool
node_find_valid_commands(GNode * gn)119a6b963c8Sespie node_find_valid_commands(GNode *gn)
120a6f1883eSespie {
121694f1218Sespie if (DEBUG(DOUBLE) && (gn->type & OP_DOUBLE))
122694f1218Sespie fprintf(stderr, "Warning: target %s had >1 lists of "
123694f1218Sespie "shell commands (ignoring later ones)\n", gn->name);
1241bae8e1fSespie if (OP_NOP(gn->type) && Lst_IsEmpty(&gn->commands)) {
125b12bcd0dSespie if (drop_silently(gn->name)) {
1261bae8e1fSespie printf("Warning: target %s", gn->name);
1271bae8e1fSespie list_parents(gn, stdout);
128b12bcd0dSespie printf(" does not have any command (BUG)\n");
1291bae8e1fSespie return true;
1301bae8e1fSespie }
131a6f1883eSespie /*
132a6f1883eSespie * No commands. Look for .DEFAULT rule from which we might infer
133a6f1883eSespie * commands
134a6f1883eSespie */
135323bf4e3Sespie if ((gn->type & OP_NODEFAULT) == 0 &&
136323bf4e3Sespie (DEFAULT->type & OP_DUMMY) == 0 &&
137866fd206Sespie !Lst_IsEmpty(&DEFAULT->commands)) {
138a6f1883eSespie /*
139df7262edSespie * Make only looks for a .DEFAULT if the node was never
140df7262edSespie * the target of an operator, so that's what we do too.
141df7262edSespie * If a .DEFAULT was given, we substitute its commands
142df7262edSespie * for gn's commands and set the IMPSRC variable to be
143df7262edSespie * the target's name The DEFAULT node acts like a
144df7262edSespie * transformation rule, in that gn also inherits any
145df7262edSespie * attributes or sources attached to .DEFAULT itself.
146a6f1883eSespie */
147a6f1883eSespie Make_HandleUse(DEFAULT, gn);
1483d97cd1aSespie Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn);
149a6f1883eSespie } else if (is_out_of_date(Dir_MTime(gn))) {
150a6f1883eSespie /*
151df7262edSespie * The node wasn't the target of an operator we have no
152df7262edSespie * .DEFAULT rule to go on and the target doesn't
153df7262edSespie * already exist. There's nothing more we can do for
1546c2dbbdaSespie * this branch.
1556c2dbbdaSespie */
1566c2dbbdaSespie return false;
1576c2dbbdaSespie }
1586c2dbbdaSespie }
1596c2dbbdaSespie return true;
1606c2dbbdaSespie }
1616c2dbbdaSespie
1621bae8e1fSespie static void
list_parents(GNode * gn,FILE * out)1631bae8e1fSespie list_parents(GNode *gn, FILE *out)
1641bae8e1fSespie {
1651bae8e1fSespie LstNode ln;
1661bae8e1fSespie bool first = true;
1671bae8e1fSespie
1681bae8e1fSespie for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln)) {
1691bae8e1fSespie GNode *p = Lst_Datum(ln);
1701bae8e1fSespie if (!p->must_make)
1711bae8e1fSespie continue;
1721bae8e1fSespie if (first) {
1731bae8e1fSespie fprintf(out, " (prerequisite of:");
1741bae8e1fSespie first = false;
1751bae8e1fSespie }
1761bae8e1fSespie fprintf(out, " %s", p->name);
1771bae8e1fSespie }
1781bae8e1fSespie if (!first)
1791bae8e1fSespie fprintf(out, ")");
1801bae8e1fSespie }
1811bae8e1fSespie
1826c2dbbdaSespie void
node_failure(GNode * gn)183a6b963c8Sespie node_failure(GNode *gn)
1846c2dbbdaSespie {
1856c2dbbdaSespie /*
1866c2dbbdaSespie If the -k flag wasn't given, we stop in
187df7262edSespie * our tracks, otherwise we just don't update this
188df7262edSespie * node's parents so they never get examined.
189a6f1883eSespie */
1901bae8e1fSespie const char *diag;
1911bae8e1fSespie FILE *out;
192a6f1883eSespie
193a6f1883eSespie if (gn->type & OP_OPTIONAL) {
1941bae8e1fSespie out = stdout;
1951bae8e1fSespie diag = "(ignored)";
196a6f1883eSespie } else if (keepgoing) {
1971bae8e1fSespie out = stdout;
1981bae8e1fSespie diag = "(continuing)";
199a6f1883eSespie } else {
2001bae8e1fSespie out = stderr;
2011bae8e1fSespie diag = "";
2021bae8e1fSespie }
2031bae8e1fSespie fprintf(out, "make: don't know how to make %s", gn->name);
2041bae8e1fSespie list_parents(gn, out);
2051bae8e1fSespie fprintf(out, "%s\n", diag);
2061bae8e1fSespie if (out == stdout)
2071bae8e1fSespie fflush(stdout);
2081bae8e1fSespie else {
209a6b963c8Sespie print_errors();
210438dc521Sespie dump_unreadable();
211a6b963c8Sespie Punt(NULL);
212a6f1883eSespie }
213a6f1883eSespie }
214a6b963c8Sespie
215fd5a6224Sespie /* touch files the hard way, by writing stuff to them */
216fd5a6224Sespie static int
rewrite_time(const char * name)217fd5a6224Sespie rewrite_time(const char *name)
218fd5a6224Sespie {
219fd5a6224Sespie int fd;
220fd5a6224Sespie char c;
221fd5a6224Sespie
222fd5a6224Sespie fd = open(name, O_RDWR | O_CREAT, 0666);
223fd5a6224Sespie if (fd < 0)
224fd5a6224Sespie return -1;
225fd5a6224Sespie /*
226fd5a6224Sespie * Read and write a byte to the file to change
227fd5a6224Sespie * the modification time.
228fd5a6224Sespie */
229fd5a6224Sespie if (read(fd, &c, 1) == 1) {
230fd5a6224Sespie (void)lseek(fd, 0, SEEK_SET);
231fd5a6224Sespie (void)write(fd, &c, 1);
232fd5a6224Sespie }
233fd5a6224Sespie
234fd5a6224Sespie (void)close(fd);
235fd5a6224Sespie return 0;
236fd5a6224Sespie }
237fd5a6224Sespie
238a6f1883eSespie void
Job_Touch(GNode * gn)239cae88e06Sespie Job_Touch(GNode *gn)
240a6f1883eSespie {
241a6b963c8Sespie handle_all_signals();
24218cc0328Sespie if (gn->type & (OP_USE|OP_OPTIONAL|OP_PHONY)) {
243a6f1883eSespie /*
244866fd206Sespie * .JOIN, .USE, and .OPTIONAL targets are "virtual" targets
245866fd206Sespie * and, as such, shouldn't really be created.
24678086188Sespie * Likewise, .PHONY targets are not really files
247a6f1883eSespie */
248a6f1883eSespie return;
249a6f1883eSespie }
250a6f1883eSespie
2514b65af26Sespie if (!Targ_Silent(gn)) {
252a6f1883eSespie (void)fprintf(stdout, "touch %s\n", gn->name);
253a6f1883eSespie (void)fflush(stdout);
254a6f1883eSespie }
255a6f1883eSespie
256a6f1883eSespie if (noExecute) {
257a6f1883eSespie return;
258a6f1883eSespie }
259a6f1883eSespie
260a6f1883eSespie if (gn->type & OP_ARCHV) {
261a6f1883eSespie Arch_Touch(gn);
262a6f1883eSespie } else {
263a6f1883eSespie const char *file = gn->path != NULL ? gn->path : gn->name;
264a6f1883eSespie
265*7e440d19Scheloha if (utimes(file, NULL) == -1){
266fd5a6224Sespie if (rewrite_time(file) == -1) {
26719e54df6Sgsoares (void)fprintf(stderr,
268df7262edSespie "*** couldn't touch %s: %s", file,
269df7262edSespie strerror(errno));
270a6f1883eSespie }
271a6f1883eSespie }
272a6f1883eSespie }
273a6f1883eSespie }
274a6f1883eSespie
275a6f1883eSespie void
Make_TimeStamp(GNode * parent,GNode * child)276687d3c4eSespie Make_TimeStamp(GNode *parent, GNode *child)
277a6f1883eSespie {
27823a9ff7bSespie if (is_strictly_before(parent->youngest->mtime, child->mtime)) {
2791ea29b92Sespie parent->youngest = child;
2801ea29b92Sespie }
281a6f1883eSespie }
282a6f1883eSespie
283a6f1883eSespie void
Make_HandleUse(GNode * cgn,GNode * pgn)284866fd206Sespie Make_HandleUse(GNode *cgn, /* The .USE node */
285a6f1883eSespie GNode *pgn) /* The target of the .USE node */
286a6f1883eSespie {
287a6f1883eSespie GNode *gn; /* A child of the .USE node */
288a6f1883eSespie LstNode ln; /* An element in the children list */
289a6f1883eSespie
2906c2dbbdaSespie assert(cgn->type & (OP_USE|OP_TRANSFORM));
2916c2dbbdaSespie
29268097c0dSespie if (pgn == NULL)
29368097c0dSespie Fatal("Trying to apply .USE to '%s' without a parent",
29468097c0dSespie cgn->name);
29568097c0dSespie
296a6f1883eSespie if ((cgn->type & OP_USE) || Lst_IsEmpty(&pgn->commands)) {
297866fd206Sespie /* .USE or transformation and target has no commands
298866fd206Sespie * -- append the child's commands to the parent. */
299a6f1883eSespie Lst_Concat(&pgn->commands, &cgn->commands);
300a6f1883eSespie }
301a6f1883eSespie
302df7262edSespie for (ln = Lst_First(&cgn->children); ln != NULL;
303df7262edSespie ln = Lst_Adv(ln)) {
304568f6c05Sespie gn = Lst_Datum(ln);
305a6f1883eSespie
306a6f1883eSespie if (Lst_AddNew(&pgn->children, gn)) {
307a6f1883eSespie Lst_AtEnd(&gn->parents, pgn);
308194f6eccSespie pgn->children_left++;
309a6f1883eSespie }
310a6f1883eSespie }
311a6f1883eSespie
312694f1218Sespie if (DEBUG(DOUBLE) && (cgn->type & OP_DOUBLE))
313694f1218Sespie fprintf(stderr,
314694f1218Sespie "Warning: .USE %s expanded in %s had >1 lists of "
315694f1218Sespie "shell commands (ignoring later ones)\n",
316694f1218Sespie cgn->name, pgn->name);
317694f1218Sespie pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM|OP_DOUBLE);
318a6f1883eSespie
319a6f1883eSespie /*
320194f6eccSespie * This child node is now built, so we decrement the count of
321194f6eccSespie * not yet built children in the parent... We also remove the child
322df7262edSespie * from the parent's list to accurately reflect the number of
323194f6eccSespie * remaining children the parent has. This is used by Make_Run to
324866fd206Sespie * decide whether to queue the parent or examine its children...
325a6f1883eSespie */
326866fd206Sespie if (cgn->type & OP_USE)
327194f6eccSespie pgn->children_left--;
328a6f1883eSespie }
329a6f1883eSespie
3303d97cd1aSespie void
Make_DoAllVar(GNode * gn)3313d97cd1aSespie Make_DoAllVar(GNode *gn)
332a6f1883eSespie {
3333d97cd1aSespie GNode *child;
3343d97cd1aSespie LstNode ln;
3353d97cd1aSespie BUFFER allsrc, oodate;
3363d97cd1aSespie char *target;
3373d97cd1aSespie bool do_oodate;
3383d97cd1aSespie int oodate_count, allsrc_count = 0;
339a6f1883eSespie
3403d97cd1aSespie oodate_count = 0;
3413d97cd1aSespie allsrc_count = 0;
3423d97cd1aSespie
343466b8ac5Sespie Var(OODATE_INDEX, gn) = "";
344466b8ac5Sespie Var(ALLSRC_INDEX, gn) = "";
345466b8ac5Sespie
3463d97cd1aSespie for (ln = Lst_First(&gn->children); ln != NULL; ln = Lst_Adv(ln)) {
347568f6c05Sespie child = Lst_Datum(ln);
34818cc0328Sespie if ((child->type & (OP_USE|OP_INVISIBLE)) != 0)
3493d97cd1aSespie continue;
350866fd206Sespie if (OP_NOP(child->type) ||
3513d97cd1aSespie (target = Var(TARGET_INDEX, child)) == NULL) {
352a6f1883eSespie /*
353df7262edSespie * this node is only source; use the specific pathname
354df7262edSespie * for it
355a6f1883eSespie */
356866fd206Sespie target = child->path != NULL ? child->path :
357866fd206Sespie child->name;
358a6f1883eSespie }
359a6f1883eSespie
360a6f1883eSespie /*
3613d97cd1aSespie * It goes in the OODATE variable if the parent is younger than
3623d97cd1aSespie * the child or if the child has been modified more recently
3633d97cd1aSespie * than the start of the make. This is to keep make from
3643d97cd1aSespie * getting confused if something else updates the parent after
3653d97cd1aSespie * the make starts (shouldn't happen, I know, but sometimes it
3663d97cd1aSespie * does). In such a case, if we've updated the kid, the parent
3673d97cd1aSespie * is likely to have a modification time later than that of the
3683d97cd1aSespie * kid and anything that relies on the OODATE variable will be
3693d97cd1aSespie * hosed.
370a6f1883eSespie */
3713d97cd1aSespie do_oodate = false;
37218cc0328Sespie if (is_strictly_before(gn->mtime, child->mtime) ||
3734c9de429Sespie (!is_strictly_before(child->mtime, starttime) &&
374ed90eef3Sespie child->built_status == REBUILT))
3753d97cd1aSespie do_oodate = true;
3763d97cd1aSespie if (do_oodate) {
3773d97cd1aSespie oodate_count++;
3783d97cd1aSespie if (oodate_count == 1)
3793d97cd1aSespie Var(OODATE_INDEX, gn) = target;
3803d97cd1aSespie else {
3813d97cd1aSespie if (oodate_count == 2) {
3823d97cd1aSespie Buf_Init(&oodate, 0);
3833d97cd1aSespie Buf_AddString(&oodate,
3843d97cd1aSespie Var(OODATE_INDEX, gn));
385a6f1883eSespie }
3863d97cd1aSespie Buf_AddSpace(&oodate);
3873d97cd1aSespie Buf_AddString(&oodate, target);
3883d97cd1aSespie }
3893d97cd1aSespie }
3903d97cd1aSespie allsrc_count++;
3913d97cd1aSespie if (allsrc_count == 1)
3923d97cd1aSespie Var(ALLSRC_INDEX, gn) = target;
3933d97cd1aSespie else {
3943d97cd1aSespie if (allsrc_count == 2) {
3953d97cd1aSespie Buf_Init(&allsrc, 0);
3963d97cd1aSespie Buf_AddString(&allsrc,
3973d97cd1aSespie Var(ALLSRC_INDEX, gn));
3983d97cd1aSespie }
3993d97cd1aSespie Buf_AddSpace(&allsrc);
4003d97cd1aSespie Buf_AddString(&allsrc, target);
401a6f1883eSespie }
402a6f1883eSespie }
403a6f1883eSespie
4043d97cd1aSespie if (allsrc_count > 1)
4053d97cd1aSespie Var(ALLSRC_INDEX, gn) = Buf_Retrieve(&allsrc);
4063d97cd1aSespie if (oodate_count > 1)
4073d97cd1aSespie Var(OODATE_INDEX, gn) = Buf_Retrieve(&oodate);
408a6f1883eSespie
4094d303f06Sespie if (gn->impliedsrc)
4103d97cd1aSespie Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn->impliedsrc);
411a6f1883eSespie }
412a6f1883eSespie
413a6f1883eSespie /* Wrapper to call Make_TimeStamp from a forEach loop. */
414a6f1883eSespie static void
MakeTimeStamp(void * parent,void * child)415866fd206Sespie MakeTimeStamp(void *parent, void *child)
416a6f1883eSespie {
4177f5855dcSespie Make_TimeStamp(parent, child);
418a6f1883eSespie }
419a6f1883eSespie
420a6f1883eSespie bool
Make_OODate(GNode * gn)421866fd206Sespie Make_OODate(GNode *gn)
422a6f1883eSespie {
423a6f1883eSespie bool oodate;
424a6f1883eSespie
425a6f1883eSespie /*
426a6f1883eSespie * Certain types of targets needn't even be sought as their datedness
427a6f1883eSespie * doesn't depend on their modification time...
428a6f1883eSespie */
42918cc0328Sespie if ((gn->type & (OP_USE|OP_PHONY)) == 0) {
430a6f1883eSespie (void)Dir_MTime(gn);
431a6f1883eSespie if (DEBUG(MAKE)) {
432866fd206Sespie if (!is_out_of_date(gn->mtime))
433df7262edSespie printf("modified %s...",
4344c9de429Sespie time_to_string(&gn->mtime));
435866fd206Sespie else
436a6f1883eSespie printf("non-existent...");
437a6f1883eSespie }
438a6f1883eSespie }
439a6f1883eSespie
440a6f1883eSespie /*
441194f6eccSespie * A target is rebuilt in one of the following circumstances:
442866fd206Sespie * - its modification time is smaller than that of its youngest child
443a6f1883eSespie * and it would actually be run (has commands or type OP_NOP)
444866fd206Sespie * - it's the object of a force operator
445866fd206Sespie * - it has no children, was on the lhs of an operator and doesn't
446df7262edSespie * exist already.
447a6f1883eSespie *
448a6f1883eSespie */
449a6f1883eSespie if (gn->type & OP_USE) {
450a6f1883eSespie /*
451a6f1883eSespie * If the node is a USE node it is *never* out of date
452a6f1883eSespie * no matter *what*.
453a6f1883eSespie */
454866fd206Sespie if (DEBUG(MAKE))
455a6f1883eSespie printf(".USE node...");
456a6f1883eSespie oodate = false;
45718cc0328Sespie } else if (gn->type & (OP_FORCE|OP_PHONY)) {
458a6f1883eSespie /*
459866fd206Sespie * A node which is the object of the force (!) operator or which
460866fd206Sespie * has the .EXEC attribute is always considered out-of-date.
461a6f1883eSespie */
462a6f1883eSespie if (DEBUG(MAKE)) {
463866fd206Sespie if (gn->type & OP_FORCE)
464a6f1883eSespie printf("! operator...");
465866fd206Sespie else if (gn->type & OP_PHONY)
466a6f1883eSespie printf(".PHONY node...");
467866fd206Sespie else
468a6f1883eSespie printf(".EXEC node...");
469a6f1883eSespie }
470a6f1883eSespie oodate = true;
47123a9ff7bSespie } else if (is_strictly_before(gn->mtime, gn->youngest->mtime) ||
47223a9ff7bSespie (gn == gn->youngest &&
473df7262edSespie (is_out_of_date(gn->mtime) || (gn->type & OP_DOUBLEDEP)))) {
474a6f1883eSespie /*
475a6f1883eSespie * A node whose modification time is less than that of its
47623a9ff7bSespie * youngest child or that has no children (gn->youngest == gn)
47723a9ff7bSespie * and either doesn't exist (mtime == OUT_OF_DATE)
478866fd206Sespie * or was the object of a :: operator is out-of-date.
479a6f1883eSespie */
480a6f1883eSespie if (DEBUG(MAKE)) {
48123a9ff7bSespie if (is_strictly_before(gn->mtime, gn->youngest->mtime))
4821ea29b92Sespie printf("modified before source(%s)...",
4831ea29b92Sespie gn->youngest->name);
484866fd206Sespie else if (is_out_of_date(gn->mtime))
485a6f1883eSespie printf("non-existent and no sources...");
486866fd206Sespie else
487a6f1883eSespie printf(":: operator and no sources...");
488a6f1883eSespie }
489a6f1883eSespie oodate = true;
490a6f1883eSespie } else {
491a6f1883eSespie oodate = false;
492a6f1883eSespie }
493a6f1883eSespie
494a6f1883eSespie /*
495a6f1883eSespie * If the target isn't out-of-date, the parents need to know its
496a6f1883eSespie * modification time. Note that targets that appear to be out-of-date
497a6f1883eSespie * but aren't, because they have no commands and aren't of type OP_NOP,
498df7262edSespie * have their mtime stay below their children's mtime to keep parents
499df7262edSespie * from thinking they're out-of-date.
500a6f1883eSespie */
501a6f1883eSespie if (!oodate)
502a6f1883eSespie Lst_ForEach(&gn->parents, MakeTimeStamp, gn);
503a6f1883eSespie
504a6f1883eSespie return oodate;
505a6f1883eSespie }
506a6f1883eSespie
50732e144d7Sespie
508a6b963c8Sespie void
job_attach_node(Job * job,GNode * node)509a6b963c8Sespie job_attach_node(Job *job, GNode *node)
510a6b963c8Sespie {
511a6b963c8Sespie job->node = node;
5121bae8e1fSespie job->node->built_status = BUILDING;
513a6b963c8Sespie job->next_cmd = Lst_First(&node->commands);
514a6b963c8Sespie job->exit_type = JOB_EXIT_OKAY;
515a6b963c8Sespie job->location = NULL;
516a6b963c8Sespie job->flags = 0;
517a6b963c8Sespie }
518a6b963c8Sespie
519a6b963c8Sespie void
handle_job_status(Job * job,int status)5203bb9adb9Sespie handle_job_status(Job *job, int status)
521a6b963c8Sespie {
522b12bcd0dSespie bool silent;
523be710f6fSespie int dying;
524b12bcd0dSespie
525b12bcd0dSespie /* if there's one job running and we don't keep going, no need
526b12bcd0dSespie * to report right now.
527b12bcd0dSespie */
528b12bcd0dSespie if ((job->flags & JOB_ERRCHECK) && !keepgoing && runningJobs == NULL)
529b12bcd0dSespie silent = !DEBUG(JOB);
530b12bcd0dSespie else
531b12bcd0dSespie silent = false;
532b12bcd0dSespie
533a6b963c8Sespie debug_job_printf("Process %ld (%s) exited with status %d.\n",
534a6b963c8Sespie (long)job->pid, job->node->name, status);
535a6b963c8Sespie
536a6b963c8Sespie /* classify status */
537a6b963c8Sespie if (WIFEXITED(status)) {
538a6b963c8Sespie job->code = WEXITSTATUS(status);/* exited */
539be710f6fSespie if (job->code != 0) {
540be710f6fSespie /* if we're already dying from that signal, be silent */
541be710f6fSespie if (!silent && job->code > 128
542be710f6fSespie && job->code <= 128 + _NSIG) {
543be710f6fSespie dying = check_dying_signal();
544be710f6fSespie silent = dying && job->code == dying + 128;
545be710f6fSespie }
546b12bcd0dSespie if (!silent)
547b12bcd0dSespie printf("*** Error %d", job->code);
548a6b963c8Sespie job->exit_type = JOB_EXIT_BAD;
549a6b963c8Sespie } else
550a6b963c8Sespie job->exit_type = JOB_EXIT_OKAY;
551a6b963c8Sespie } else {
552a6b963c8Sespie job->exit_type = JOB_SIGNALED;
553a6b963c8Sespie job->code = WTERMSIG(status); /* signaled */
554be710f6fSespie /* if we're already dying from that signal, be silent */
555be710f6fSespie if (!silent) {
556be710f6fSespie dying = check_dying_signal();
557be710f6fSespie silent = dying && job->code == dying;
558be710f6fSespie }
559b12bcd0dSespie if (!silent)
560a6b963c8Sespie printf("*** Signal %d", job->code);
561a6b963c8Sespie }
562a6b963c8Sespie
563a6b963c8Sespie /* if there is a problem, what's going on ? */
564a6b963c8Sespie if (job->exit_type != JOB_EXIT_OKAY) {
565b12bcd0dSespie if (!silent)
566b12bcd0dSespie printf(" in target '%s'", job->node->name);
567a6b963c8Sespie if (job->flags & JOB_ERRCHECK) {
568a6b963c8Sespie job->node->built_status = ERROR;
569a6b963c8Sespie if (!keepgoing) {
570b12bcd0dSespie if (!silent)
571a6b963c8Sespie printf("\n");
5727a7b8f33Sespie job->flags |= JOB_KEEPERROR;
573a6b963c8Sespie /* XXX don't free the command */
574a6b963c8Sespie return;
575a6b963c8Sespie }
576a6b963c8Sespie printf(", line %lu of %s", job->location->lineno,
577a6b963c8Sespie job->location->fname);
5780b019757Sespie /* Parallel make already determined whether
5790b019757Sespie * JOB_IS_EXPENSIVE, perform the computation for
5800b019757Sespie * sequential make to figure out whether to display the
5810b019757Sespie * command or not. */
5827dcceccaSespie if ((job->flags & JOB_SILENT) && sequential)
583d211a910Sespie determine_expensive_job(job);
584a6b963c8Sespie if ((job->flags & (JOB_SILENT | JOB_IS_EXPENSIVE))
585a6b963c8Sespie == JOB_SILENT)
586a6b963c8Sespie printf(": %s", job->cmd);
587a6b963c8Sespie /* Abort the current target,
588a6b963c8Sespie * but let others continue. */
589a6b963c8Sespie printf(" (continuing)\n");
590a6b963c8Sespie } else {
591a6b963c8Sespie /* Continue executing commands for
592a6b963c8Sespie * this target. If we return 0,
593a6b963c8Sespie * this will happen... */
594a6b963c8Sespie printf(" (ignored)\n");
595a6b963c8Sespie job->exit_type = JOB_EXIT_OKAY;
596a6b963c8Sespie }
597a6b963c8Sespie }
598a6b963c8Sespie free(job->cmd);
599a6b963c8Sespie }
600a6b963c8Sespie
601a6b963c8Sespie int
run_gnode(GNode * gn)602a6b963c8Sespie run_gnode(GNode *gn)
603a6b963c8Sespie {
604a6b963c8Sespie if (!gn || (gn->type & OP_DUMMY))
605a6b963c8Sespie return NOSUCHNODE;
606a6b963c8Sespie
607bee8c711Sespie Job_Make(gn);
608bee8c711Sespie loop_handle_running_jobs();
609a6b963c8Sespie return gn->built_status;
610a6b963c8Sespie }
611a6b963c8Sespie
612a6b963c8Sespie
613a6b963c8Sespie static bool
do_run_command(Job * job,const char * pre)6140a342675Sespie do_run_command(Job *job, const char *pre)
61532e144d7Sespie {
61632e144d7Sespie bool silent; /* Don't print command */
61732e144d7Sespie bool doExecute; /* Execute the command */
61832e144d7Sespie bool errCheck; /* Check errors */
619a6b963c8Sespie pid_t cpid; /* Child pid */
62032e144d7Sespie
621a6b963c8Sespie const char *cmd = job->cmd;
6224b65af26Sespie silent = Targ_Silent(job->node);
6234b65af26Sespie errCheck = !Targ_Ignore(job->node);
624a6b963c8Sespie if (job->node->type & OP_MAKE)
625a6b963c8Sespie doExecute = true;
626a6b963c8Sespie else
62732e144d7Sespie doExecute = !noExecute;
62832e144d7Sespie
62932e144d7Sespie /* How can we execute a null command ? we warn the user that the
63032e144d7Sespie * command expanded to nothing (is this the right thing to do?). */
631f46d747cSespie if (*cmd == '\0') {
6320a342675Sespie Parse_Error(PARSE_WARNING,
6330a342675Sespie "'%s' expands to '' while building %s",
6340a342675Sespie pre, job->node->name);
635a6b963c8Sespie return false;
636f46d747cSespie }
63732e144d7Sespie
63832e144d7Sespie for (;; cmd++) {
63932e144d7Sespie if (*cmd == '@')
64032e144d7Sespie silent = DEBUG(LOUD) ? false : true;
64132e144d7Sespie else if (*cmd == '-')
64232e144d7Sespie errCheck = false;
64332e144d7Sespie else if (*cmd == '+')
64432e144d7Sespie doExecute = true;
64532e144d7Sespie else
64632e144d7Sespie break;
64732e144d7Sespie }
64856afcde6Sespie while (ISSPACE(*cmd))
64932e144d7Sespie cmd++;
650a6b963c8Sespie /* Print the command before fork if make -n or !silent*/
651a6b963c8Sespie if ( noExecute || !silent)
65232e144d7Sespie printf("%s\n", cmd);
653a6b963c8Sespie
654a6b963c8Sespie if (silent)
655a6b963c8Sespie job->flags |= JOB_SILENT;
656a6b963c8Sespie else
657a6b963c8Sespie job->flags &= ~JOB_SILENT;
658a6b963c8Sespie
65932e144d7Sespie /* If we're not supposed to execute any commands, this is as far as
66032e144d7Sespie * we go... */
66132e144d7Sespie if (!doExecute)
662a6b963c8Sespie return false;
663a6b963c8Sespie /* always flush for other stuff */
664a6b963c8Sespie fflush(stdout);
66532e144d7Sespie
6668a1af4f8Sespie /* Optimization: bypass comments entirely */
6678a1af4f8Sespie if (*cmd == '#')
6688a1af4f8Sespie return false;
6698a1af4f8Sespie
67032e144d7Sespie /* Fork and execute the single command. If the fork fails, we abort. */
67132e144d7Sespie switch (cpid = fork()) {
67232e144d7Sespie case -1:
673a6b963c8Sespie Punt("Could not fork");
67432e144d7Sespie /*NOTREACHED*/
67532e144d7Sespie case 0:
676868b296aSespie reset_signal_mask();
6771bae8e1fSespie /* put a random delay unless we're the only job running
6781bae8e1fSespie * and there's nothing left to do.
6791bae8e1fSespie */
6801bae8e1fSespie if (random_delay)
68180ccc038Sespie if (!(runningJobs == NULL && nothing_left_to_build()))
6828a774f81Snaddy usleep(arc4random_uniform(random_delay));
68332e144d7Sespie run_command(cmd, errCheck);
68432e144d7Sespie /*NOTREACHED*/
68532e144d7Sespie default:
686a6b963c8Sespie job->pid = cpid;
687a6b963c8Sespie job->next = runningJobs;
688a6b963c8Sespie runningJobs = job;
689a6b963c8Sespie if (errCheck)
690a6b963c8Sespie job->flags |= JOB_ERRCHECK;
6911ef353c6Sespie else
692a6b963c8Sespie job->flags &= ~JOB_ERRCHECK;
693a6b963c8Sespie debug_job_printf("Running %ld (%s) %s\n", (long)job->pid,
694a6b963c8Sespie job->node->name, (noExecute || !silent) ? "" : cmd);
695a6b963c8Sespie return true;
69632e144d7Sespie }
69732e144d7Sespie }
698a6b963c8Sespie
699a6b963c8Sespie bool
job_run_next(Job * job)700a6b963c8Sespie job_run_next(Job *job)
701a6b963c8Sespie {
702a6b963c8Sespie bool started;
703a6b963c8Sespie GNode *gn = job->node;
704a6b963c8Sespie
705a6b963c8Sespie while (job->next_cmd != NULL) {
706a6b963c8Sespie struct command *command = Lst_Datum(job->next_cmd);
707a6b963c8Sespie
708a6b963c8Sespie handle_all_signals();
709a6b963c8Sespie job->location = &command->location;
710a6b963c8Sespie Parse_SetLocation(job->location);
71191797de1Sespie job->cmd = Var_Subst(command->string, &gn->localvars, false);
712a6b963c8Sespie job->next_cmd = Lst_Adv(job->next_cmd);
713a6b963c8Sespie if (fatal_errors)
714a6b963c8Sespie Punt(NULL);
7150a342675Sespie started = do_run_command(job, command->string);
716a6b963c8Sespie if (started)
717a6b963c8Sespie return false;
718a6b963c8Sespie else
719a6b963c8Sespie free(job->cmd);
720a6b963c8Sespie }
721a6b963c8Sespie job->exit_type = JOB_EXIT_OKAY;
722a6b963c8Sespie return true;
723a6b963c8Sespie }
724a6b963c8Sespie
725