xref: /freebsd/contrib/bmake/make.c (revision dba7b0ef928af88caa38728a73657b837aeeac93)
1*dba7b0efSSimon J. Gerraty /*	$NetBSD: make.c,v 1.242 2021/02/05 05:15:12 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
7106b9b3e0SSimon J. Gerraty /*
7206b9b3e0SSimon J. Gerraty  * Examination of targets and their suitability for creation.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Interface:
75e2eeea75SSimon J. Gerraty  *	Make_Run	Initialize things for the module. Returns TRUE if
76e2eeea75SSimon J. Gerraty  *			work was (or would have been) done.
773955d011SMarcel Moolenaar  *
78e2eeea75SSimon J. Gerraty  *	Make_Update	After a target is made, update all its parents.
79e2eeea75SSimon J. Gerraty  *			Perform various bookkeeping chores like the updating
80956e45f6SSimon J. Gerraty  *			of the youngestChild field of the parent, filling
81*dba7b0efSSimon J. Gerraty  *			of the IMPSRC variable, etc. Place the parent on the
82*dba7b0efSSimon J. Gerraty  *			toBeMade queue if it should be.
833955d011SMarcel Moolenaar  *
84e2eeea75SSimon J. Gerraty  *	GNode_UpdateYoungestChild
85e2eeea75SSimon J. Gerraty  *			Update the node's youngestChild field based on the
86e2eeea75SSimon J. Gerraty  *			child's modification time.
873955d011SMarcel Moolenaar  *
883955d011SMarcel Moolenaar  *	Make_DoAllVar	Set up the various local variables for a
893955d011SMarcel Moolenaar  *			target, including the .ALLSRC variable, making
903955d011SMarcel Moolenaar  *			sure that any variable that needs to exist
913955d011SMarcel Moolenaar  *			at the very least has the empty value.
923955d011SMarcel Moolenaar  *
93e2eeea75SSimon J. Gerraty  *	GNode_IsOODate	Determine if a target is out-of-date.
943955d011SMarcel Moolenaar  *
953955d011SMarcel Moolenaar  *	Make_HandleUse	See if a child is a .USE node for a parent
963955d011SMarcel Moolenaar  *			and perform the .USE actions if so.
973955d011SMarcel Moolenaar  *
983955d011SMarcel Moolenaar  *	Make_ExpandUse	Expand .USE nodes
993955d011SMarcel Moolenaar  */
1003955d011SMarcel Moolenaar 
1013955d011SMarcel Moolenaar #include "make.h"
1023955d011SMarcel Moolenaar #include "dir.h"
1033955d011SMarcel Moolenaar #include "job.h"
1043955d011SMarcel Moolenaar 
105956e45f6SSimon J. Gerraty /*	"@(#)make.c	8.1 (Berkeley) 6/6/93"	*/
106*dba7b0efSSimon J. Gerraty MAKE_RCSID("$NetBSD: make.c,v 1.242 2021/02/05 05:15:12 rillig Exp $");
1073955d011SMarcel Moolenaar 
108956e45f6SSimon J. Gerraty /* Sequence # to detect recursion. */
109e2eeea75SSimon J. Gerraty static unsigned int checked_seqno = 1;
110956e45f6SSimon J. Gerraty 
11106b9b3e0SSimon J. Gerraty /*
11206b9b3e0SSimon J. Gerraty  * The current fringe of the graph.
113956e45f6SSimon J. Gerraty  * These are nodes which await examination by MakeOODate.
11406b9b3e0SSimon J. Gerraty  * It is added to by Make_Update and subtracted from by MakeStartJobs
11506b9b3e0SSimon J. Gerraty  */
11606b9b3e0SSimon J. Gerraty static GNodeList toBeMade = LST_INIT;
117956e45f6SSimon J. Gerraty 
1183955d011SMarcel Moolenaar 
119956e45f6SSimon J. Gerraty void
120956e45f6SSimon J. Gerraty debug_printf(const char *fmt, ...)
121956e45f6SSimon J. Gerraty {
122956e45f6SSimon J. Gerraty 	va_list args;
123956e45f6SSimon J. Gerraty 
124956e45f6SSimon J. Gerraty 	va_start(args, fmt);
125956e45f6SSimon J. Gerraty 	vfprintf(opts.debug_file, fmt, args);
126956e45f6SSimon J. Gerraty 	va_end(args);
127956e45f6SSimon J. Gerraty }
128956e45f6SSimon J. Gerraty 
1293955d011SMarcel Moolenaar MAKE_ATTR_DEAD static void
13006b9b3e0SSimon J. Gerraty make_abort(GNode *gn, int lineno)
1313955d011SMarcel Moolenaar {
13206b9b3e0SSimon J. Gerraty 
13306b9b3e0SSimon J. Gerraty 	debug_printf("make_abort from line %d\n", lineno);
134956e45f6SSimon J. Gerraty 	Targ_PrintNode(gn, 2);
13506b9b3e0SSimon J. Gerraty 	Targ_PrintNodes(&toBeMade, 2);
1363955d011SMarcel Moolenaar 	Targ_PrintGraph(3);
1373955d011SMarcel Moolenaar 	abort();
1383955d011SMarcel Moolenaar }
1393955d011SMarcel Moolenaar 
1402c3632d1SSimon J. Gerraty ENUM_FLAGS_RTTI_31(GNodeType,
1412c3632d1SSimon J. Gerraty     OP_DEPENDS, OP_FORCE, OP_DOUBLEDEP,
1422c3632d1SSimon J. Gerraty /* OP_OPMASK is omitted since it combines other flags */
1432c3632d1SSimon J. Gerraty     OP_OPTIONAL, OP_USE, OP_EXEC, OP_IGNORE,
1442c3632d1SSimon J. Gerraty     OP_PRECIOUS, OP_SILENT, OP_MAKE, OP_JOIN,
1452c3632d1SSimon J. Gerraty     OP_MADE, OP_SPECIAL, OP_USEBEFORE, OP_INVISIBLE,
1462c3632d1SSimon J. Gerraty     OP_NOTMAIN, OP_PHONY, OP_NOPATH, OP_WAIT,
1472c3632d1SSimon J. Gerraty     OP_NOMETA, OP_META, OP_NOMETA_CMP, OP_SUBMAKE,
1482c3632d1SSimon J. Gerraty     OP_TRANSFORM, OP_MEMBER, OP_LIB, OP_ARCHV,
1492c3632d1SSimon J. Gerraty     OP_HAS_COMMANDS, OP_SAVE_CMDS, OP_DEPS_FOUND, OP_MARK);
1502c3632d1SSimon J. Gerraty 
151*dba7b0efSSimon J. Gerraty ENUM_FLAGS_RTTI_9(GNodeFlags,
1522c3632d1SSimon J. Gerraty     REMAKE, CHILDMADE, FORCE, DONE_WAIT,
1532c3632d1SSimon J. Gerraty     DONE_ORDER, FROM_DEPEND, DONE_ALLSRC, CYCLE,
154*dba7b0efSSimon J. Gerraty     DONECYCLE);
1552c3632d1SSimon J. Gerraty 
1562c3632d1SSimon J. Gerraty void
1572c3632d1SSimon J. Gerraty GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn,
1582c3632d1SSimon J. Gerraty 		    const char *suffix)
1592c3632d1SSimon J. Gerraty {
1602c3632d1SSimon J. Gerraty 	char type_buf[GNodeType_ToStringSize];
1612c3632d1SSimon J. Gerraty 	char flags_buf[GNodeFlags_ToStringSize];
1622c3632d1SSimon J. Gerraty 
163*dba7b0efSSimon J. Gerraty 	fprintf(f, "%s%s, type %s, flags %s%s",
1642c3632d1SSimon J. Gerraty 	    prefix,
165*dba7b0efSSimon J. Gerraty 	    GNodeMade_Name(gn->made),
166*dba7b0efSSimon J. Gerraty 	    GNodeType_ToString(type_buf, gn->type),
167*dba7b0efSSimon J. Gerraty 	    GNodeFlags_ToString(flags_buf, gn->flags),
1682c3632d1SSimon J. Gerraty 	    suffix);
1692c3632d1SSimon J. Gerraty }
1702c3632d1SSimon J. Gerraty 
171956e45f6SSimon J. Gerraty Boolean
172956e45f6SSimon J. Gerraty GNode_ShouldExecute(GNode *gn)
173956e45f6SSimon J. Gerraty {
17406b9b3e0SSimon J. Gerraty 	return !((gn->type & OP_MAKE)
17506b9b3e0SSimon J. Gerraty 	    ? opts.noRecursiveExecute
17606b9b3e0SSimon J. Gerraty 	    : opts.noExecute);
177956e45f6SSimon J. Gerraty }
178956e45f6SSimon J. Gerraty 
179956e45f6SSimon J. Gerraty /* Update the youngest child of the node, according to the given child. */
180956e45f6SSimon J. Gerraty void
181e2eeea75SSimon J. Gerraty GNode_UpdateYoungestChild(GNode *gn, GNode *cgn)
1823955d011SMarcel Moolenaar {
183e2eeea75SSimon J. Gerraty 	if (gn->youngestChild == NULL || cgn->mtime > gn->youngestChild->mtime)
184e2eeea75SSimon J. Gerraty 		gn->youngestChild = cgn;
1853955d011SMarcel Moolenaar }
186e2eeea75SSimon J. Gerraty 
187e2eeea75SSimon J. Gerraty static Boolean
188e2eeea75SSimon J. Gerraty IsOODateRegular(GNode *gn)
189e2eeea75SSimon J. Gerraty {
190e2eeea75SSimon J. Gerraty 	/* These rules are inherited from the original Make. */
191e2eeea75SSimon J. Gerraty 
192e2eeea75SSimon J. Gerraty 	if (gn->youngestChild != NULL) {
193e2eeea75SSimon J. Gerraty 		if (gn->mtime < gn->youngestChild->mtime) {
194e2eeea75SSimon J. Gerraty 			DEBUG1(MAKE, "modified before source \"%s\"...",
195e2eeea75SSimon J. Gerraty 			    GNode_Path(gn->youngestChild));
196e2eeea75SSimon J. Gerraty 			return TRUE;
197e2eeea75SSimon J. Gerraty 		}
198e2eeea75SSimon J. Gerraty 		return FALSE;
199e2eeea75SSimon J. Gerraty 	}
200e2eeea75SSimon J. Gerraty 
201e2eeea75SSimon J. Gerraty 	if (gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) {
20206b9b3e0SSimon J. Gerraty 		DEBUG0(MAKE, "nonexistent and no sources...");
203e2eeea75SSimon J. Gerraty 		return TRUE;
204e2eeea75SSimon J. Gerraty 	}
205e2eeea75SSimon J. Gerraty 
206e2eeea75SSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP) {
207e2eeea75SSimon J. Gerraty 		DEBUG0(MAKE, ":: operator and no sources...");
208e2eeea75SSimon J. Gerraty 		return TRUE;
209e2eeea75SSimon J. Gerraty 	}
210e2eeea75SSimon J. Gerraty 
211e2eeea75SSimon J. Gerraty 	return FALSE;
2123955d011SMarcel Moolenaar }
2133955d011SMarcel Moolenaar 
21406b9b3e0SSimon J. Gerraty /*
21506b9b3e0SSimon J. Gerraty  * See if the node is out of date with respect to its sources.
2163955d011SMarcel Moolenaar  *
2173955d011SMarcel Moolenaar  * Used by Make_Run when deciding which nodes to place on the
218956e45f6SSimon J. Gerraty  * toBeMade queue initially and by Make_Update to screen out .USE and
219956e45f6SSimon J. Gerraty  * .EXEC nodes. In the latter case, however, any other sort of node
2203955d011SMarcel Moolenaar  * must be considered out-of-date since at least one of its children
2213955d011SMarcel Moolenaar  * will have been recreated.
2223955d011SMarcel Moolenaar  *
223956e45f6SSimon J. Gerraty  * The mtime field of the node and the youngestChild field of its parents
224956e45f6SSimon J. Gerraty  * may be changed.
2253955d011SMarcel Moolenaar  */
2263955d011SMarcel Moolenaar Boolean
227e2eeea75SSimon J. Gerraty GNode_IsOODate(GNode *gn)
2283955d011SMarcel Moolenaar {
2293955d011SMarcel Moolenaar 	Boolean oodate;
2303955d011SMarcel Moolenaar 
2313955d011SMarcel Moolenaar 	/*
2323955d011SMarcel Moolenaar 	 * Certain types of targets needn't even be sought as their datedness
2333955d011SMarcel Moolenaar 	 * doesn't depend on their modification time...
2343955d011SMarcel Moolenaar 	 */
235e2eeea75SSimon J. Gerraty 	if (!(gn->type & (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC))) {
236e2eeea75SSimon J. Gerraty 		Dir_UpdateMTime(gn, TRUE);
2373955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
238e2eeea75SSimon J. Gerraty 			if (gn->mtime != 0)
23906b9b3e0SSimon J. Gerraty 				debug_printf("modified %s...",
24006b9b3e0SSimon J. Gerraty 				    Targ_FmtTime(gn->mtime));
241e2eeea75SSimon J. Gerraty 			else
24206b9b3e0SSimon J. Gerraty 				debug_printf("nonexistent...");
2433955d011SMarcel Moolenaar 		}
2443955d011SMarcel Moolenaar 	}
2453955d011SMarcel Moolenaar 
2463955d011SMarcel Moolenaar 	/*
2473955d011SMarcel Moolenaar 	 * A target is remade in one of the following circumstances:
24806b9b3e0SSimon J. Gerraty 	 *
24906b9b3e0SSimon J. Gerraty 	 *	its modification time is smaller than that of its youngest
25006b9b3e0SSimon J. Gerraty 	 *	child and it would actually be run (has commands or is not
25106b9b3e0SSimon J. Gerraty 	 *	GNode_IsTarget)
25206b9b3e0SSimon J. Gerraty 	 *
2533955d011SMarcel Moolenaar 	 *	it's the object of a force operator
2543955d011SMarcel Moolenaar 	 *
25506b9b3e0SSimon J. Gerraty 	 *	it has no children, was on the lhs of an operator and doesn't
25606b9b3e0SSimon J. Gerraty 	 *	exist already.
2573955d011SMarcel Moolenaar 	 *
25806b9b3e0SSimon J. Gerraty 	 * Libraries are only considered out-of-date if the archive module
25906b9b3e0SSimon J. Gerraty 	 * says they are.
26006b9b3e0SSimon J. Gerraty 	 *
26106b9b3e0SSimon J. Gerraty 	 * These weird rules are brought to you by Backward-Compatibility
26206b9b3e0SSimon J. Gerraty 	 * and the strange people who wrote 'Make'.
2633955d011SMarcel Moolenaar 	 */
2643955d011SMarcel Moolenaar 	if (gn->type & (OP_USE | OP_USEBEFORE)) {
2653955d011SMarcel Moolenaar 		/*
2663955d011SMarcel Moolenaar 		 * If the node is a USE node it is *never* out of date
2673955d011SMarcel Moolenaar 		 * no matter *what*.
2683955d011SMarcel Moolenaar 		 */
269956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, ".USE node...");
2703955d011SMarcel Moolenaar 		oodate = FALSE;
271e2eeea75SSimon J. Gerraty 	} else if ((gn->type & OP_LIB) && (gn->mtime == 0 || Arch_IsLib(gn))) {
272956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, "library...");
2733955d011SMarcel Moolenaar 
2743955d011SMarcel Moolenaar 		/*
2753955d011SMarcel Moolenaar 		 * always out of date if no children and :: target
27606b9b3e0SSimon J. Gerraty 		 * or nonexistent.
2773955d011SMarcel Moolenaar 		 */
2783955d011SMarcel Moolenaar 		oodate = (gn->mtime == 0 || Arch_LibOODate(gn) ||
27906b9b3e0SSimon J. Gerraty 			  (gn->youngestChild == NULL &&
28006b9b3e0SSimon J. Gerraty 			   (gn->type & OP_DOUBLEDEP)));
2813955d011SMarcel Moolenaar 	} else if (gn->type & OP_JOIN) {
2823955d011SMarcel Moolenaar 		/*
2833955d011SMarcel Moolenaar 		 * A target with the .JOIN attribute is only considered
2843955d011SMarcel Moolenaar 		 * out-of-date if any of its children was out-of-date.
2853955d011SMarcel Moolenaar 		 */
286956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, ".JOIN node...");
28706b9b3e0SSimon J. Gerraty 		DEBUG1(MAKE, "source %smade...",
28806b9b3e0SSimon J. Gerraty 		    gn->flags & CHILDMADE ? "" : "not ");
289e2eeea75SSimon J. Gerraty 		oodate = (gn->flags & CHILDMADE) != 0;
2903955d011SMarcel Moolenaar 	} else if (gn->type & (OP_FORCE | OP_EXEC | OP_PHONY)) {
2913955d011SMarcel Moolenaar 		/*
29206b9b3e0SSimon J. Gerraty 		 * A node which is the object of the force (!) operator or
29306b9b3e0SSimon J. Gerraty 		 * which has the .EXEC attribute is always considered
29406b9b3e0SSimon J. Gerraty 		 * out-of-date.
2953955d011SMarcel Moolenaar 		 */
2963955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
2973955d011SMarcel Moolenaar 			if (gn->type & OP_FORCE) {
298956e45f6SSimon J. Gerraty 				debug_printf("! operator...");
2993955d011SMarcel Moolenaar 			} else if (gn->type & OP_PHONY) {
300956e45f6SSimon J. Gerraty 				debug_printf(".PHONY node...");
3013955d011SMarcel Moolenaar 			} else {
302956e45f6SSimon J. Gerraty 				debug_printf(".EXEC node...");
3033955d011SMarcel Moolenaar 			}
3043955d011SMarcel Moolenaar 		}
3053955d011SMarcel Moolenaar 		oodate = TRUE;
306e2eeea75SSimon J. Gerraty 	} else if (IsOODateRegular(gn)) {
3073955d011SMarcel Moolenaar 		oodate = TRUE;
3083955d011SMarcel Moolenaar 	} else {
3093955d011SMarcel Moolenaar 		/*
31006b9b3e0SSimon J. Gerraty 		 * When a nonexistent child with no sources
3113955d011SMarcel Moolenaar 		 * (such as a typically used FORCE source) has been made and
3123955d011SMarcel Moolenaar 		 * the target of the child (usually a directory) has the same
31306b9b3e0SSimon J. Gerraty 		 * timestamp as the timestamp just given to the nonexistent
31406b9b3e0SSimon J. Gerraty 		 * child after it was considered made.
3153955d011SMarcel Moolenaar 		 */
3163955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
3173955d011SMarcel Moolenaar 			if (gn->flags & FORCE)
318956e45f6SSimon J. Gerraty 				debug_printf("non existing child...");
3193955d011SMarcel Moolenaar 		}
320e2eeea75SSimon J. Gerraty 		oodate = (gn->flags & FORCE) != 0;
3213955d011SMarcel Moolenaar 	}
3223955d011SMarcel Moolenaar 
3233955d011SMarcel Moolenaar #ifdef USE_META
3243955d011SMarcel Moolenaar 	if (useMeta) {
3253955d011SMarcel Moolenaar 		oodate = meta_oodate(gn, oodate);
3263955d011SMarcel Moolenaar 	}
3273955d011SMarcel Moolenaar #endif
3283955d011SMarcel Moolenaar 
3293955d011SMarcel Moolenaar 	/*
3303955d011SMarcel Moolenaar 	 * If the target isn't out-of-date, the parents need to know its
3313955d011SMarcel Moolenaar 	 * modification time. Note that targets that appear to be out-of-date
332956e45f6SSimon J. Gerraty 	 * but aren't, because they have no commands and are GNode_IsTarget,
33306b9b3e0SSimon J. Gerraty 	 * have their mtime stay below their children's mtime to keep parents
33406b9b3e0SSimon J. Gerraty 	 * from thinking they're out-of-date.
3353955d011SMarcel Moolenaar 	 */
3363955d011SMarcel Moolenaar 	if (!oodate) {
337956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
33806b9b3e0SSimon J. Gerraty 		for (ln = gn->parents.first; ln != NULL; ln = ln->next)
339e2eeea75SSimon J. Gerraty 			GNode_UpdateYoungestChild(ln->datum, gn);
3403955d011SMarcel Moolenaar 	}
3413955d011SMarcel Moolenaar 
3423841c287SSimon J. Gerraty 	return oodate;
3433955d011SMarcel Moolenaar }
3442c3632d1SSimon J. Gerraty 
345e2eeea75SSimon J. Gerraty static void
346e2eeea75SSimon J. Gerraty PretendAllChildrenAreMade(GNode *pgn)
3473955d011SMarcel Moolenaar {
348e2eeea75SSimon J. Gerraty 	GNodeListNode *ln;
3493955d011SMarcel Moolenaar 
35006b9b3e0SSimon J. Gerraty 	for (ln = pgn->children.first; ln != NULL; ln = ln->next) {
351e2eeea75SSimon J. Gerraty 		GNode *cgn = ln->datum;
3522c3632d1SSimon J. Gerraty 
35306b9b3e0SSimon J. Gerraty 		/* This may also update cgn->path. */
35406b9b3e0SSimon J. Gerraty 		Dir_UpdateMTime(cgn, FALSE);
355e2eeea75SSimon J. Gerraty 		GNode_UpdateYoungestChild(pgn, cgn);
3563955d011SMarcel Moolenaar 		pgn->unmade--;
357e2eeea75SSimon J. Gerraty 	}
3583955d011SMarcel Moolenaar }
3592c3632d1SSimon J. Gerraty 
36006b9b3e0SSimon J. Gerraty /*
36106b9b3e0SSimon J. Gerraty  * Called by Make_Run and SuffApplyTransform on the downward pass to handle
3622c3632d1SSimon J. Gerraty  * .USE and transformation nodes, by copying the child node's commands, type
3632c3632d1SSimon J. Gerraty  * flags and children to the parent node.
3643955d011SMarcel Moolenaar  *
3652c3632d1SSimon J. Gerraty  * A .USE node is much like an explicit transformation rule, except its
3662c3632d1SSimon J. Gerraty  * commands are always added to the target node, even if the target already
3672c3632d1SSimon J. Gerraty  * has commands.
3683955d011SMarcel Moolenaar  *
3693955d011SMarcel Moolenaar  * Input:
370956e45f6SSimon J. Gerraty  *	cgn		The source node, which is either a .USE/.USEBEFORE
371956e45f6SSimon J. Gerraty  *			node or a transformation node (OP_TRANSFORM).
372956e45f6SSimon J. Gerraty  *	pgn		The target node
3733955d011SMarcel Moolenaar  */
3743955d011SMarcel Moolenaar void
3753955d011SMarcel Moolenaar Make_HandleUse(GNode *cgn, GNode *pgn)
3763955d011SMarcel Moolenaar {
377956e45f6SSimon J. Gerraty 	GNodeListNode *ln;	/* An element in the children list */
3783955d011SMarcel Moolenaar 
3793955d011SMarcel Moolenaar #ifdef DEBUG_SRC
380e2eeea75SSimon J. Gerraty 	if (!(cgn->type & (OP_USE | OP_USEBEFORE | OP_TRANSFORM))) {
38106b9b3e0SSimon J. Gerraty 		debug_printf("Make_HandleUse: called for plain node %s\n",
38206b9b3e0SSimon J. Gerraty 		    cgn->name);
38306b9b3e0SSimon J. Gerraty 		/* XXX: debug mode should not affect control flow */
38406b9b3e0SSimon J. Gerraty 		return;
3853955d011SMarcel Moolenaar 	}
3863955d011SMarcel Moolenaar #endif
3873955d011SMarcel Moolenaar 
38806b9b3e0SSimon J. Gerraty 	if ((cgn->type & (OP_USE | OP_USEBEFORE)) ||
38906b9b3e0SSimon J. Gerraty 	    Lst_IsEmpty(&pgn->commands)) {
3903955d011SMarcel Moolenaar 		if (cgn->type & OP_USEBEFORE) {
3912c3632d1SSimon J. Gerraty 			/* .USEBEFORE */
39206b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&pgn->commands, &cgn->commands);
3933955d011SMarcel Moolenaar 		} else {
3942c3632d1SSimon J. Gerraty 			/* .USE, or target has no commands */
39506b9b3e0SSimon J. Gerraty 			Lst_AppendAll(&pgn->commands, &cgn->commands);
3963955d011SMarcel Moolenaar 		}
3973955d011SMarcel Moolenaar 	}
3983955d011SMarcel Moolenaar 
39906b9b3e0SSimon J. Gerraty 	for (ln = cgn->children.first; ln != NULL; ln = ln->next) {
400956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
4013955d011SMarcel Moolenaar 
4023955d011SMarcel Moolenaar 		/*
4033955d011SMarcel Moolenaar 		 * Expand variables in the .USE node's name
4043955d011SMarcel Moolenaar 		 * and save the unexpanded form.
4053955d011SMarcel Moolenaar 		 * We don't need to do this for commands.
4063955d011SMarcel Moolenaar 		 * They get expanded properly when we execute.
4073955d011SMarcel Moolenaar 		 */
4083955d011SMarcel Moolenaar 		if (gn->uname == NULL) {
4093955d011SMarcel Moolenaar 			gn->uname = gn->name;
4103955d011SMarcel Moolenaar 		} else {
4113955d011SMarcel Moolenaar 			free(gn->name);
4123955d011SMarcel Moolenaar 		}
413956e45f6SSimon J. Gerraty 		(void)Var_Subst(gn->uname, pgn, VARE_WANTRES, &gn->name);
414956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
41506b9b3e0SSimon J. Gerraty 		if (gn->uname != NULL && strcmp(gn->name, gn->uname) != 0) {
4163955d011SMarcel Moolenaar 			/* See if we have a target for this node. */
417956e45f6SSimon J. Gerraty 			GNode *tgn = Targ_FindNode(gn->name);
4183955d011SMarcel Moolenaar 			if (tgn != NULL)
4193955d011SMarcel Moolenaar 				gn = tgn;
4203955d011SMarcel Moolenaar 		}
4213955d011SMarcel Moolenaar 
42206b9b3e0SSimon J. Gerraty 		Lst_Append(&pgn->children, gn);
42306b9b3e0SSimon J. Gerraty 		Lst_Append(&gn->parents, pgn);
424956e45f6SSimon J. Gerraty 		pgn->unmade++;
4253955d011SMarcel Moolenaar 	}
4263955d011SMarcel Moolenaar 
42706b9b3e0SSimon J. Gerraty 	pgn->type |=
42806b9b3e0SSimon J. Gerraty 	    cgn->type & ~(OP_OPMASK | OP_USE | OP_USEBEFORE | OP_TRANSFORM);
4293955d011SMarcel Moolenaar }
4303955d011SMarcel Moolenaar 
43106b9b3e0SSimon J. Gerraty /*
43206b9b3e0SSimon J. Gerraty  * Used by Make_Run on the downward pass to handle .USE nodes. Should be
433956e45f6SSimon J. Gerraty  * called before the children are enqueued to be looked at by MakeAddChild.
434956e45f6SSimon J. Gerraty  *
435956e45f6SSimon J. Gerraty  * For a .USE child, the commands, type flags and children are copied to the
436956e45f6SSimon J. Gerraty  * parent node, and since the relation to the .USE node is then no longer
437956e45f6SSimon J. Gerraty  * needed, that relation is removed.
4383955d011SMarcel Moolenaar  *
4393955d011SMarcel Moolenaar  * Input:
440956e45f6SSimon J. Gerraty  *	cgn		the child, which may be a .USE node
441956e45f6SSimon J. Gerraty  *	pgn		the current parent
4423955d011SMarcel Moolenaar  */
443956e45f6SSimon J. Gerraty static void
444956e45f6SSimon J. Gerraty MakeHandleUse(GNode *cgn, GNode *pgn, GNodeListNode *ln)
4453955d011SMarcel Moolenaar {
446956e45f6SSimon J. Gerraty 	Boolean unmarked;
4473955d011SMarcel Moolenaar 
448e2eeea75SSimon J. Gerraty 	unmarked = !(cgn->type & OP_MARK);
4493955d011SMarcel Moolenaar 	cgn->type |= OP_MARK;
4503955d011SMarcel Moolenaar 
451e2eeea75SSimon J. Gerraty 	if (!(cgn->type & (OP_USE | OP_USEBEFORE)))
452956e45f6SSimon J. Gerraty 		return;
4533955d011SMarcel Moolenaar 
4543955d011SMarcel Moolenaar 	if (unmarked)
4553955d011SMarcel Moolenaar 		Make_HandleUse(cgn, pgn);
4563955d011SMarcel Moolenaar 
4573955d011SMarcel Moolenaar 	/*
4583955d011SMarcel Moolenaar 	 * This child node is now "made", so we decrement the count of
4593955d011SMarcel Moolenaar 	 * unmade children in the parent... We also remove the child
4603955d011SMarcel Moolenaar 	 * from the parent's list to accurately reflect the number of decent
4613955d011SMarcel Moolenaar 	 * children the parent has. This is used by Make_Run to decide
4623955d011SMarcel Moolenaar 	 * whether to queue the parent or examine its children...
4633955d011SMarcel Moolenaar 	 */
46406b9b3e0SSimon J. Gerraty 	Lst_Remove(&pgn->children, ln);
4653955d011SMarcel Moolenaar 	pgn->unmade--;
4663955d011SMarcel Moolenaar }
467956e45f6SSimon J. Gerraty 
468956e45f6SSimon J. Gerraty static void
469956e45f6SSimon J. Gerraty HandleUseNodes(GNode *gn)
470956e45f6SSimon J. Gerraty {
471956e45f6SSimon J. Gerraty 	GNodeListNode *ln, *nln;
47206b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = nln) {
473956e45f6SSimon J. Gerraty 		nln = ln->next;
474956e45f6SSimon J. Gerraty 		MakeHandleUse(ln->datum, gn, ln);
475956e45f6SSimon J. Gerraty 	}
4763955d011SMarcel Moolenaar }
4773955d011SMarcel Moolenaar 
4783955d011SMarcel Moolenaar 
47906b9b3e0SSimon J. Gerraty /*
48006b9b3e0SSimon J. Gerraty  * Check the modification time of a gnode, and update it if necessary.
48106b9b3e0SSimon J. Gerraty  * Return 0 if the gnode does not exist, or its filesystem time if it does.
48206b9b3e0SSimon J. Gerraty  */
4833955d011SMarcel Moolenaar time_t
4843955d011SMarcel Moolenaar Make_Recheck(GNode *gn)
4853955d011SMarcel Moolenaar {
486e2eeea75SSimon J. Gerraty 	time_t mtime;
487e2eeea75SSimon J. Gerraty 
488e2eeea75SSimon J. Gerraty 	Dir_UpdateMTime(gn, TRUE);
489e2eeea75SSimon J. Gerraty 	mtime = gn->mtime;
4903955d011SMarcel Moolenaar 
4913955d011SMarcel Moolenaar #ifndef RECHECK
4923955d011SMarcel Moolenaar 	/*
4933955d011SMarcel Moolenaar 	 * We can't re-stat the thing, but we can at least take care of rules
4943955d011SMarcel Moolenaar 	 * where a target depends on a source that actually creates the
4953955d011SMarcel Moolenaar 	 * target, but only if it has changed, e.g.
4963955d011SMarcel Moolenaar 	 *
4973955d011SMarcel Moolenaar 	 * parse.h : parse.o
4983955d011SMarcel Moolenaar 	 *
4993955d011SMarcel Moolenaar 	 * parse.o : parse.y
5003955d011SMarcel Moolenaar 	 *		yacc -d parse.y
5013955d011SMarcel Moolenaar 	 *		cc -c y.tab.c
5023955d011SMarcel Moolenaar 	 *		mv y.tab.o parse.o
5033955d011SMarcel Moolenaar 	 *		cmp -s y.tab.h parse.h || mv y.tab.h parse.h
5043955d011SMarcel Moolenaar 	 *
5053955d011SMarcel Moolenaar 	 * In this case, if the definitions produced by yacc haven't changed
5063955d011SMarcel Moolenaar 	 * from before, parse.h won't have been updated and gn->mtime will
5073955d011SMarcel Moolenaar 	 * reflect the current modification time for parse.h. This is
508e2eeea75SSimon J. Gerraty 	 * something of a kludge, I admit, but it's a useful one.
5093955d011SMarcel Moolenaar 	 *
510e2eeea75SSimon J. Gerraty 	 * XXX: People like to use a rule like "FRC:" to force things that
511e2eeea75SSimon J. Gerraty 	 * depend on FRC to be made, so we have to check for gn->children
512e2eeea75SSimon J. Gerraty 	 * being empty as well.
5133955d011SMarcel Moolenaar 	 */
5143955d011SMarcel Moolenaar 	if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
5153955d011SMarcel Moolenaar 		gn->mtime = now;
5163955d011SMarcel Moolenaar 	}
5173955d011SMarcel Moolenaar #else
5183955d011SMarcel Moolenaar 	/*
5193955d011SMarcel Moolenaar 	 * This is what Make does and it's actually a good thing, as it
5203955d011SMarcel Moolenaar 	 * allows rules like
5213955d011SMarcel Moolenaar 	 *
5223955d011SMarcel Moolenaar 	 *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
5233955d011SMarcel Moolenaar 	 *
5243955d011SMarcel Moolenaar 	 * to function as intended. Unfortunately, thanks to the stateless
5253955d011SMarcel Moolenaar 	 * nature of NFS (by which I mean the loose coupling of two clients
52606b9b3e0SSimon J. Gerraty 	 * using the same file from a common server), there are times when
52706b9b3e0SSimon J. Gerraty 	 * the modification time of a file created on a remote machine
52806b9b3e0SSimon J. Gerraty 	 * will not be modified before the local stat() implied by the
52906b9b3e0SSimon J. Gerraty 	 * Dir_UpdateMTime occurs, thus leading us to believe that the file
5303955d011SMarcel Moolenaar 	 * is unchanged, wreaking havoc with files that depend on this one.
5313955d011SMarcel Moolenaar 	 *
5323955d011SMarcel Moolenaar 	 * I have decided it is better to make too much than to make too
5333955d011SMarcel Moolenaar 	 * little, so this stuff is commented out unless you're sure it's ok.
5343955d011SMarcel Moolenaar 	 * -- ardeb 1/12/88
5353955d011SMarcel Moolenaar 	 */
5363955d011SMarcel Moolenaar 	/*
537e2eeea75SSimon J. Gerraty 	 * Christos, 4/9/92: If we are saving commands, pretend that
538e2eeea75SSimon J. Gerraty 	 * the target is made now. Otherwise archives with '...' rules
5393955d011SMarcel Moolenaar 	 * don't work!
5403955d011SMarcel Moolenaar 	 */
541956e45f6SSimon J. Gerraty 	if (!GNode_ShouldExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
5423955d011SMarcel Moolenaar 	    (mtime == 0 && !(gn->type & OP_WAIT))) {
543956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, " recheck(%s): update time from %s to now\n",
54406b9b3e0SSimon J. Gerraty 		    gn->name,
54506b9b3e0SSimon J. Gerraty 		    gn->mtime == 0 ? "nonexistent" : Targ_FmtTime(gn->mtime));
5463955d011SMarcel Moolenaar 		gn->mtime = now;
547e2eeea75SSimon J. Gerraty 	} else {
548956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, " recheck(%s): current update time: %s\n",
5493955d011SMarcel Moolenaar 		    gn->name, Targ_FmtTime(gn->mtime));
5503955d011SMarcel Moolenaar 	}
5513955d011SMarcel Moolenaar #endif
552e2eeea75SSimon J. Gerraty 
553e2eeea75SSimon J. Gerraty 	/* XXX: The returned mtime may differ from gn->mtime.
554e2eeea75SSimon J. Gerraty 	 * Intentionally? */
5553955d011SMarcel Moolenaar 	return mtime;
5563955d011SMarcel Moolenaar }
5573955d011SMarcel Moolenaar 
558956e45f6SSimon J. Gerraty /*
559956e45f6SSimon J. Gerraty  * Set the .PREFIX and .IMPSRC variables for all the implied parents
560956e45f6SSimon J. Gerraty  * of this node.
561956e45f6SSimon J. Gerraty  */
562956e45f6SSimon J. Gerraty static void
563956e45f6SSimon J. Gerraty UpdateImplicitParentsVars(GNode *cgn, const char *cname)
564956e45f6SSimon J. Gerraty {
565956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
566956e45f6SSimon J. Gerraty 	const char *cpref = GNode_VarPrefix(cgn);
567956e45f6SSimon J. Gerraty 
56806b9b3e0SSimon J. Gerraty 	for (ln = cgn->implicitParents.first; ln != NULL; ln = ln->next) {
569956e45f6SSimon J. Gerraty 		GNode *pgn = ln->datum;
570956e45f6SSimon J. Gerraty 		if (pgn->flags & REMAKE) {
571*dba7b0efSSimon J. Gerraty 			Var_Set(pgn, IMPSRC, cname);
572956e45f6SSimon J. Gerraty 			if (cpref != NULL)
573*dba7b0efSSimon J. Gerraty 				Var_Set(pgn, PREFIX, cpref);
574956e45f6SSimon J. Gerraty 		}
575956e45f6SSimon J. Gerraty 	}
576956e45f6SSimon J. Gerraty }
577956e45f6SSimon J. Gerraty 
578e2eeea75SSimon J. Gerraty /* See if a .ORDER rule stops us from building this node. */
579e2eeea75SSimon J. Gerraty static Boolean
580e2eeea75SSimon J. Gerraty IsWaitingForOrder(GNode *gn)
581e2eeea75SSimon J. Gerraty {
582e2eeea75SSimon J. Gerraty 	GNodeListNode *ln;
583e2eeea75SSimon J. Gerraty 
58406b9b3e0SSimon J. Gerraty 	for (ln = gn->order_pred.first; ln != NULL; ln = ln->next) {
585e2eeea75SSimon J. Gerraty 		GNode *ogn = ln->datum;
586e2eeea75SSimon J. Gerraty 
58706b9b3e0SSimon J. Gerraty 		if (GNode_IsDone(ogn) || !(ogn->flags & REMAKE))
588e2eeea75SSimon J. Gerraty 			continue;
589e2eeea75SSimon J. Gerraty 
59006b9b3e0SSimon J. Gerraty 		DEBUG2(MAKE,
59106b9b3e0SSimon J. Gerraty 		    "IsWaitingForOrder: Waiting for .ORDER node \"%s%s\"\n",
592e2eeea75SSimon J. Gerraty 		    ogn->name, ogn->cohort_num);
593e2eeea75SSimon J. Gerraty 		return TRUE;
594e2eeea75SSimon J. Gerraty 	}
595e2eeea75SSimon J. Gerraty 	return FALSE;
596e2eeea75SSimon J. Gerraty }
597e2eeea75SSimon J. Gerraty 
598*dba7b0efSSimon J. Gerraty static void MakeBuildParent(GNode *, GNodeListNode *);
59906b9b3e0SSimon J. Gerraty 
60006b9b3e0SSimon J. Gerraty static void
60106b9b3e0SSimon J. Gerraty ScheduleOrderSuccessors(GNode *gn)
60206b9b3e0SSimon J. Gerraty {
60306b9b3e0SSimon J. Gerraty 	GNodeListNode *toBeMadeNext = toBeMade.first;
60406b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
60506b9b3e0SSimon J. Gerraty 
60606b9b3e0SSimon J. Gerraty 	for (ln = gn->order_succ.first; ln != NULL; ln = ln->next)
607*dba7b0efSSimon J. Gerraty 		MakeBuildParent(ln->datum, toBeMadeNext);
60806b9b3e0SSimon J. Gerraty }
60906b9b3e0SSimon J. Gerraty 
61006b9b3e0SSimon J. Gerraty /*
61106b9b3e0SSimon J. Gerraty  * Perform update on the parents of a node. Used by JobFinish once
6123955d011SMarcel Moolenaar  * a node has been dealt with and by MakeStartJobs if it finds an
6133955d011SMarcel Moolenaar  * up-to-date node.
6143955d011SMarcel Moolenaar  *
6153955d011SMarcel Moolenaar  * The unmade field of pgn is decremented and pgn may be placed on
6163955d011SMarcel Moolenaar  * the toBeMade queue if this field becomes 0.
6173955d011SMarcel Moolenaar  *
6183955d011SMarcel Moolenaar  * If the child was made, the parent's flag CHILDMADE field will be
6193955d011SMarcel Moolenaar  * set true.
6203955d011SMarcel Moolenaar  *
6213955d011SMarcel Moolenaar  * If the child is not up-to-date and still does not exist,
6223955d011SMarcel Moolenaar  * set the FORCE flag on the parents.
6233955d011SMarcel Moolenaar  *
624956e45f6SSimon J. Gerraty  * If the child wasn't made, the youngestChild field of the parent will be
6253955d011SMarcel Moolenaar  * altered if the child's mtime is big enough.
6263955d011SMarcel Moolenaar  *
6273955d011SMarcel Moolenaar  * Finally, if the child is the implied source for the parent, the
6283955d011SMarcel Moolenaar  * parent's IMPSRC variable is set appropriately.
6293955d011SMarcel Moolenaar  */
6303955d011SMarcel Moolenaar void
6313955d011SMarcel Moolenaar Make_Update(GNode *cgn)
6323955d011SMarcel Moolenaar {
6332c3632d1SSimon J. Gerraty 	const char *cname;	/* the child's name */
6343955d011SMarcel Moolenaar 	time_t mtime = -1;
635956e45f6SSimon J. Gerraty 	GNodeList *parents;
636956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
6373955d011SMarcel Moolenaar 	GNode *centurion;
6383955d011SMarcel Moolenaar 
6393955d011SMarcel Moolenaar 	/* It is save to re-examine any nodes again */
640e2eeea75SSimon J. Gerraty 	checked_seqno++;
6413955d011SMarcel Moolenaar 
642956e45f6SSimon J. Gerraty 	cname = GNode_VarTarget(cgn);
6433955d011SMarcel Moolenaar 
644956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
6453955d011SMarcel Moolenaar 
6463955d011SMarcel Moolenaar 	/*
6473955d011SMarcel Moolenaar 	 * If the child was actually made, see what its modification time is
64806b9b3e0SSimon J. Gerraty 	 * now -- some rules won't actually update the file. If the file
64906b9b3e0SSimon J. Gerraty 	 * still doesn't exist, make its mtime now.
6503955d011SMarcel Moolenaar 	 */
6513955d011SMarcel Moolenaar 	if (cgn->made != UPTODATE) {
6523955d011SMarcel Moolenaar 		mtime = Make_Recheck(cgn);
6533955d011SMarcel Moolenaar 	}
6543955d011SMarcel Moolenaar 
6553955d011SMarcel Moolenaar 	/*
6563955d011SMarcel Moolenaar 	 * If this is a `::' node, we must consult its first instance
6573955d011SMarcel Moolenaar 	 * which is where all parents are linked.
6583955d011SMarcel Moolenaar 	 */
6593955d011SMarcel Moolenaar 	if ((centurion = cgn->centurion) != NULL) {
66006b9b3e0SSimon J. Gerraty 		if (!Lst_IsEmpty(&cgn->parents))
66106b9b3e0SSimon J. Gerraty 			Punt("%s%s: cohort has parents", cgn->name,
66206b9b3e0SSimon J. Gerraty 			    cgn->cohort_num);
663956e45f6SSimon J. Gerraty 		centurion->unmade_cohorts--;
6643955d011SMarcel Moolenaar 		if (centurion->unmade_cohorts < 0)
66506b9b3e0SSimon J. Gerraty 			Error("Graph cycles through centurion %s",
66606b9b3e0SSimon J. Gerraty 			    centurion->name);
6673955d011SMarcel Moolenaar 	} else {
6683955d011SMarcel Moolenaar 		centurion = cgn;
6693955d011SMarcel Moolenaar 	}
67006b9b3e0SSimon J. Gerraty 	parents = &centurion->parents;
6713955d011SMarcel Moolenaar 
6723955d011SMarcel Moolenaar 	/* If this was a .ORDER node, schedule the RHS */
67306b9b3e0SSimon J. Gerraty 	ScheduleOrderSuccessors(centurion);
6743955d011SMarcel Moolenaar 
6753955d011SMarcel Moolenaar 	/* Now mark all the parents as having one less unmade child */
676956e45f6SSimon J. Gerraty 	for (ln = parents->first; ln != NULL; ln = ln->next) {
677956e45f6SSimon J. Gerraty 		GNode *pgn = ln->datum;
678956e45f6SSimon J. Gerraty 
679e2eeea75SSimon J. Gerraty 		if (DEBUG(MAKE)) {
68006b9b3e0SSimon J. Gerraty 			debug_printf("inspect parent %s%s: ", pgn->name,
68106b9b3e0SSimon J. Gerraty 			    pgn->cohort_num);
682e2eeea75SSimon J. Gerraty 			GNode_FprintDetails(opts.debug_file, "", pgn, "");
683e2eeea75SSimon J. Gerraty 			debug_printf(", unmade %d ", pgn->unmade - 1);
684e2eeea75SSimon J. Gerraty 		}
6853955d011SMarcel Moolenaar 
6863955d011SMarcel Moolenaar 		if (!(pgn->flags & REMAKE)) {
6873955d011SMarcel Moolenaar 			/* This parent isn't needed */
688956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- not needed\n");
6893955d011SMarcel Moolenaar 			continue;
6903955d011SMarcel Moolenaar 		}
6913955d011SMarcel Moolenaar 		if (mtime == 0 && !(cgn->type & OP_WAIT))
6923955d011SMarcel Moolenaar 			pgn->flags |= FORCE;
6933955d011SMarcel Moolenaar 
6943955d011SMarcel Moolenaar 		/*
6953955d011SMarcel Moolenaar 		 * If the parent has the .MADE attribute, its timestamp got
696956e45f6SSimon J. Gerraty 		 * updated to that of its newest child, and its unmade
6973955d011SMarcel Moolenaar 		 * child count got set to zero in Make_ExpandUse().
6983955d011SMarcel Moolenaar 		 * However other things might cause us to build one of its
6993955d011SMarcel Moolenaar 		 * children - and so we mustn't do any processing here when
7003955d011SMarcel Moolenaar 		 * the child build finishes.
7013955d011SMarcel Moolenaar 		 */
7023955d011SMarcel Moolenaar 		if (pgn->type & OP_MADE) {
703956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- .MADE\n");
7043955d011SMarcel Moolenaar 			continue;
7053955d011SMarcel Moolenaar 		}
7063955d011SMarcel Moolenaar 
7073955d011SMarcel Moolenaar 		if (!(cgn->type & (OP_EXEC | OP_USE | OP_USEBEFORE))) {
7083955d011SMarcel Moolenaar 			if (cgn->made == MADE)
7093955d011SMarcel Moolenaar 				pgn->flags |= CHILDMADE;
710e2eeea75SSimon J. Gerraty 			GNode_UpdateYoungestChild(pgn, cgn);
7113955d011SMarcel Moolenaar 		}
7123955d011SMarcel Moolenaar 
7133955d011SMarcel Moolenaar 		/*
7143955d011SMarcel Moolenaar 		 * A parent must wait for the completion of all instances
7153955d011SMarcel Moolenaar 		 * of a `::' dependency.
7163955d011SMarcel Moolenaar 		 */
71706b9b3e0SSimon J. Gerraty 		if (centurion->unmade_cohorts != 0 ||
71806b9b3e0SSimon J. Gerraty 		    !GNode_IsDone(centurion)) {
71906b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE,
72006b9b3e0SSimon J. Gerraty 			    "- centurion made %d, %d unmade cohorts\n",
7213955d011SMarcel Moolenaar 			    centurion->made, centurion->unmade_cohorts);
7223955d011SMarcel Moolenaar 			continue;
7233955d011SMarcel Moolenaar 		}
7243955d011SMarcel Moolenaar 
7253955d011SMarcel Moolenaar 		/* One more child of this parent is now made */
726956e45f6SSimon J. Gerraty 		pgn->unmade--;
7273955d011SMarcel Moolenaar 		if (pgn->unmade < 0) {
7283955d011SMarcel Moolenaar 			if (DEBUG(MAKE)) {
729956e45f6SSimon J. Gerraty 				debug_printf("Graph cycles through %s%s\n",
7303955d011SMarcel Moolenaar 				    pgn->name, pgn->cohort_num);
7313955d011SMarcel Moolenaar 				Targ_PrintGraph(2);
7323955d011SMarcel Moolenaar 			}
73306b9b3e0SSimon J. Gerraty 			Error("Graph cycles through %s%s", pgn->name,
73406b9b3e0SSimon J. Gerraty 			    pgn->cohort_num);
7353955d011SMarcel Moolenaar 		}
7363955d011SMarcel Moolenaar 
73706b9b3e0SSimon J. Gerraty 		/*
73806b9b3e0SSimon J. Gerraty 		 * We must always rescan the parents of .WAIT and .ORDER
73906b9b3e0SSimon J. Gerraty 		 * nodes.
74006b9b3e0SSimon J. Gerraty 		 */
7413955d011SMarcel Moolenaar 		if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
7423955d011SMarcel Moolenaar 		    && !(centurion->flags & DONE_ORDER)) {
743956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- unmade children\n");
7443955d011SMarcel Moolenaar 			continue;
7453955d011SMarcel Moolenaar 		}
7463955d011SMarcel Moolenaar 		if (pgn->made != DEFERRED) {
7473955d011SMarcel Moolenaar 			/*
74806b9b3e0SSimon J. Gerraty 			 * Either this parent is on a different branch of
74906b9b3e0SSimon J. Gerraty 			 * the tree, or it on the RHS of a .WAIT directive
7503955d011SMarcel Moolenaar 			 * or it is already on the toBeMade list.
7513955d011SMarcel Moolenaar 			 */
752956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- not deferred\n");
7533955d011SMarcel Moolenaar 			continue;
7543955d011SMarcel Moolenaar 		}
755e2eeea75SSimon J. Gerraty 
756e2eeea75SSimon J. Gerraty 		if (IsWaitingForOrder(pgn))
7573955d011SMarcel Moolenaar 			continue;
758e2eeea75SSimon J. Gerraty 
7593955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
760956e45f6SSimon J. Gerraty 			debug_printf("- %s%s made, schedule %s%s (made %d)\n",
7613955d011SMarcel Moolenaar 			    cgn->name, cgn->cohort_num,
7623955d011SMarcel Moolenaar 			    pgn->name, pgn->cohort_num, pgn->made);
763956e45f6SSimon J. Gerraty 			Targ_PrintNode(pgn, 2);
7643955d011SMarcel Moolenaar 		}
7653955d011SMarcel Moolenaar 		/* Ok, we can schedule the parent again */
7663955d011SMarcel Moolenaar 		pgn->made = REQUESTED;
76706b9b3e0SSimon J. Gerraty 		Lst_Enqueue(&toBeMade, pgn);
7683955d011SMarcel Moolenaar 	}
7693955d011SMarcel Moolenaar 
770956e45f6SSimon J. Gerraty 	UpdateImplicitParentsVars(cgn, cname);
771956e45f6SSimon J. Gerraty }
772956e45f6SSimon J. Gerraty 
773956e45f6SSimon J. Gerraty static void
774956e45f6SSimon J. Gerraty UnmarkChildren(GNode *gn)
7752c3632d1SSimon J. Gerraty {
776956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
7773955d011SMarcel Moolenaar 
77806b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next) {
779956e45f6SSimon J. Gerraty 		GNode *child = ln->datum;
780956e45f6SSimon J. Gerraty 		child->type &= ~OP_MARK;
7813955d011SMarcel Moolenaar 	}
7823955d011SMarcel Moolenaar }
7832c3632d1SSimon J. Gerraty 
78406b9b3e0SSimon J. Gerraty /*
78506b9b3e0SSimon J. Gerraty  * Add a child's name to the ALLSRC and OODATE variables of the given
786956e45f6SSimon J. Gerraty  * node, but only if it has not been given the .EXEC, .USE or .INVISIBLE
787956e45f6SSimon J. Gerraty  * attributes. .EXEC and .USE children are very rarely going to be files,
788956e45f6SSimon J. Gerraty  * so...
789956e45f6SSimon J. Gerraty  *
7903955d011SMarcel Moolenaar  * If the child is a .JOIN node, its ALLSRC is propagated to the parent.
7913955d011SMarcel Moolenaar  *
7923955d011SMarcel Moolenaar  * A child is added to the OODATE variable if its modification time is
7933955d011SMarcel Moolenaar  * later than that of its parent, as defined by Make, except if the
7943955d011SMarcel Moolenaar  * parent is a .JOIN node. In that case, it is only added to the OODATE
7953955d011SMarcel Moolenaar  * variable if it was actually made (since .JOIN nodes don't have
7963955d011SMarcel Moolenaar  * modification times, the comparison is rather unfair...)..
7973955d011SMarcel Moolenaar  *
7983955d011SMarcel Moolenaar  * Input:
799956e45f6SSimon J. Gerraty  *	cgn		The child to add
800956e45f6SSimon J. Gerraty  *	pgn		The parent to whose ALLSRC variable it should
8013955d011SMarcel Moolenaar  *			be added
8023955d011SMarcel Moolenaar  */
803956e45f6SSimon J. Gerraty static void
804956e45f6SSimon J. Gerraty MakeAddAllSrc(GNode *cgn, GNode *pgn)
8053955d011SMarcel Moolenaar {
806*dba7b0efSSimon J. Gerraty 	const char *child, *allsrc;
807*dba7b0efSSimon J. Gerraty 
8083955d011SMarcel Moolenaar 	if (cgn->type & OP_MARK)
809956e45f6SSimon J. Gerraty 		return;
8103955d011SMarcel Moolenaar 	cgn->type |= OP_MARK;
8113955d011SMarcel Moolenaar 
812*dba7b0efSSimon J. Gerraty 	if (cgn->type & (OP_EXEC | OP_USE | OP_USEBEFORE | OP_INVISIBLE))
813*dba7b0efSSimon J. Gerraty 		return;
8143955d011SMarcel Moolenaar 
8153955d011SMarcel Moolenaar 	if (cgn->type & OP_ARCHV)
816956e45f6SSimon J. Gerraty 		child = GNode_VarMember(cgn);
8173955d011SMarcel Moolenaar 	else
818956e45f6SSimon J. Gerraty 		child = GNode_Path(cgn);
819*dba7b0efSSimon J. Gerraty 
820*dba7b0efSSimon J. Gerraty 	if (cgn->type & OP_JOIN)
821956e45f6SSimon J. Gerraty 		allsrc = GNode_VarAllsrc(cgn);
822*dba7b0efSSimon J. Gerraty 	else
8233955d011SMarcel Moolenaar 		allsrc = child;
824*dba7b0efSSimon J. Gerraty 
8253955d011SMarcel Moolenaar 	if (allsrc != NULL)
826*dba7b0efSSimon J. Gerraty 		Var_Append(pgn, ALLSRC, allsrc);
827*dba7b0efSSimon J. Gerraty 
8283955d011SMarcel Moolenaar 	if (pgn->type & OP_JOIN) {
829*dba7b0efSSimon J. Gerraty 		if (cgn->made == MADE)
830*dba7b0efSSimon J. Gerraty 			Var_Append(pgn, OODATE, child);
831*dba7b0efSSimon J. Gerraty 
8323955d011SMarcel Moolenaar 	} else if ((pgn->mtime < cgn->mtime) ||
83306b9b3e0SSimon J. Gerraty 		   (cgn->mtime >= now && cgn->made == MADE)) {
8343955d011SMarcel Moolenaar 		/*
83506b9b3e0SSimon J. Gerraty 		 * It goes in the OODATE variable if the parent is
83606b9b3e0SSimon J. Gerraty 		 * younger than the child or if the child has been
83706b9b3e0SSimon J. Gerraty 		 * modified more recently than the start of the make.
83806b9b3e0SSimon J. Gerraty 		 * This is to keep pmake from getting confused if
83906b9b3e0SSimon J. Gerraty 		 * something else updates the parent after the make
84006b9b3e0SSimon J. Gerraty 		 * starts (shouldn't happen, I know, but sometimes it
84106b9b3e0SSimon J. Gerraty 		 * does). In such a case, if we've updated the child,
84206b9b3e0SSimon J. Gerraty 		 * the parent is likely to have a modification time
84306b9b3e0SSimon J. Gerraty 		 * later than that of the child and anything that
84406b9b3e0SSimon J. Gerraty 		 * relies on the OODATE variable will be hosed.
8453955d011SMarcel Moolenaar 		 *
84606b9b3e0SSimon J. Gerraty 		 * XXX: This will cause all made children to go in
84706b9b3e0SSimon J. Gerraty 		 * the OODATE variable, even if they're not touched,
84806b9b3e0SSimon J. Gerraty 		 * if RECHECK isn't defined, since cgn->mtime is set
84906b9b3e0SSimon J. Gerraty 		 * to now in Make_Update. According to some people,
85006b9b3e0SSimon J. Gerraty 		 * this is good...
8513955d011SMarcel Moolenaar 		 */
852*dba7b0efSSimon J. Gerraty 		Var_Append(pgn, OODATE, child);
8533955d011SMarcel Moolenaar 	}
8543955d011SMarcel Moolenaar }
8552c3632d1SSimon J. Gerraty 
85606b9b3e0SSimon J. Gerraty /*
85706b9b3e0SSimon J. Gerraty  * Set up the ALLSRC and OODATE variables. Sad to say, it must be
8583955d011SMarcel Moolenaar  * done separately, rather than while traversing the graph. This is
8593955d011SMarcel Moolenaar  * because Make defined OODATE to contain all sources whose modification
8603955d011SMarcel Moolenaar  * times were later than that of the target, *not* those sources that
8613955d011SMarcel Moolenaar  * were out-of-date. Since in both compatibility and native modes,
8623955d011SMarcel Moolenaar  * the modification time of the parent isn't found until the child
8633955d011SMarcel Moolenaar  * has been dealt with, we have to wait until now to fill in the
8643955d011SMarcel Moolenaar  * variable. As for ALLSRC, the ordering is important and not
8653955d011SMarcel Moolenaar  * guaranteed when in native mode, so it must be set here, too.
8663955d011SMarcel Moolenaar  *
8673955d011SMarcel Moolenaar  * If the node is a .JOIN node, its TARGET variable will be set to
8683955d011SMarcel Moolenaar  * match its ALLSRC variable.
8693955d011SMarcel Moolenaar  */
8703955d011SMarcel Moolenaar void
8713955d011SMarcel Moolenaar Make_DoAllVar(GNode *gn)
8723955d011SMarcel Moolenaar {
873956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
874956e45f6SSimon J. Gerraty 
8753955d011SMarcel Moolenaar 	if (gn->flags & DONE_ALLSRC)
8763955d011SMarcel Moolenaar 		return;
8773955d011SMarcel Moolenaar 
878956e45f6SSimon J. Gerraty 	UnmarkChildren(gn);
87906b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next)
880956e45f6SSimon J. Gerraty 		MakeAddAllSrc(ln->datum, gn);
8813955d011SMarcel Moolenaar 
882*dba7b0efSSimon J. Gerraty 	if (!Var_Exists(gn, OODATE))
883*dba7b0efSSimon J. Gerraty 		Var_Set(gn, OODATE, "");
884*dba7b0efSSimon J. Gerraty 	if (!Var_Exists(gn, ALLSRC))
885*dba7b0efSSimon J. Gerraty 		Var_Set(gn, ALLSRC, "");
8863955d011SMarcel Moolenaar 
887956e45f6SSimon J. Gerraty 	if (gn->type & OP_JOIN)
888*dba7b0efSSimon J. Gerraty 		Var_Set(gn, TARGET, GNode_VarAllsrc(gn));
8893955d011SMarcel Moolenaar 	gn->flags |= DONE_ALLSRC;
8903955d011SMarcel Moolenaar }
8912c3632d1SSimon J. Gerraty 
892*dba7b0efSSimon J. Gerraty static Boolean
89306b9b3e0SSimon J. Gerraty MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
8943955d011SMarcel Moolenaar {
8953955d011SMarcel Moolenaar 
896e2eeea75SSimon J. Gerraty 	if (DEBUG(MAKE)) {
897e2eeea75SSimon J. Gerraty 		debug_printf("MakeBuildChild: inspect %s%s, ",
898e2eeea75SSimon J. Gerraty 		    cn->name, cn->cohort_num);
899e2eeea75SSimon J. Gerraty 		GNode_FprintDetails(opts.debug_file, "", cn, "\n");
900e2eeea75SSimon J. Gerraty 	}
90106b9b3e0SSimon J. Gerraty 	if (GNode_IsReady(cn))
902*dba7b0efSSimon J. Gerraty 		return FALSE;
9033955d011SMarcel Moolenaar 
9043955d011SMarcel Moolenaar 	/* If this node is on the RHS of a .ORDER, check LHSs. */
905e2eeea75SSimon J. Gerraty 	if (IsWaitingForOrder(cn)) {
9063955d011SMarcel Moolenaar 		/* Can't build this (or anything else in this child list) yet */
9073955d011SMarcel Moolenaar 		cn->made = DEFERRED;
908*dba7b0efSSimon J. Gerraty 		return FALSE;	/* but keep looking */
9093955d011SMarcel Moolenaar 	}
9103955d011SMarcel Moolenaar 
91106b9b3e0SSimon J. Gerraty 	DEBUG2(MAKE, "MakeBuildChild: schedule %s%s\n",
91206b9b3e0SSimon J. Gerraty 	    cn->name, cn->cohort_num);
9133955d011SMarcel Moolenaar 
9143955d011SMarcel Moolenaar 	cn->made = REQUESTED;
91506b9b3e0SSimon J. Gerraty 	if (toBeMadeNext == NULL)
91606b9b3e0SSimon J. Gerraty 		Lst_Append(&toBeMade, cn);
9173955d011SMarcel Moolenaar 	else
91806b9b3e0SSimon J. Gerraty 		Lst_InsertBefore(&toBeMade, toBeMadeNext, cn);
9193955d011SMarcel Moolenaar 
92006b9b3e0SSimon J. Gerraty 	if (cn->unmade_cohorts != 0) {
92106b9b3e0SSimon J. Gerraty 		ListNode *ln;
92206b9b3e0SSimon J. Gerraty 
92306b9b3e0SSimon J. Gerraty 		for (ln = cn->cohorts.first; ln != NULL; ln = ln->next)
924*dba7b0efSSimon J. Gerraty 			if (MakeBuildChild(ln->datum, toBeMadeNext))
92506b9b3e0SSimon J. Gerraty 				break;
92606b9b3e0SSimon J. Gerraty 	}
9273955d011SMarcel Moolenaar 
9283955d011SMarcel Moolenaar 	/*
929956e45f6SSimon J. Gerraty 	 * If this node is a .WAIT node with unmade children
9303955d011SMarcel Moolenaar 	 * then don't add the next sibling.
9313955d011SMarcel Moolenaar 	 */
9323955d011SMarcel Moolenaar 	return cn->type & OP_WAIT && cn->unmade > 0;
9333955d011SMarcel Moolenaar }
9343955d011SMarcel Moolenaar 
935e2eeea75SSimon J. Gerraty /* When a .ORDER LHS node completes, we do this on each RHS. */
936*dba7b0efSSimon J. Gerraty static void
93706b9b3e0SSimon J. Gerraty MakeBuildParent(GNode *pn, GNodeListNode *toBeMadeNext)
9383955d011SMarcel Moolenaar {
9393955d011SMarcel Moolenaar 	if (pn->made != DEFERRED)
940*dba7b0efSSimon J. Gerraty 		return;
9413955d011SMarcel Moolenaar 
942*dba7b0efSSimon J. Gerraty 	if (!MakeBuildChild(pn, toBeMadeNext)) {
94306b9b3e0SSimon J. Gerraty 		/* When this node is built, reschedule its parents. */
9443955d011SMarcel Moolenaar 		pn->flags |= DONE_ORDER;
9453955d011SMarcel Moolenaar 	}
9463955d011SMarcel Moolenaar }
9473955d011SMarcel Moolenaar 
94806b9b3e0SSimon J. Gerraty static void
94906b9b3e0SSimon J. Gerraty MakeChildren(GNode *gn)
95006b9b3e0SSimon J. Gerraty {
95106b9b3e0SSimon J. Gerraty 	GNodeListNode *toBeMadeNext = toBeMade.first;
95206b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
95306b9b3e0SSimon J. Gerraty 
95406b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next)
955*dba7b0efSSimon J. Gerraty 		if (MakeBuildChild(ln->datum, toBeMadeNext))
95606b9b3e0SSimon J. Gerraty 			break;
95706b9b3e0SSimon J. Gerraty }
95806b9b3e0SSimon J. Gerraty 
95906b9b3e0SSimon J. Gerraty /*
96006b9b3e0SSimon J. Gerraty  * Start as many jobs as possible, taking them from the toBeMade queue.
961956e45f6SSimon J. Gerraty  *
962e2eeea75SSimon J. Gerraty  * If the -q option was given, no job will be started,
963956e45f6SSimon J. Gerraty  * but as soon as an out-of-date target is found, this function
964e2eeea75SSimon J. Gerraty  * returns TRUE. In all other cases, this function returns FALSE.
965956e45f6SSimon J. Gerraty  */
9663955d011SMarcel Moolenaar static Boolean
9673955d011SMarcel Moolenaar MakeStartJobs(void)
9683955d011SMarcel Moolenaar {
9693955d011SMarcel Moolenaar 	GNode *gn;
970e2eeea75SSimon J. Gerraty 	Boolean have_token = FALSE;
9713955d011SMarcel Moolenaar 
97206b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&toBeMade)) {
97306b9b3e0SSimon J. Gerraty 		/*
97406b9b3e0SSimon J. Gerraty 		 * Get token now to avoid cycling job-list when we only
97506b9b3e0SSimon J. Gerraty 		 * have 1 token
97606b9b3e0SSimon J. Gerraty 		 */
9773955d011SMarcel Moolenaar 		if (!have_token && !Job_TokenWithdraw())
9783955d011SMarcel Moolenaar 			break;
979e2eeea75SSimon J. Gerraty 		have_token = TRUE;
9803955d011SMarcel Moolenaar 
98106b9b3e0SSimon J. Gerraty 		gn = Lst_Dequeue(&toBeMade);
982956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num);
9833955d011SMarcel Moolenaar 
9843955d011SMarcel Moolenaar 		if (gn->made != REQUESTED) {
98506b9b3e0SSimon J. Gerraty 			/*
98606b9b3e0SSimon J. Gerraty 			 * XXX: Replace %d with string representation;
98706b9b3e0SSimon J. Gerraty 			 * see made_name.
98806b9b3e0SSimon J. Gerraty 			 */
989956e45f6SSimon J. Gerraty 			DEBUG1(MAKE, "state %d\n", gn->made);
9903955d011SMarcel Moolenaar 
9913955d011SMarcel Moolenaar 			make_abort(gn, __LINE__);
9923955d011SMarcel Moolenaar 		}
9933955d011SMarcel Moolenaar 
994e2eeea75SSimon J. Gerraty 		if (gn->checked_seqno == checked_seqno) {
99506b9b3e0SSimon J. Gerraty 			/*
99606b9b3e0SSimon J. Gerraty 			 * We've already looked at this node since a job
99706b9b3e0SSimon J. Gerraty 			 * finished...
99806b9b3e0SSimon J. Gerraty 			 */
99906b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE, "already checked %s%s\n", gn->name,
100006b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
10013955d011SMarcel Moolenaar 			gn->made = DEFERRED;
10023955d011SMarcel Moolenaar 			continue;
10033955d011SMarcel Moolenaar 		}
1004e2eeea75SSimon J. Gerraty 		gn->checked_seqno = checked_seqno;
10053955d011SMarcel Moolenaar 
10063955d011SMarcel Moolenaar 		if (gn->unmade != 0) {
10073955d011SMarcel Moolenaar 			/*
100806b9b3e0SSimon J. Gerraty 			 * We can't build this yet, add all unmade children
100906b9b3e0SSimon J. Gerraty 			 * to toBeMade, just before the current first element.
10103955d011SMarcel Moolenaar 			 */
10113955d011SMarcel Moolenaar 			gn->made = DEFERRED;
101206b9b3e0SSimon J. Gerraty 
101306b9b3e0SSimon J. Gerraty 			MakeChildren(gn);
101406b9b3e0SSimon J. Gerraty 
10153955d011SMarcel Moolenaar 			/* and drop this node on the floor */
101606b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE, "dropped %s%s\n", gn->name,
101706b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
10183955d011SMarcel Moolenaar 			continue;
10193955d011SMarcel Moolenaar 		}
10203955d011SMarcel Moolenaar 
10213955d011SMarcel Moolenaar 		gn->made = BEINGMADE;
1022e2eeea75SSimon J. Gerraty 		if (GNode_IsOODate(gn)) {
1023956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "out-of-date\n");
1024e2eeea75SSimon J. Gerraty 			if (opts.queryFlag)
10253841c287SSimon J. Gerraty 				return TRUE;
10263955d011SMarcel Moolenaar 			Make_DoAllVar(gn);
10273955d011SMarcel Moolenaar 			Job_Make(gn);
1028e2eeea75SSimon J. Gerraty 			have_token = FALSE;
10293955d011SMarcel Moolenaar 		} else {
1030956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "up-to-date\n");
10313955d011SMarcel Moolenaar 			gn->made = UPTODATE;
10323955d011SMarcel Moolenaar 			if (gn->type & OP_JOIN) {
10333955d011SMarcel Moolenaar 				/*
103406b9b3e0SSimon J. Gerraty 				 * Even for an up-to-date .JOIN node, we
1035*dba7b0efSSimon J. Gerraty 				 * need it to have its local variables so
103606b9b3e0SSimon J. Gerraty 				 * references to it get the correct value
1037*dba7b0efSSimon J. Gerraty 				 * for .TARGET when building up the local
103806b9b3e0SSimon J. Gerraty 				 * variables of its parent(s)...
10393955d011SMarcel Moolenaar 				 */
10403955d011SMarcel Moolenaar 				Make_DoAllVar(gn);
10413955d011SMarcel Moolenaar 			}
10423955d011SMarcel Moolenaar 			Make_Update(gn);
10433955d011SMarcel Moolenaar 		}
10443955d011SMarcel Moolenaar 	}
10453955d011SMarcel Moolenaar 
10463955d011SMarcel Moolenaar 	if (have_token)
10473955d011SMarcel Moolenaar 		Job_TokenReturn();
10483955d011SMarcel Moolenaar 
10493841c287SSimon J. Gerraty 	return FALSE;
10503955d011SMarcel Moolenaar }
10512c3632d1SSimon J. Gerraty 
1052e2eeea75SSimon J. Gerraty /* Print the status of a .ORDER node. */
1053956e45f6SSimon J. Gerraty static void
1054956e45f6SSimon J. Gerraty MakePrintStatusOrderNode(GNode *ogn, GNode *gn)
10553955d011SMarcel Moolenaar {
105606b9b3e0SSimon J. Gerraty 	if (!GNode_IsWaitingFor(ogn))
1057956e45f6SSimon J. Gerraty 		return;
10583955d011SMarcel Moolenaar 
10592c3632d1SSimon J. Gerraty 	printf("    `%s%s' has .ORDER dependency against %s%s ",
10602c3632d1SSimon J. Gerraty 	    gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
10612c3632d1SSimon J. Gerraty 	GNode_FprintDetails(stdout, "(", ogn, ")\n");
10622c3632d1SSimon J. Gerraty 
1063956e45f6SSimon J. Gerraty 	if (DEBUG(MAKE) && opts.debug_file != stdout) {
1064956e45f6SSimon J. Gerraty 		debug_printf("    `%s%s' has .ORDER dependency against %s%s ",
10652c3632d1SSimon J. Gerraty 		    gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
1066956e45f6SSimon J. Gerraty 		GNode_FprintDetails(opts.debug_file, "(", ogn, ")\n");
10672c3632d1SSimon J. Gerraty 	}
10683955d011SMarcel Moolenaar }
10693955d011SMarcel Moolenaar 
1070956e45f6SSimon J. Gerraty static void
1071956e45f6SSimon J. Gerraty MakePrintStatusOrder(GNode *gn)
10723955d011SMarcel Moolenaar {
1073956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
107406b9b3e0SSimon J. Gerraty 	for (ln = gn->order_pred.first; ln != NULL; ln = ln->next)
1075956e45f6SSimon J. Gerraty 		MakePrintStatusOrderNode(ln->datum, gn);
1076956e45f6SSimon J. Gerraty }
10773955d011SMarcel Moolenaar 
1078956e45f6SSimon J. Gerraty static void MakePrintStatusList(GNodeList *, int *);
1079956e45f6SSimon J. Gerraty 
108006b9b3e0SSimon J. Gerraty /*
108106b9b3e0SSimon J. Gerraty  * Print the status of a top-level node, viz. it being up-to-date already
1082956e45f6SSimon J. Gerraty  * or not created due to an error in a lower level.
1083956e45f6SSimon J. Gerraty  */
1084956e45f6SSimon J. Gerraty static Boolean
1085956e45f6SSimon J. Gerraty MakePrintStatus(GNode *gn, int *errors)
1086956e45f6SSimon J. Gerraty {
108706b9b3e0SSimon J. Gerraty 	if (gn->flags & DONECYCLE) {
108806b9b3e0SSimon J. Gerraty 		/*
108906b9b3e0SSimon J. Gerraty 		 * We've completely processed this node before, don't do
109006b9b3e0SSimon J. Gerraty 		 * it again.
109106b9b3e0SSimon J. Gerraty 		 */
1092956e45f6SSimon J. Gerraty 		return FALSE;
109306b9b3e0SSimon J. Gerraty 	}
10943955d011SMarcel Moolenaar 
10953955d011SMarcel Moolenaar 	if (gn->unmade == 0) {
10963955d011SMarcel Moolenaar 		gn->flags |= DONECYCLE;
10973955d011SMarcel Moolenaar 		switch (gn->made) {
10983955d011SMarcel Moolenaar 		case UPTODATE:
109906b9b3e0SSimon J. Gerraty 			printf("`%s%s' is up to date.\n", gn->name,
110006b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
11013955d011SMarcel Moolenaar 			break;
11023955d011SMarcel Moolenaar 		case MADE:
11033955d011SMarcel Moolenaar 			break;
11043955d011SMarcel Moolenaar 		case UNMADE:
11053955d011SMarcel Moolenaar 		case DEFERRED:
11063955d011SMarcel Moolenaar 		case REQUESTED:
11073955d011SMarcel Moolenaar 		case BEINGMADE:
11083955d011SMarcel Moolenaar 			(*errors)++;
110906b9b3e0SSimon J. Gerraty 			printf("`%s%s' was not built", gn->name,
111006b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
11112c3632d1SSimon J. Gerraty 			GNode_FprintDetails(stdout, " (", gn, ")!\n");
1112956e45f6SSimon J. Gerraty 			if (DEBUG(MAKE) && opts.debug_file != stdout) {
111306b9b3e0SSimon J. Gerraty 				debug_printf("`%s%s' was not built", gn->name,
111406b9b3e0SSimon J. Gerraty 				    gn->cohort_num);
111506b9b3e0SSimon J. Gerraty 				GNode_FprintDetails(opts.debug_file, " (", gn,
111606b9b3e0SSimon J. Gerraty 				    ")!\n");
11172c3632d1SSimon J. Gerraty 			}
11183955d011SMarcel Moolenaar 			/* Most likely problem is actually caused by .ORDER */
1119956e45f6SSimon J. Gerraty 			MakePrintStatusOrder(gn);
11203955d011SMarcel Moolenaar 			break;
11213955d011SMarcel Moolenaar 		default:
11223955d011SMarcel Moolenaar 			/* Errors - already counted */
11233955d011SMarcel Moolenaar 			printf("`%s%s' not remade because of errors.\n",
11243955d011SMarcel Moolenaar 			    gn->name, gn->cohort_num);
1125956e45f6SSimon J. Gerraty 			if (DEBUG(MAKE) && opts.debug_file != stdout)
112606b9b3e0SSimon J. Gerraty 				debug_printf(
112706b9b3e0SSimon J. Gerraty 				    "`%s%s' not remade because of errors.\n",
11283955d011SMarcel Moolenaar 				    gn->name, gn->cohort_num);
11293955d011SMarcel Moolenaar 			break;
11303955d011SMarcel Moolenaar 		}
1131956e45f6SSimon J. Gerraty 		return FALSE;
11323955d011SMarcel Moolenaar 	}
11333955d011SMarcel Moolenaar 
1134956e45f6SSimon J. Gerraty 	DEBUG3(MAKE, "MakePrintStatus: %s%s has %d unmade children\n",
11353955d011SMarcel Moolenaar 	    gn->name, gn->cohort_num, gn->unmade);
11363955d011SMarcel Moolenaar 	/*
11373955d011SMarcel Moolenaar 	 * If printing cycles and came to one that has unmade children,
11383955d011SMarcel Moolenaar 	 * print out the cycle by recursing on its children.
11393955d011SMarcel Moolenaar 	 */
11403955d011SMarcel Moolenaar 	if (!(gn->flags & CYCLE)) {
1141e2eeea75SSimon J. Gerraty 		/* First time we've seen this node, check all children */
11423955d011SMarcel Moolenaar 		gn->flags |= CYCLE;
114306b9b3e0SSimon J. Gerraty 		MakePrintStatusList(&gn->children, errors);
11443955d011SMarcel Moolenaar 		/* Mark that this node needn't be processed again */
11453955d011SMarcel Moolenaar 		gn->flags |= DONECYCLE;
1146956e45f6SSimon J. Gerraty 		return FALSE;
11473955d011SMarcel Moolenaar 	}
11483955d011SMarcel Moolenaar 
11493955d011SMarcel Moolenaar 	/* Only output the error once per node */
11503955d011SMarcel Moolenaar 	gn->flags |= DONECYCLE;
11513955d011SMarcel Moolenaar 	Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
11523955d011SMarcel Moolenaar 	if ((*errors)++ > 100)
11533955d011SMarcel Moolenaar 		/* Abandon the whole error report */
1154956e45f6SSimon J. Gerraty 		return TRUE;
11553955d011SMarcel Moolenaar 
11563955d011SMarcel Moolenaar 	/* Reporting for our children will give the rest of the loop */
115706b9b3e0SSimon J. Gerraty 	MakePrintStatusList(&gn->children, errors);
1158956e45f6SSimon J. Gerraty 	return FALSE;
11593955d011SMarcel Moolenaar }
11602c3632d1SSimon J. Gerraty 
1161956e45f6SSimon J. Gerraty static void
1162956e45f6SSimon J. Gerraty MakePrintStatusList(GNodeList *gnodes, int *errors)
1163956e45f6SSimon J. Gerraty {
1164956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
116506b9b3e0SSimon J. Gerraty 
1166956e45f6SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
1167956e45f6SSimon J. Gerraty 		if (MakePrintStatus(ln->datum, errors))
1168956e45f6SSimon J. Gerraty 			break;
1169956e45f6SSimon J. Gerraty }
11703955d011SMarcel Moolenaar 
1171e2eeea75SSimon J. Gerraty static void
1172e2eeea75SSimon J. Gerraty ExamineLater(GNodeList *examine, GNodeList *toBeExamined)
1173e2eeea75SSimon J. Gerraty {
1174e2eeea75SSimon J. Gerraty 	ListNode *ln;
1175e2eeea75SSimon J. Gerraty 
1176e2eeea75SSimon J. Gerraty 	for (ln = toBeExamined->first; ln != NULL; ln = ln->next) {
1177e2eeea75SSimon J. Gerraty 		GNode *gn = ln->datum;
1178e2eeea75SSimon J. Gerraty 
1179e2eeea75SSimon J. Gerraty 		if (gn->flags & REMAKE)
1180e2eeea75SSimon J. Gerraty 			continue;
1181e2eeea75SSimon J. Gerraty 		if (gn->type & (OP_USE | OP_USEBEFORE))
1182e2eeea75SSimon J. Gerraty 			continue;
1183e2eeea75SSimon J. Gerraty 
1184e2eeea75SSimon J. Gerraty 		DEBUG2(MAKE, "ExamineLater: need to examine \"%s%s\"\n",
1185e2eeea75SSimon J. Gerraty 		    gn->name, gn->cohort_num);
1186e2eeea75SSimon J. Gerraty 		Lst_Enqueue(examine, gn);
1187e2eeea75SSimon J. Gerraty 	}
1188e2eeea75SSimon J. Gerraty }
1189e2eeea75SSimon J. Gerraty 
119006b9b3e0SSimon J. Gerraty /*
119106b9b3e0SSimon J. Gerraty  * Expand .USE nodes and create a new targets list.
11923955d011SMarcel Moolenaar  *
11933955d011SMarcel Moolenaar  * Input:
11943955d011SMarcel Moolenaar  *	targs		the initial list of targets
11953955d011SMarcel Moolenaar  */
11963955d011SMarcel Moolenaar void
1197956e45f6SSimon J. Gerraty Make_ExpandUse(GNodeList *targs)
11983955d011SMarcel Moolenaar {
119906b9b3e0SSimon J. Gerraty 	GNodeList examine = LST_INIT;	/* Queue of targets to examine */
120006b9b3e0SSimon J. Gerraty 	Lst_AppendAll(&examine, targs);
12013955d011SMarcel Moolenaar 
12023955d011SMarcel Moolenaar 	/*
120306b9b3e0SSimon J. Gerraty 	 * Make an initial downward pass over the graph, marking nodes to
120406b9b3e0SSimon J. Gerraty 	 * be made as we go down.
120506b9b3e0SSimon J. Gerraty 	 *
120606b9b3e0SSimon J. Gerraty 	 * We call Suff_FindDeps to find where a node is and to get some
120706b9b3e0SSimon J. Gerraty 	 * children for it if it has none and also has no commands. If the
120806b9b3e0SSimon J. Gerraty 	 * node is a leaf, we stick it on the toBeMade queue to be looked
120906b9b3e0SSimon J. Gerraty 	 * at in a minute, otherwise we add its children to our queue and
121006b9b3e0SSimon J. Gerraty 	 * go on about our business.
12113955d011SMarcel Moolenaar 	 */
121206b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&examine)) {
121306b9b3e0SSimon J. Gerraty 		GNode *gn = Lst_Dequeue(&examine);
12143955d011SMarcel Moolenaar 
12153955d011SMarcel Moolenaar 		if (gn->flags & REMAKE)
12163955d011SMarcel Moolenaar 			/* We've looked at this one already */
12173955d011SMarcel Moolenaar 			continue;
12183955d011SMarcel Moolenaar 		gn->flags |= REMAKE;
1219956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, "Make_ExpandUse: examine %s%s\n",
12203955d011SMarcel Moolenaar 		    gn->name, gn->cohort_num);
12213955d011SMarcel Moolenaar 
12222c3632d1SSimon J. Gerraty 		if (gn->type & OP_DOUBLEDEP)
122306b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&examine, &gn->cohorts);
12243955d011SMarcel Moolenaar 
12253955d011SMarcel Moolenaar 		/*
122606b9b3e0SSimon J. Gerraty 		 * Apply any .USE rules before looking for implicit
122706b9b3e0SSimon J. Gerraty 		 * dependencies to make sure everything has commands that
122806b9b3e0SSimon J. Gerraty 		 * should.
122906b9b3e0SSimon J. Gerraty 		 *
12303955d011SMarcel Moolenaar 		 * Make sure that the TARGET is set, so that we can make
12313955d011SMarcel Moolenaar 		 * expansions.
12323955d011SMarcel Moolenaar 		 */
12333955d011SMarcel Moolenaar 		if (gn->type & OP_ARCHV) {
1234e2eeea75SSimon J. Gerraty 			char *eoa = strchr(gn->name, '(');
1235e2eeea75SSimon J. Gerraty 			char *eon = strchr(gn->name, ')');
12363955d011SMarcel Moolenaar 			if (eoa == NULL || eon == NULL)
12373955d011SMarcel Moolenaar 				continue;
12383955d011SMarcel Moolenaar 			*eoa = '\0';
12393955d011SMarcel Moolenaar 			*eon = '\0';
1240*dba7b0efSSimon J. Gerraty 			Var_Set(gn, MEMBER, eoa + 1);
1241*dba7b0efSSimon J. Gerraty 			Var_Set(gn, ARCHIVE, gn->name);
12423955d011SMarcel Moolenaar 			*eoa = '(';
12433955d011SMarcel Moolenaar 			*eon = ')';
12443955d011SMarcel Moolenaar 		}
12453955d011SMarcel Moolenaar 
1246e2eeea75SSimon J. Gerraty 		Dir_UpdateMTime(gn, FALSE);
1247*dba7b0efSSimon J. Gerraty 		Var_Set(gn, TARGET, GNode_Path(gn));
1248956e45f6SSimon J. Gerraty 		UnmarkChildren(gn);
1249956e45f6SSimon J. Gerraty 		HandleUseNodes(gn);
12503955d011SMarcel Moolenaar 
1251e2eeea75SSimon J. Gerraty 		if (!(gn->type & OP_MADE))
12523955d011SMarcel Moolenaar 			Suff_FindDeps(gn);
12533955d011SMarcel Moolenaar 		else {
1254e2eeea75SSimon J. Gerraty 			PretendAllChildrenAreMade(gn);
125506b9b3e0SSimon J. Gerraty 			if (gn->unmade != 0) {
125606b9b3e0SSimon J. Gerraty 				printf(
125706b9b3e0SSimon J. Gerraty 				    "Warning: "
125806b9b3e0SSimon J. Gerraty 				    "%s%s still has %d unmade children\n",
12593955d011SMarcel Moolenaar 				    gn->name, gn->cohort_num, gn->unmade);
12603955d011SMarcel Moolenaar 			}
12613955d011SMarcel Moolenaar 		}
12623955d011SMarcel Moolenaar 
126306b9b3e0SSimon J. Gerraty 		if (gn->unmade != 0)
126406b9b3e0SSimon J. Gerraty 			ExamineLater(&examine, &gn->children);
126506b9b3e0SSimon J. Gerraty 	}
126606b9b3e0SSimon J. Gerraty 
126706b9b3e0SSimon J. Gerraty 	Lst_Done(&examine);
12683955d011SMarcel Moolenaar }
12693955d011SMarcel Moolenaar 
1270956e45f6SSimon J. Gerraty /* Make the .WAIT node depend on the previous children */
1271956e45f6SSimon J. Gerraty static void
1272956e45f6SSimon J. Gerraty add_wait_dependency(GNodeListNode *owln, GNode *wn)
12733955d011SMarcel Moolenaar {
1274956e45f6SSimon J. Gerraty 	GNodeListNode *cln;
1275956e45f6SSimon J. Gerraty 	GNode *cn;
12763955d011SMarcel Moolenaar 
1277956e45f6SSimon J. Gerraty 	for (cln = owln; (cn = cln->datum) != wn; cln = cln->next) {
1278956e45f6SSimon J. Gerraty 		DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n",
12793955d011SMarcel Moolenaar 		    cn->name, cn->cohort_num, wn->name);
12803955d011SMarcel Moolenaar 
1281956e45f6SSimon J. Gerraty 		/* XXX: This pattern should be factored out, it repeats often */
128206b9b3e0SSimon J. Gerraty 		Lst_Append(&wn->children, cn);
12833955d011SMarcel Moolenaar 		wn->unmade++;
128406b9b3e0SSimon J. Gerraty 		Lst_Append(&cn->parents, wn);
1285956e45f6SSimon J. Gerraty 	}
12863955d011SMarcel Moolenaar }
12873955d011SMarcel Moolenaar 
1288956e45f6SSimon J. Gerraty /* Convert .WAIT nodes into dependencies. */
12893955d011SMarcel Moolenaar static void
1290956e45f6SSimon J. Gerraty Make_ProcessWait(GNodeList *targs)
12913955d011SMarcel Moolenaar {
12923955d011SMarcel Moolenaar 	GNode *pgn;		/* 'parent' node we are examining */
1293956e45f6SSimon J. Gerraty 	GNodeListNode *owln;	/* Previous .WAIT node */
129406b9b3e0SSimon J. Gerraty 	GNodeList examine;	/* List of targets to examine */
12953955d011SMarcel Moolenaar 
12963955d011SMarcel Moolenaar 	/*
12973955d011SMarcel Moolenaar 	 * We need all the nodes to have a common parent in order for the
12983955d011SMarcel Moolenaar 	 * .WAIT and .ORDER scheduling to work.
12993955d011SMarcel Moolenaar 	 * Perhaps this should be done earlier...
13003955d011SMarcel Moolenaar 	 */
13013955d011SMarcel Moolenaar 
1302e2eeea75SSimon J. Gerraty 	pgn = GNode_New(".MAIN");
13033955d011SMarcel Moolenaar 	pgn->flags = REMAKE;
13043955d011SMarcel Moolenaar 	pgn->type = OP_PHONY | OP_DEPENDS;
13053955d011SMarcel Moolenaar 	/* Get it displayed in the diag dumps */
13062c3632d1SSimon J. Gerraty 	Lst_Prepend(Targ_List(), pgn);
13073955d011SMarcel Moolenaar 
1308956e45f6SSimon J. Gerraty 	{
1309956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
1310956e45f6SSimon J. Gerraty 		for (ln = targs->first; ln != NULL; ln = ln->next) {
1311956e45f6SSimon J. Gerraty 			GNode *cgn = ln->datum;
1312956e45f6SSimon J. Gerraty 
131306b9b3e0SSimon J. Gerraty 			Lst_Append(&pgn->children, cgn);
131406b9b3e0SSimon J. Gerraty 			Lst_Append(&cgn->parents, pgn);
1315956e45f6SSimon J. Gerraty 			pgn->unmade++;
1316956e45f6SSimon J. Gerraty 		}
1317956e45f6SSimon J. Gerraty 	}
13183955d011SMarcel Moolenaar 
13193955d011SMarcel Moolenaar 	/* Start building with the 'dummy' .MAIN' node */
13203955d011SMarcel Moolenaar 	MakeBuildChild(pgn, NULL);
13213955d011SMarcel Moolenaar 
132206b9b3e0SSimon J. Gerraty 	Lst_Init(&examine);
132306b9b3e0SSimon J. Gerraty 	Lst_Append(&examine, pgn);
13243955d011SMarcel Moolenaar 
132506b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&examine)) {
1326956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
1327956e45f6SSimon J. Gerraty 
132806b9b3e0SSimon J. Gerraty 		pgn = Lst_Dequeue(&examine);
13293955d011SMarcel Moolenaar 
13303955d011SMarcel Moolenaar 		/* We only want to process each child-list once */
13313955d011SMarcel Moolenaar 		if (pgn->flags & DONE_WAIT)
13323955d011SMarcel Moolenaar 			continue;
13333955d011SMarcel Moolenaar 		pgn->flags |= DONE_WAIT;
1334956e45f6SSimon J. Gerraty 		DEBUG1(MAKE, "Make_ProcessWait: examine %s\n", pgn->name);
13353955d011SMarcel Moolenaar 
13362c3632d1SSimon J. Gerraty 		if (pgn->type & OP_DOUBLEDEP)
133706b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&examine, &pgn->cohorts);
13383955d011SMarcel Moolenaar 
133906b9b3e0SSimon J. Gerraty 		owln = pgn->children.first;
134006b9b3e0SSimon J. Gerraty 		for (ln = pgn->children.first; ln != NULL; ln = ln->next) {
1341956e45f6SSimon J. Gerraty 			GNode *cgn = ln->datum;
13423955d011SMarcel Moolenaar 			if (cgn->type & OP_WAIT) {
1343956e45f6SSimon J. Gerraty 				add_wait_dependency(owln, cgn);
13443955d011SMarcel Moolenaar 				owln = ln;
13453955d011SMarcel Moolenaar 			} else {
134606b9b3e0SSimon J. Gerraty 				Lst_Append(&examine, cgn);
13473955d011SMarcel Moolenaar 			}
13483955d011SMarcel Moolenaar 		}
13493955d011SMarcel Moolenaar 	}
13503955d011SMarcel Moolenaar 
135106b9b3e0SSimon J. Gerraty 	Lst_Done(&examine);
13523955d011SMarcel Moolenaar }
13533955d011SMarcel Moolenaar 
135406b9b3e0SSimon J. Gerraty /*
135506b9b3e0SSimon J. Gerraty  * Initialize the nodes to remake and the list of nodes which are ready to
135606b9b3e0SSimon J. Gerraty  * be made by doing a breadth-first traversal of the graph starting from the
135706b9b3e0SSimon J. Gerraty  * nodes in the given list. Once this traversal is finished, all the 'leaves'
135806b9b3e0SSimon J. Gerraty  * of the graph are in the toBeMade queue.
135906b9b3e0SSimon J. Gerraty  *
136006b9b3e0SSimon J. Gerraty  * Using this queue and the Job module, work back up the graph, calling on
136106b9b3e0SSimon J. Gerraty  * MakeStartJobs to keep the job table as full as possible.
13623955d011SMarcel Moolenaar  *
13633955d011SMarcel Moolenaar  * Input:
13643955d011SMarcel Moolenaar  *	targs		the initial list of targets
13653955d011SMarcel Moolenaar  *
13663955d011SMarcel Moolenaar  * Results:
13673955d011SMarcel Moolenaar  *	TRUE if work was done. FALSE otherwise.
13683955d011SMarcel Moolenaar  *
13693955d011SMarcel Moolenaar  * Side Effects:
13703955d011SMarcel Moolenaar  *	The make field of all nodes involved in the creation of the given
13713955d011SMarcel Moolenaar  *	targets is set to 1. The toBeMade list is set to contain all the
13723955d011SMarcel Moolenaar  *	'leaves' of these subgraphs.
13733955d011SMarcel Moolenaar  */
13743955d011SMarcel Moolenaar Boolean
1375956e45f6SSimon J. Gerraty Make_Run(GNodeList *targs)
13763955d011SMarcel Moolenaar {
13773955d011SMarcel Moolenaar 	int errors;		/* Number of errors the Job module reports */
13783955d011SMarcel Moolenaar 
13793955d011SMarcel Moolenaar 	/* Start trying to make the current targets... */
138006b9b3e0SSimon J. Gerraty 	Lst_Init(&toBeMade);
13813955d011SMarcel Moolenaar 
13823955d011SMarcel Moolenaar 	Make_ExpandUse(targs);
13833955d011SMarcel Moolenaar 	Make_ProcessWait(targs);
13843955d011SMarcel Moolenaar 
13853955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
1386956e45f6SSimon J. Gerraty 		debug_printf("#***# full graph\n");
13873955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
13883955d011SMarcel Moolenaar 	}
13893955d011SMarcel Moolenaar 
1390956e45f6SSimon J. Gerraty 	if (opts.queryFlag) {
13913955d011SMarcel Moolenaar 		/*
139206b9b3e0SSimon J. Gerraty 		 * We wouldn't do any work unless we could start some jobs
139306b9b3e0SSimon J. Gerraty 		 * in the next loop... (we won't actually start any, of
139406b9b3e0SSimon J. Gerraty 		 * course, this is just to see if any of the targets was out
139506b9b3e0SSimon J. Gerraty 		 * of date)
13963955d011SMarcel Moolenaar 		 */
13973841c287SSimon J. Gerraty 		return MakeStartJobs();
13983955d011SMarcel Moolenaar 	}
13993955d011SMarcel Moolenaar 	/*
14003955d011SMarcel Moolenaar 	 * Initialization. At the moment, no jobs are running and until some
14013955d011SMarcel Moolenaar 	 * get started, nothing will happen since the remaining upward
14023955d011SMarcel Moolenaar 	 * traversal of the graph is performed by the routines in job.c upon
14033955d011SMarcel Moolenaar 	 * the finishing of a job. So we fill the Job table as much as we can
14043955d011SMarcel Moolenaar 	 * before going into our loop.
14053955d011SMarcel Moolenaar 	 */
14063955d011SMarcel Moolenaar 	(void)MakeStartJobs();
14073955d011SMarcel Moolenaar 
14083955d011SMarcel Moolenaar 	/*
14093955d011SMarcel Moolenaar 	 * Main Loop: The idea here is that the ending of jobs will take
141006b9b3e0SSimon J. Gerraty 	 * care of the maintenance of data structures and the waiting for
141106b9b3e0SSimon J. Gerraty 	 * output will cause us to be idle most of the time while our
141206b9b3e0SSimon J. Gerraty 	 * children run as much as possible. Because the job table is kept
141306b9b3e0SSimon J. Gerraty 	 * as full as possible, the only time when it will be empty is when
141406b9b3e0SSimon J. Gerraty 	 * all the jobs which need running have been run, so that is the end
141506b9b3e0SSimon J. Gerraty 	 * condition of this loop. Note that the Job module will exit if
141606b9b3e0SSimon J. Gerraty 	 * there were any errors unless the keepgoing flag was given.
14173955d011SMarcel Moolenaar 	 */
141806b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&toBeMade) || jobTokensRunning > 0) {
14193955d011SMarcel Moolenaar 		Job_CatchOutput();
14203955d011SMarcel Moolenaar 		(void)MakeStartJobs();
14213955d011SMarcel Moolenaar 	}
14223955d011SMarcel Moolenaar 
14233955d011SMarcel Moolenaar 	errors = Job_Finish();
14243955d011SMarcel Moolenaar 
14253955d011SMarcel Moolenaar 	/*
14263955d011SMarcel Moolenaar 	 * Print the final status of each target. E.g. if it wasn't made
14273955d011SMarcel Moolenaar 	 * because some inferior reported an error.
14283955d011SMarcel Moolenaar 	 */
1429956e45f6SSimon J. Gerraty 	DEBUG1(MAKE, "done: errors %d\n", errors);
14303955d011SMarcel Moolenaar 	if (errors == 0) {
1431956e45f6SSimon J. Gerraty 		MakePrintStatusList(targs, &errors);
14323955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
1433956e45f6SSimon J. Gerraty 			debug_printf("done: errors %d\n", errors);
1434e2eeea75SSimon J. Gerraty 			if (errors > 0)
14353955d011SMarcel Moolenaar 				Targ_PrintGraph(4);
14363955d011SMarcel Moolenaar 		}
14373955d011SMarcel Moolenaar 	}
1438e2eeea75SSimon J. Gerraty 	return errors > 0;
14393955d011SMarcel Moolenaar }
1440