xref: /freebsd/contrib/bmake/make.c (revision e2eeea75eb8b6dd50c1298067a0655880d186734)
1*e2eeea75SSimon J. Gerraty /*	$NetBSD: make.c,v 1.209 2020/11/16 22:31:42 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 
71*e2eeea75SSimon J. Gerraty /* Examination of targets and their suitability for creation.
723955d011SMarcel Moolenaar  *
733955d011SMarcel Moolenaar  * Interface:
74*e2eeea75SSimon J. Gerraty  *	Make_Run	Initialize things for the module. Returns TRUE if
75*e2eeea75SSimon J. Gerraty  *			work was (or would have been) done.
763955d011SMarcel Moolenaar  *
77*e2eeea75SSimon J. Gerraty  *	Make_Update	After a target is made, update all its parents.
78*e2eeea75SSimon J. Gerraty  *			Perform various bookkeeping chores like the updating
79956e45f6SSimon J. Gerraty  *			of the youngestChild field of the parent, filling
80*e2eeea75SSimon J. Gerraty  *			of the IMPSRC context variable, etc. Place the parent
81*e2eeea75SSimon J. Gerraty  *			on the toBeMade queue if it should be.
823955d011SMarcel Moolenaar  *
83*e2eeea75SSimon J. Gerraty  *	GNode_UpdateYoungestChild
84*e2eeea75SSimon J. Gerraty  *			Update the node's youngestChild field based on the
85*e2eeea75SSimon J. Gerraty  *			child's modification time.
863955d011SMarcel Moolenaar  *
873955d011SMarcel Moolenaar  *	Make_DoAllVar	Set up the various local variables for a
883955d011SMarcel Moolenaar  *			target, including the .ALLSRC variable, making
893955d011SMarcel Moolenaar  *			sure that any variable that needs to exist
903955d011SMarcel Moolenaar  *			at the very least has the empty value.
913955d011SMarcel Moolenaar  *
92*e2eeea75SSimon J. Gerraty  *	GNode_IsOODate	Determine if a target is out-of-date.
933955d011SMarcel Moolenaar  *
943955d011SMarcel Moolenaar  *	Make_HandleUse	See if a child is a .USE node for a parent
953955d011SMarcel Moolenaar  *			and perform the .USE actions if so.
963955d011SMarcel Moolenaar  *
973955d011SMarcel Moolenaar  *	Make_ExpandUse	Expand .USE nodes
983955d011SMarcel Moolenaar  */
993955d011SMarcel Moolenaar 
1003955d011SMarcel Moolenaar #include "make.h"
1013955d011SMarcel Moolenaar #include "dir.h"
1023955d011SMarcel Moolenaar #include "job.h"
1033955d011SMarcel Moolenaar 
104956e45f6SSimon J. Gerraty /*	"@(#)make.c	8.1 (Berkeley) 6/6/93"	*/
105*e2eeea75SSimon J. Gerraty MAKE_RCSID("$NetBSD: make.c,v 1.209 2020/11/16 22:31:42 rillig Exp $");
1063955d011SMarcel Moolenaar 
107956e45f6SSimon J. Gerraty /* Sequence # to detect recursion. */
108*e2eeea75SSimon J. Gerraty static unsigned int checked_seqno = 1;
109956e45f6SSimon J. Gerraty 
110956e45f6SSimon J. Gerraty /* The current fringe of the graph.
111956e45f6SSimon J. Gerraty  * These are nodes which await examination by MakeOODate.
112956e45f6SSimon J. Gerraty  * It is added to by Make_Update and subtracted from by MakeStartJobs */
113956e45f6SSimon J. Gerraty static GNodeList *toBeMade;
114956e45f6SSimon J. Gerraty 
1153955d011SMarcel Moolenaar static int MakeBuildParent(void *, void *);
1163955d011SMarcel Moolenaar 
117956e45f6SSimon J. Gerraty void
118956e45f6SSimon J. Gerraty debug_printf(const char *fmt, ...)
119956e45f6SSimon J. Gerraty {
120956e45f6SSimon J. Gerraty     va_list args;
121956e45f6SSimon J. Gerraty 
122956e45f6SSimon J. Gerraty     va_start(args, fmt);
123956e45f6SSimon J. Gerraty     vfprintf(opts.debug_file, fmt, args);
124956e45f6SSimon J. Gerraty     va_end(args);
125956e45f6SSimon J. Gerraty }
126956e45f6SSimon J. Gerraty 
1273955d011SMarcel Moolenaar MAKE_ATTR_DEAD static void
1283955d011SMarcel Moolenaar make_abort(GNode *gn, int line)
1293955d011SMarcel Moolenaar {
130956e45f6SSimon J. Gerraty     debug_printf("make_abort from line %d\n", line);
131956e45f6SSimon J. Gerraty     Targ_PrintNode(gn, 2);
132956e45f6SSimon J. Gerraty     Targ_PrintNodes(toBeMade, 2);
1333955d011SMarcel Moolenaar     Targ_PrintGraph(3);
1343955d011SMarcel Moolenaar     abort();
1353955d011SMarcel Moolenaar }
1363955d011SMarcel Moolenaar 
1372c3632d1SSimon J. Gerraty ENUM_VALUE_RTTI_8(GNodeMade,
1382c3632d1SSimon J. Gerraty 		  UNMADE, DEFERRED, REQUESTED, BEINGMADE,
1392c3632d1SSimon J. Gerraty 		  MADE, UPTODATE, ERROR, ABORTED);
1402c3632d1SSimon J. Gerraty 
1412c3632d1SSimon J. Gerraty ENUM_FLAGS_RTTI_31(GNodeType,
1422c3632d1SSimon J. Gerraty 		   OP_DEPENDS, OP_FORCE, OP_DOUBLEDEP,
1432c3632d1SSimon J. Gerraty 		   /* OP_OPMASK is omitted since it combines other flags */
1442c3632d1SSimon J. Gerraty 		   OP_OPTIONAL, OP_USE, OP_EXEC, OP_IGNORE,
1452c3632d1SSimon J. Gerraty 		   OP_PRECIOUS, OP_SILENT, OP_MAKE, OP_JOIN,
1462c3632d1SSimon J. Gerraty 		   OP_MADE, OP_SPECIAL, OP_USEBEFORE, OP_INVISIBLE,
1472c3632d1SSimon J. Gerraty 		   OP_NOTMAIN, OP_PHONY, OP_NOPATH, OP_WAIT,
1482c3632d1SSimon J. Gerraty 		   OP_NOMETA, OP_META, OP_NOMETA_CMP, OP_SUBMAKE,
1492c3632d1SSimon J. Gerraty 		   OP_TRANSFORM, OP_MEMBER, OP_LIB, OP_ARCHV,
1502c3632d1SSimon J. Gerraty 		   OP_HAS_COMMANDS, OP_SAVE_CMDS, OP_DEPS_FOUND, OP_MARK);
1512c3632d1SSimon J. Gerraty 
1522c3632d1SSimon J. Gerraty ENUM_FLAGS_RTTI_10(GNodeFlags,
1532c3632d1SSimon J. Gerraty 		   REMAKE, CHILDMADE, FORCE, DONE_WAIT,
1542c3632d1SSimon J. Gerraty 		   DONE_ORDER, FROM_DEPEND, DONE_ALLSRC, CYCLE,
1552c3632d1SSimon J. Gerraty 		   DONECYCLE, INTERNAL);
1562c3632d1SSimon J. Gerraty 
1572c3632d1SSimon J. Gerraty void
1582c3632d1SSimon J. Gerraty GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn,
1592c3632d1SSimon J. Gerraty 		    const char *suffix)
1602c3632d1SSimon J. Gerraty {
1612c3632d1SSimon J. Gerraty     char type_buf[GNodeType_ToStringSize];
1622c3632d1SSimon J. Gerraty     char flags_buf[GNodeFlags_ToStringSize];
1632c3632d1SSimon J. Gerraty 
1642c3632d1SSimon J. Gerraty     fprintf(f, "%smade %s, type %s, flags %s%s",
1652c3632d1SSimon J. Gerraty 	    prefix,
1662c3632d1SSimon J. Gerraty 	    Enum_ValueToString(gn->made, GNodeMade_ToStringSpecs),
1672c3632d1SSimon J. Gerraty 	    Enum_FlagsToString(type_buf, sizeof type_buf,
1682c3632d1SSimon J. Gerraty 			       gn->type, GNodeType_ToStringSpecs),
1692c3632d1SSimon J. Gerraty 	    Enum_FlagsToString(flags_buf, sizeof flags_buf,
1702c3632d1SSimon J. Gerraty 			       gn->flags, GNodeFlags_ToStringSpecs),
1712c3632d1SSimon J. Gerraty 	    suffix);
1722c3632d1SSimon J. Gerraty }
1732c3632d1SSimon J. Gerraty 
174956e45f6SSimon J. Gerraty Boolean
175956e45f6SSimon J. Gerraty GNode_ShouldExecute(GNode *gn)
176956e45f6SSimon J. Gerraty {
177956e45f6SSimon J. Gerraty     return !((gn->type & OP_MAKE) ? opts.noRecursiveExecute : opts.noExecute);
178956e45f6SSimon J. Gerraty }
179956e45f6SSimon J. Gerraty 
180956e45f6SSimon J. Gerraty /* Update the youngest child of the node, according to the given child. */
181956e45f6SSimon J. Gerraty void
182*e2eeea75SSimon J. Gerraty GNode_UpdateYoungestChild(GNode *gn, GNode *cgn)
1833955d011SMarcel Moolenaar {
184*e2eeea75SSimon J. Gerraty     if (gn->youngestChild == NULL || cgn->mtime > gn->youngestChild->mtime)
185*e2eeea75SSimon J. Gerraty 	gn->youngestChild = cgn;
1863955d011SMarcel Moolenaar }
187*e2eeea75SSimon J. Gerraty 
188*e2eeea75SSimon J. Gerraty static Boolean
189*e2eeea75SSimon J. Gerraty IsOODateRegular(GNode *gn)
190*e2eeea75SSimon J. Gerraty {
191*e2eeea75SSimon J. Gerraty     /* These rules are inherited from the original Make. */
192*e2eeea75SSimon J. Gerraty 
193*e2eeea75SSimon J. Gerraty     if (gn->youngestChild != NULL) {
194*e2eeea75SSimon J. Gerraty 	if (gn->mtime < gn->youngestChild->mtime) {
195*e2eeea75SSimon J. Gerraty 	    DEBUG1(MAKE, "modified before source \"%s\"...",
196*e2eeea75SSimon J. Gerraty 		   GNode_Path(gn->youngestChild));
197*e2eeea75SSimon J. Gerraty 	    return TRUE;
198*e2eeea75SSimon J. Gerraty 	}
199*e2eeea75SSimon J. Gerraty 	return FALSE;
200*e2eeea75SSimon J. Gerraty     }
201*e2eeea75SSimon J. Gerraty 
202*e2eeea75SSimon J. Gerraty     if (gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) {
203*e2eeea75SSimon J. Gerraty 	DEBUG0(MAKE, "non-existent and no sources...");
204*e2eeea75SSimon J. Gerraty 	return TRUE;
205*e2eeea75SSimon J. Gerraty     }
206*e2eeea75SSimon J. Gerraty 
207*e2eeea75SSimon J. Gerraty     if (gn->type & OP_DOUBLEDEP) {
208*e2eeea75SSimon J. Gerraty 	DEBUG0(MAKE, ":: operator and no sources...");
209*e2eeea75SSimon J. Gerraty 	return TRUE;
210*e2eeea75SSimon J. Gerraty     }
211*e2eeea75SSimon J. Gerraty 
212*e2eeea75SSimon J. Gerraty     return FALSE;
2133955d011SMarcel Moolenaar }
2143955d011SMarcel Moolenaar 
215956e45f6SSimon 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
227*e2eeea75SSimon 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      */
235*e2eeea75SSimon J. Gerraty     if (!(gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
236*e2eeea75SSimon J. Gerraty 	Dir_UpdateMTime(gn, TRUE);
2373955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
238*e2eeea75SSimon J. Gerraty 	    if (gn->mtime != 0)
239956e45f6SSimon J. Gerraty 		debug_printf("modified %s...", Targ_FmtTime(gn->mtime));
240*e2eeea75SSimon J. Gerraty 	    else
241956e45f6SSimon J. Gerraty 		debug_printf("non-existent...");
2423955d011SMarcel Moolenaar 	}
2433955d011SMarcel Moolenaar     }
2443955d011SMarcel Moolenaar 
2453955d011SMarcel Moolenaar     /*
2463955d011SMarcel Moolenaar      * A target is remade in one of the following circumstances:
247956e45f6SSimon J. Gerraty      *	its modification time is smaller than that of its youngest child and
248956e45f6SSimon J. Gerraty      *	    it would actually be run (has commands or is not GNode_IsTarget)
2493955d011SMarcel Moolenaar      *	it's the object of a force operator
2503955d011SMarcel Moolenaar      *	it has no children, was on the lhs of an operator and doesn't exist
2513955d011SMarcel Moolenaar      *	    already.
2523955d011SMarcel Moolenaar      *
2533955d011SMarcel Moolenaar      * Libraries are only considered out-of-date if the archive module says
2543955d011SMarcel Moolenaar      * they are.
2553955d011SMarcel Moolenaar      *
2563955d011SMarcel Moolenaar      * These weird rules are brought to you by Backward-Compatibility and
2573955d011SMarcel Moolenaar      * the strange people who wrote 'Make'.
2583955d011SMarcel Moolenaar      */
2593955d011SMarcel Moolenaar     if (gn->type & (OP_USE|OP_USEBEFORE)) {
2603955d011SMarcel Moolenaar 	/*
2613955d011SMarcel Moolenaar 	 * If the node is a USE node it is *never* out of date
2623955d011SMarcel Moolenaar 	 * no matter *what*.
2633955d011SMarcel Moolenaar 	 */
264956e45f6SSimon J. Gerraty 	DEBUG0(MAKE, ".USE node...");
2653955d011SMarcel Moolenaar 	oodate = FALSE;
266*e2eeea75SSimon J. Gerraty     } else if ((gn->type & OP_LIB) && (gn->mtime == 0 || Arch_IsLib(gn))) {
267956e45f6SSimon J. Gerraty 	DEBUG0(MAKE, "library...");
2683955d011SMarcel Moolenaar 
2693955d011SMarcel Moolenaar 	/*
2703955d011SMarcel Moolenaar 	 * always out of date if no children and :: target
2713955d011SMarcel Moolenaar 	 * or non-existent.
2723955d011SMarcel Moolenaar 	 */
2733955d011SMarcel Moolenaar 	oodate = (gn->mtime == 0 || Arch_LibOODate(gn) ||
274956e45f6SSimon J. Gerraty 		  (gn->youngestChild == NULL && (gn->type & OP_DOUBLEDEP)));
2753955d011SMarcel Moolenaar     } else if (gn->type & OP_JOIN) {
2763955d011SMarcel Moolenaar 	/*
2773955d011SMarcel Moolenaar 	 * A target with the .JOIN attribute is only considered
2783955d011SMarcel Moolenaar 	 * out-of-date if any of its children was out-of-date.
2793955d011SMarcel Moolenaar 	 */
280956e45f6SSimon J. Gerraty 	DEBUG0(MAKE, ".JOIN node...");
281956e45f6SSimon J. Gerraty 	DEBUG1(MAKE, "source %smade...", gn->flags & CHILDMADE ? "" : "not ");
282*e2eeea75SSimon J. Gerraty 	oodate = (gn->flags & CHILDMADE) != 0;
2833955d011SMarcel Moolenaar     } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
2843955d011SMarcel Moolenaar 	/*
2853955d011SMarcel Moolenaar 	 * A node which is the object of the force (!) operator or which has
2863955d011SMarcel Moolenaar 	 * the .EXEC attribute is always considered out-of-date.
2873955d011SMarcel Moolenaar 	 */
2883955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
2893955d011SMarcel Moolenaar 	    if (gn->type & OP_FORCE) {
290956e45f6SSimon J. Gerraty 		debug_printf("! operator...");
2913955d011SMarcel Moolenaar 	    } else if (gn->type & OP_PHONY) {
292956e45f6SSimon J. Gerraty 		debug_printf(".PHONY node...");
2933955d011SMarcel Moolenaar 	    } else {
294956e45f6SSimon J. Gerraty 		debug_printf(".EXEC node...");
2953955d011SMarcel Moolenaar 	    }
2963955d011SMarcel Moolenaar 	}
2973955d011SMarcel Moolenaar 	oodate = TRUE;
298*e2eeea75SSimon J. Gerraty     } else if (IsOODateRegular(gn)) {
2993955d011SMarcel Moolenaar 	oodate = TRUE;
3003955d011SMarcel Moolenaar     } else {
3013955d011SMarcel Moolenaar 	/*
3023955d011SMarcel Moolenaar 	 * When a non-existing child with no sources
3033955d011SMarcel Moolenaar 	 * (such as a typically used FORCE source) has been made and
3043955d011SMarcel Moolenaar 	 * the target of the child (usually a directory) has the same
3053955d011SMarcel Moolenaar 	 * timestamp as the timestamp just given to the non-existing child
3063955d011SMarcel Moolenaar 	 * after it was considered made.
3073955d011SMarcel Moolenaar 	 */
3083955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
3093955d011SMarcel Moolenaar 	    if (gn->flags & FORCE)
310956e45f6SSimon J. Gerraty 		debug_printf("non existing child...");
3113955d011SMarcel Moolenaar 	}
312*e2eeea75SSimon J. Gerraty 	oodate = (gn->flags & FORCE) != 0;
3133955d011SMarcel Moolenaar     }
3143955d011SMarcel Moolenaar 
3153955d011SMarcel Moolenaar #ifdef USE_META
3163955d011SMarcel Moolenaar     if (useMeta) {
3173955d011SMarcel Moolenaar 	oodate = meta_oodate(gn, oodate);
3183955d011SMarcel Moolenaar     }
3193955d011SMarcel Moolenaar #endif
3203955d011SMarcel Moolenaar 
3213955d011SMarcel Moolenaar     /*
3223955d011SMarcel Moolenaar      * If the target isn't out-of-date, the parents need to know its
3233955d011SMarcel Moolenaar      * modification time. Note that targets that appear to be out-of-date
324956e45f6SSimon J. Gerraty      * but aren't, because they have no commands and are GNode_IsTarget,
3253955d011SMarcel Moolenaar      * have their mtime stay below their children's mtime to keep parents from
3263955d011SMarcel Moolenaar      * thinking they're out-of-date.
3273955d011SMarcel Moolenaar      */
3283955d011SMarcel Moolenaar     if (!oodate) {
329956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
330956e45f6SSimon J. Gerraty 	for (ln = gn->parents->first; ln != NULL; ln = ln->next)
331*e2eeea75SSimon J. Gerraty 	    GNode_UpdateYoungestChild(ln->datum, gn);
3323955d011SMarcel Moolenaar     }
3333955d011SMarcel Moolenaar 
3343841c287SSimon J. Gerraty     return oodate;
3353955d011SMarcel Moolenaar }
3362c3632d1SSimon J. Gerraty 
337*e2eeea75SSimon J. Gerraty static void
338*e2eeea75SSimon J. Gerraty PretendAllChildrenAreMade(GNode *pgn)
3393955d011SMarcel Moolenaar {
340*e2eeea75SSimon J. Gerraty     GNodeListNode *ln;
3413955d011SMarcel Moolenaar 
342*e2eeea75SSimon J. Gerraty     for (ln = pgn->children->first; ln != NULL; ln = ln->next) {
343*e2eeea75SSimon J. Gerraty 	GNode *cgn = ln->datum;
3442c3632d1SSimon J. Gerraty 
345*e2eeea75SSimon J. Gerraty 	Dir_UpdateMTime(cgn, FALSE);	/* cgn->path may get updated as well */
346*e2eeea75SSimon J. Gerraty 	GNode_UpdateYoungestChild(pgn, cgn);
3473955d011SMarcel Moolenaar 	pgn->unmade--;
348*e2eeea75SSimon J. Gerraty     }
3493955d011SMarcel Moolenaar }
3502c3632d1SSimon J. Gerraty 
3512c3632d1SSimon J. Gerraty /* Called by Make_Run and SuffApplyTransform on the downward pass to handle
3522c3632d1SSimon J. Gerraty  * .USE and transformation nodes, by copying the child node's commands, type
3532c3632d1SSimon J. Gerraty  * flags and children to the parent node.
3543955d011SMarcel Moolenaar  *
3552c3632d1SSimon J. Gerraty  * A .USE node is much like an explicit transformation rule, except its
3562c3632d1SSimon J. Gerraty  * commands are always added to the target node, even if the target already
3572c3632d1SSimon J. Gerraty  * has commands.
3583955d011SMarcel Moolenaar  *
3593955d011SMarcel Moolenaar  * Input:
360956e45f6SSimon J. Gerraty  *	cgn		The source node, which is either a .USE/.USEBEFORE
361956e45f6SSimon J. Gerraty  *			node or a transformation node (OP_TRANSFORM).
362956e45f6SSimon J. Gerraty  *	pgn		The target node
3633955d011SMarcel Moolenaar  */
3643955d011SMarcel Moolenaar void
3653955d011SMarcel Moolenaar Make_HandleUse(GNode *cgn, GNode *pgn)
3663955d011SMarcel Moolenaar {
367956e45f6SSimon J. Gerraty     GNodeListNode *ln;	/* An element in the children list */
3683955d011SMarcel Moolenaar 
3693955d011SMarcel Moolenaar #ifdef DEBUG_SRC
370*e2eeea75SSimon J. Gerraty     if (!(cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM))) {
371956e45f6SSimon J. Gerraty 	debug_printf("Make_HandleUse: called for plain node %s\n", cgn->name);
372*e2eeea75SSimon J. Gerraty 	return;		/* XXX: debug mode should not affect control flow */
3733955d011SMarcel Moolenaar     }
3743955d011SMarcel Moolenaar #endif
3753955d011SMarcel Moolenaar 
3763955d011SMarcel Moolenaar     if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) {
3773955d011SMarcel Moolenaar 	    if (cgn->type & OP_USEBEFORE) {
3782c3632d1SSimon J. Gerraty 		/* .USEBEFORE */
3792c3632d1SSimon J. Gerraty 		Lst_PrependAll(pgn->commands, cgn->commands);
3803955d011SMarcel Moolenaar 	    } else {
3812c3632d1SSimon J. Gerraty 		/* .USE, or target has no commands */
3822c3632d1SSimon J. Gerraty 		Lst_AppendAll(pgn->commands, cgn->commands);
3833955d011SMarcel Moolenaar 	    }
3843955d011SMarcel Moolenaar     }
3853955d011SMarcel Moolenaar 
386956e45f6SSimon J. Gerraty     for (ln = cgn->children->first; ln != NULL; ln = ln->next) {
387956e45f6SSimon J. Gerraty 	GNode *gn = ln->datum;
3883955d011SMarcel Moolenaar 
3893955d011SMarcel Moolenaar 	/*
3903955d011SMarcel Moolenaar 	 * Expand variables in the .USE node's name
3913955d011SMarcel Moolenaar 	 * and save the unexpanded form.
3923955d011SMarcel Moolenaar 	 * We don't need to do this for commands.
3933955d011SMarcel Moolenaar 	 * They get expanded properly when we execute.
3943955d011SMarcel Moolenaar 	 */
3953955d011SMarcel Moolenaar 	if (gn->uname == NULL) {
3963955d011SMarcel Moolenaar 	    gn->uname = gn->name;
3973955d011SMarcel Moolenaar 	} else {
3983955d011SMarcel Moolenaar 	    free(gn->name);
3993955d011SMarcel Moolenaar 	}
400956e45f6SSimon J. Gerraty 	(void)Var_Subst(gn->uname, pgn, VARE_WANTRES, &gn->name);
401956e45f6SSimon J. Gerraty 	/* TODO: handle errors */
4022c3632d1SSimon J. Gerraty 	if (gn->uname && strcmp(gn->name, gn->uname) != 0) {
4033955d011SMarcel Moolenaar 	    /* See if we have a target for this node. */
404956e45f6SSimon J. Gerraty 	    GNode *tgn = Targ_FindNode(gn->name);
4053955d011SMarcel Moolenaar 	    if (tgn != NULL)
4063955d011SMarcel Moolenaar 		gn = tgn;
4073955d011SMarcel Moolenaar 	}
4083955d011SMarcel Moolenaar 
4092c3632d1SSimon J. Gerraty 	Lst_Append(pgn->children, gn);
4102c3632d1SSimon J. Gerraty 	Lst_Append(gn->parents, pgn);
411956e45f6SSimon J. Gerraty 	pgn->unmade++;
4123955d011SMarcel Moolenaar     }
4133955d011SMarcel Moolenaar 
4143955d011SMarcel Moolenaar     pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM);
4153955d011SMarcel Moolenaar }
4163955d011SMarcel Moolenaar 
417956e45f6SSimon J. Gerraty /* Used by Make_Run on the downward pass to handle .USE nodes. Should be
418956e45f6SSimon J. Gerraty  * called before the children are enqueued to be looked at by MakeAddChild.
419956e45f6SSimon J. Gerraty  *
420956e45f6SSimon J. Gerraty  * For a .USE child, the commands, type flags and children are copied to the
421956e45f6SSimon J. Gerraty  * parent node, and since the relation to the .USE node is then no longer
422956e45f6SSimon J. Gerraty  * needed, that relation is removed.
4233955d011SMarcel Moolenaar  *
4243955d011SMarcel Moolenaar  * Input:
425956e45f6SSimon J. Gerraty  *	cgn		the child, which may be a .USE node
426956e45f6SSimon J. Gerraty  *	pgn		the current parent
4273955d011SMarcel Moolenaar  */
428956e45f6SSimon J. Gerraty static void
429956e45f6SSimon J. Gerraty MakeHandleUse(GNode *cgn, GNode *pgn, GNodeListNode *ln)
4303955d011SMarcel Moolenaar {
431956e45f6SSimon J. Gerraty     Boolean unmarked;
4323955d011SMarcel Moolenaar 
433*e2eeea75SSimon J. Gerraty     unmarked = !(cgn->type & OP_MARK);
4343955d011SMarcel Moolenaar     cgn->type |= OP_MARK;
4353955d011SMarcel Moolenaar 
436*e2eeea75SSimon J. Gerraty     if (!(cgn->type & (OP_USE|OP_USEBEFORE)))
437956e45f6SSimon J. Gerraty 	return;
4383955d011SMarcel Moolenaar 
4393955d011SMarcel Moolenaar     if (unmarked)
4403955d011SMarcel Moolenaar 	Make_HandleUse(cgn, pgn);
4413955d011SMarcel Moolenaar 
4423955d011SMarcel Moolenaar     /*
4433955d011SMarcel Moolenaar      * This child node is now "made", so we decrement the count of
4443955d011SMarcel Moolenaar      * unmade children in the parent... We also remove the child
4453955d011SMarcel Moolenaar      * from the parent's list to accurately reflect the number of decent
4463955d011SMarcel Moolenaar      * children the parent has. This is used by Make_Run to decide
4473955d011SMarcel Moolenaar      * whether to queue the parent or examine its children...
4483955d011SMarcel Moolenaar      */
4493955d011SMarcel Moolenaar     Lst_Remove(pgn->children, ln);
4503955d011SMarcel Moolenaar     pgn->unmade--;
4513955d011SMarcel Moolenaar }
452956e45f6SSimon J. Gerraty 
453956e45f6SSimon J. Gerraty static void
454956e45f6SSimon J. Gerraty HandleUseNodes(GNode *gn)
455956e45f6SSimon J. Gerraty {
456956e45f6SSimon J. Gerraty     GNodeListNode *ln, *nln;
457956e45f6SSimon J. Gerraty     for (ln = gn->children->first; ln != NULL; ln = nln) {
458956e45f6SSimon J. Gerraty 	nln = ln->next;
459956e45f6SSimon J. Gerraty 	MakeHandleUse(ln->datum, gn, ln);
460956e45f6SSimon J. Gerraty     }
4613955d011SMarcel Moolenaar }
4623955d011SMarcel Moolenaar 
4633955d011SMarcel Moolenaar 
464956e45f6SSimon J. Gerraty /* Check the modification time of a gnode, and update it if necessary.
465956e45f6SSimon J. Gerraty  * Return 0 if the gnode does not exist, or its filesystem time if it does. */
4663955d011SMarcel Moolenaar time_t
4673955d011SMarcel Moolenaar Make_Recheck(GNode *gn)
4683955d011SMarcel Moolenaar {
469*e2eeea75SSimon J. Gerraty     time_t mtime;
470*e2eeea75SSimon J. Gerraty 
471*e2eeea75SSimon J. Gerraty     Dir_UpdateMTime(gn, TRUE);
472*e2eeea75SSimon J. Gerraty     mtime = gn->mtime;
4733955d011SMarcel Moolenaar 
4743955d011SMarcel Moolenaar #ifndef RECHECK
4753955d011SMarcel Moolenaar     /*
4763955d011SMarcel Moolenaar      * We can't re-stat the thing, but we can at least take care of rules
4773955d011SMarcel Moolenaar      * where a target depends on a source that actually creates the
4783955d011SMarcel Moolenaar      * target, but only if it has changed, e.g.
4793955d011SMarcel Moolenaar      *
4803955d011SMarcel Moolenaar      * parse.h : parse.o
4813955d011SMarcel Moolenaar      *
4823955d011SMarcel Moolenaar      * parse.o : parse.y
4833955d011SMarcel Moolenaar      *		yacc -d parse.y
4843955d011SMarcel Moolenaar      *		cc -c y.tab.c
4853955d011SMarcel Moolenaar      *		mv y.tab.o parse.o
4863955d011SMarcel Moolenaar      *		cmp -s y.tab.h parse.h || mv y.tab.h parse.h
4873955d011SMarcel Moolenaar      *
4883955d011SMarcel Moolenaar      * In this case, if the definitions produced by yacc haven't changed
4893955d011SMarcel Moolenaar      * from before, parse.h won't have been updated and gn->mtime will
4903955d011SMarcel Moolenaar      * reflect the current modification time for parse.h. This is
491*e2eeea75SSimon J. Gerraty      * something of a kludge, I admit, but it's a useful one.
4923955d011SMarcel Moolenaar      *
493*e2eeea75SSimon J. Gerraty      * XXX: People like to use a rule like "FRC:" to force things that
494*e2eeea75SSimon J. Gerraty      * depend on FRC to be made, so we have to check for gn->children
495*e2eeea75SSimon J. Gerraty      * being empty as well.
4963955d011SMarcel Moolenaar      */
4973955d011SMarcel Moolenaar     if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
4983955d011SMarcel Moolenaar 	gn->mtime = now;
4993955d011SMarcel Moolenaar     }
5003955d011SMarcel Moolenaar #else
5013955d011SMarcel Moolenaar     /*
5023955d011SMarcel Moolenaar      * This is what Make does and it's actually a good thing, as it
5033955d011SMarcel Moolenaar      * allows rules like
5043955d011SMarcel Moolenaar      *
5053955d011SMarcel Moolenaar      *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
5063955d011SMarcel Moolenaar      *
5073955d011SMarcel Moolenaar      * to function as intended. Unfortunately, thanks to the stateless
5083955d011SMarcel Moolenaar      * nature of NFS (by which I mean the loose coupling of two clients
5093955d011SMarcel Moolenaar      * using the same file from a common server), there are times
5103955d011SMarcel Moolenaar      * when the modification time of a file created on a remote
5113955d011SMarcel Moolenaar      * machine will not be modified before the local stat() implied by
512*e2eeea75SSimon J. Gerraty      * the Dir_UpdateMTime occurs, thus leading us to believe that the file
5133955d011SMarcel Moolenaar      * is unchanged, wreaking havoc with files that depend on this one.
5143955d011SMarcel Moolenaar      *
5153955d011SMarcel Moolenaar      * I have decided it is better to make too much than to make too
5163955d011SMarcel Moolenaar      * little, so this stuff is commented out unless you're sure it's ok.
5173955d011SMarcel Moolenaar      * -- ardeb 1/12/88
5183955d011SMarcel Moolenaar      */
5193955d011SMarcel Moolenaar     /*
520*e2eeea75SSimon J. Gerraty      * Christos, 4/9/92: If we are saving commands, pretend that
521*e2eeea75SSimon J. Gerraty      * the target is made now. Otherwise archives with '...' rules
5223955d011SMarcel Moolenaar      * don't work!
5233955d011SMarcel Moolenaar      */
524956e45f6SSimon J. Gerraty     if (!GNode_ShouldExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
5253955d011SMarcel Moolenaar 	    (mtime == 0 && !(gn->type & OP_WAIT))) {
526956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, " recheck(%s): update time from %s to now\n",
5273955d011SMarcel Moolenaar 	       gn->name, Targ_FmtTime(gn->mtime));
5283955d011SMarcel Moolenaar 	gn->mtime = now;
529*e2eeea75SSimon J. Gerraty     } else {
530956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, " recheck(%s): current update time: %s\n",
5313955d011SMarcel Moolenaar 	       gn->name, Targ_FmtTime(gn->mtime));
5323955d011SMarcel Moolenaar     }
5333955d011SMarcel Moolenaar #endif
534*e2eeea75SSimon J. Gerraty 
535*e2eeea75SSimon J. Gerraty     /* XXX: The returned mtime may differ from gn->mtime.
536*e2eeea75SSimon J. Gerraty      * Intentionally? */
5373955d011SMarcel Moolenaar     return mtime;
5383955d011SMarcel Moolenaar }
5393955d011SMarcel Moolenaar 
540956e45f6SSimon J. Gerraty /*
541956e45f6SSimon J. Gerraty  * Set the .PREFIX and .IMPSRC variables for all the implied parents
542956e45f6SSimon J. Gerraty  * of this node.
543956e45f6SSimon J. Gerraty  */
544956e45f6SSimon J. Gerraty static void
545956e45f6SSimon J. Gerraty UpdateImplicitParentsVars(GNode *cgn, const char *cname)
546956e45f6SSimon J. Gerraty {
547956e45f6SSimon J. Gerraty     GNodeListNode *ln;
548956e45f6SSimon J. Gerraty     const char *cpref = GNode_VarPrefix(cgn);
549956e45f6SSimon J. Gerraty 
550956e45f6SSimon J. Gerraty     for (ln = cgn->implicitParents->first; ln != NULL; ln = ln->next) {
551956e45f6SSimon J. Gerraty 	GNode *pgn = ln->datum;
552956e45f6SSimon J. Gerraty 	if (pgn->flags & REMAKE) {
553956e45f6SSimon J. Gerraty 	    Var_Set(IMPSRC, cname, pgn);
554956e45f6SSimon J. Gerraty 	    if (cpref != NULL)
555956e45f6SSimon J. Gerraty 		Var_Set(PREFIX, cpref, pgn);
556956e45f6SSimon J. Gerraty 	}
557956e45f6SSimon J. Gerraty     }
558956e45f6SSimon J. Gerraty }
559956e45f6SSimon J. Gerraty 
560*e2eeea75SSimon J. Gerraty /* See if a .ORDER rule stops us from building this node. */
561*e2eeea75SSimon J. Gerraty static Boolean
562*e2eeea75SSimon J. Gerraty IsWaitingForOrder(GNode *gn)
563*e2eeea75SSimon J. Gerraty {
564*e2eeea75SSimon J. Gerraty     GNodeListNode *ln;
565*e2eeea75SSimon J. Gerraty 
566*e2eeea75SSimon J. Gerraty     for (ln = gn->order_pred->first; ln != NULL; ln = ln->next) {
567*e2eeea75SSimon J. Gerraty 	GNode *ogn = ln->datum;
568*e2eeea75SSimon J. Gerraty 
569*e2eeea75SSimon J. Gerraty 	if (ogn->made >= MADE || !(ogn->flags & REMAKE))
570*e2eeea75SSimon J. Gerraty 	    continue;
571*e2eeea75SSimon J. Gerraty 
572*e2eeea75SSimon J. Gerraty 	DEBUG2(MAKE, "IsWaitingForOrder: Waiting for .ORDER node \"%s%s\"\n",
573*e2eeea75SSimon J. Gerraty 	       ogn->name, ogn->cohort_num);
574*e2eeea75SSimon J. Gerraty 	return TRUE;
575*e2eeea75SSimon J. Gerraty     }
576*e2eeea75SSimon J. Gerraty     return FALSE;
577*e2eeea75SSimon J. Gerraty }
578*e2eeea75SSimon J. Gerraty 
579956e45f6SSimon J. Gerraty /* Perform update on the parents of a node. Used by JobFinish once
5803955d011SMarcel Moolenaar  * a node has been dealt with and by MakeStartJobs if it finds an
5813955d011SMarcel Moolenaar  * up-to-date node.
5823955d011SMarcel Moolenaar  *
5833955d011SMarcel Moolenaar  * The unmade field of pgn is decremented and pgn may be placed on
5843955d011SMarcel Moolenaar  * the toBeMade queue if this field becomes 0.
5853955d011SMarcel Moolenaar  *
5863955d011SMarcel Moolenaar  * If the child was made, the parent's flag CHILDMADE field will be
5873955d011SMarcel Moolenaar  * set true.
5883955d011SMarcel Moolenaar  *
5893955d011SMarcel Moolenaar  * If the child is not up-to-date and still does not exist,
5903955d011SMarcel Moolenaar  * set the FORCE flag on the parents.
5913955d011SMarcel Moolenaar  *
592956e45f6SSimon J. Gerraty  * If the child wasn't made, the youngestChild field of the parent will be
5933955d011SMarcel Moolenaar  * altered if the child's mtime is big enough.
5943955d011SMarcel Moolenaar  *
5953955d011SMarcel Moolenaar  * Finally, if the child is the implied source for the parent, the
5963955d011SMarcel Moolenaar  * parent's IMPSRC variable is set appropriately.
5973955d011SMarcel Moolenaar  */
5983955d011SMarcel Moolenaar void
5993955d011SMarcel Moolenaar Make_Update(GNode *cgn)
6003955d011SMarcel Moolenaar {
6012c3632d1SSimon J. Gerraty     const char *cname;		/* the child's name */
6023955d011SMarcel Moolenaar     time_t	mtime = -1;
603956e45f6SSimon J. Gerraty     GNodeList *parents;
604956e45f6SSimon J. Gerraty     GNodeListNode *ln;
6053955d011SMarcel Moolenaar     GNode	*centurion;
6063955d011SMarcel Moolenaar 
6073955d011SMarcel Moolenaar     /* It is save to re-examine any nodes again */
608*e2eeea75SSimon J. Gerraty     checked_seqno++;
6093955d011SMarcel Moolenaar 
610956e45f6SSimon J. Gerraty     cname = GNode_VarTarget(cgn);
6113955d011SMarcel Moolenaar 
612956e45f6SSimon J. Gerraty     DEBUG2(MAKE, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
6133955d011SMarcel Moolenaar 
6143955d011SMarcel Moolenaar     /*
6153955d011SMarcel Moolenaar      * If the child was actually made, see what its modification time is
6163955d011SMarcel Moolenaar      * now -- some rules won't actually update the file. If the file still
6173955d011SMarcel Moolenaar      * doesn't exist, make its mtime now.
6183955d011SMarcel Moolenaar      */
6193955d011SMarcel Moolenaar     if (cgn->made != UPTODATE) {
6203955d011SMarcel Moolenaar 	mtime = Make_Recheck(cgn);
6213955d011SMarcel Moolenaar     }
6223955d011SMarcel Moolenaar 
6233955d011SMarcel Moolenaar     /*
6243955d011SMarcel Moolenaar      * If this is a `::' node, we must consult its first instance
6253955d011SMarcel Moolenaar      * which is where all parents are linked.
6263955d011SMarcel Moolenaar      */
6273955d011SMarcel Moolenaar     if ((centurion = cgn->centurion) != NULL) {
6283955d011SMarcel Moolenaar 	if (!Lst_IsEmpty(cgn->parents))
6293955d011SMarcel Moolenaar 		Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num);
630956e45f6SSimon J. Gerraty 	centurion->unmade_cohorts--;
6313955d011SMarcel Moolenaar 	if (centurion->unmade_cohorts < 0)
6323955d011SMarcel Moolenaar 	    Error("Graph cycles through centurion %s", centurion->name);
6333955d011SMarcel Moolenaar     } else {
6343955d011SMarcel Moolenaar 	centurion = cgn;
6353955d011SMarcel Moolenaar     }
6363955d011SMarcel Moolenaar     parents = centurion->parents;
6373955d011SMarcel Moolenaar 
6383955d011SMarcel Moolenaar     /* If this was a .ORDER node, schedule the RHS */
639956e45f6SSimon J. Gerraty     Lst_ForEachUntil(centurion->order_succ, MakeBuildParent, toBeMade->first);
6403955d011SMarcel Moolenaar 
6413955d011SMarcel Moolenaar     /* Now mark all the parents as having one less unmade child */
642956e45f6SSimon J. Gerraty     for (ln = parents->first; ln != NULL; ln = ln->next) {
643956e45f6SSimon J. Gerraty 	GNode *pgn = ln->datum;
644956e45f6SSimon J. Gerraty 
645*e2eeea75SSimon J. Gerraty 	if (DEBUG(MAKE)) {
646*e2eeea75SSimon J. Gerraty 	    debug_printf("inspect parent %s%s: ", pgn->name, pgn->cohort_num);
647*e2eeea75SSimon J. Gerraty 	    GNode_FprintDetails(opts.debug_file, "", pgn, "");
648*e2eeea75SSimon J. Gerraty 	    debug_printf(", unmade %d ", pgn->unmade - 1);
649*e2eeea75SSimon J. Gerraty 	}
6503955d011SMarcel Moolenaar 
6513955d011SMarcel Moolenaar 	if (!(pgn->flags & REMAKE)) {
6523955d011SMarcel Moolenaar 	    /* This parent isn't needed */
653956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "- not needed\n");
6543955d011SMarcel Moolenaar 	    continue;
6553955d011SMarcel Moolenaar 	}
6563955d011SMarcel Moolenaar 	if (mtime == 0 && !(cgn->type & OP_WAIT))
6573955d011SMarcel Moolenaar 	    pgn->flags |= FORCE;
6583955d011SMarcel Moolenaar 
6593955d011SMarcel Moolenaar 	/*
6603955d011SMarcel Moolenaar 	 * If the parent has the .MADE attribute, its timestamp got
661956e45f6SSimon J. Gerraty 	 * updated to that of its newest child, and its unmade
6623955d011SMarcel Moolenaar 	 * child count got set to zero in Make_ExpandUse().
6633955d011SMarcel Moolenaar 	 * However other things might cause us to build one of its
6643955d011SMarcel Moolenaar 	 * children - and so we mustn't do any processing here when
6653955d011SMarcel Moolenaar 	 * the child build finishes.
6663955d011SMarcel Moolenaar 	 */
6673955d011SMarcel Moolenaar 	if (pgn->type & OP_MADE) {
668956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "- .MADE\n");
6693955d011SMarcel Moolenaar 	    continue;
6703955d011SMarcel Moolenaar 	}
6713955d011SMarcel Moolenaar 
6723955d011SMarcel Moolenaar 	if (!(cgn->type & (OP_EXEC | OP_USE | OP_USEBEFORE))) {
6733955d011SMarcel Moolenaar 	    if (cgn->made == MADE)
6743955d011SMarcel Moolenaar 		pgn->flags |= CHILDMADE;
675*e2eeea75SSimon J. Gerraty 	    GNode_UpdateYoungestChild(pgn, cgn);
6763955d011SMarcel Moolenaar 	}
6773955d011SMarcel Moolenaar 
6783955d011SMarcel Moolenaar 	/*
6793955d011SMarcel Moolenaar 	 * A parent must wait for the completion of all instances
6803955d011SMarcel Moolenaar 	 * of a `::' dependency.
6813955d011SMarcel Moolenaar 	 */
6823955d011SMarcel Moolenaar 	if (centurion->unmade_cohorts != 0 || centurion->made < MADE) {
683956e45f6SSimon J. Gerraty 	    DEBUG2(MAKE, "- centurion made %d, %d unmade cohorts\n",
6843955d011SMarcel Moolenaar 		   centurion->made, centurion->unmade_cohorts);
6853955d011SMarcel Moolenaar 	    continue;
6863955d011SMarcel Moolenaar 	}
6873955d011SMarcel Moolenaar 
6883955d011SMarcel Moolenaar 	/* One more child of this parent is now made */
689956e45f6SSimon J. Gerraty 	pgn->unmade--;
6903955d011SMarcel Moolenaar 	if (pgn->unmade < 0) {
6913955d011SMarcel Moolenaar 	    if (DEBUG(MAKE)) {
692956e45f6SSimon J. Gerraty 		debug_printf("Graph cycles through %s%s\n",
6933955d011SMarcel Moolenaar 			     pgn->name, pgn->cohort_num);
6943955d011SMarcel Moolenaar 		Targ_PrintGraph(2);
6953955d011SMarcel Moolenaar 	    }
6963955d011SMarcel Moolenaar 	    Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num);
6973955d011SMarcel Moolenaar 	}
6983955d011SMarcel Moolenaar 
6993955d011SMarcel Moolenaar 	/* We must always rescan the parents of .WAIT and .ORDER nodes. */
7003955d011SMarcel Moolenaar 	if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
7013955d011SMarcel Moolenaar 		&& !(centurion->flags & DONE_ORDER)) {
702956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "- unmade children\n");
7033955d011SMarcel Moolenaar 	    continue;
7043955d011SMarcel Moolenaar 	}
7053955d011SMarcel Moolenaar 	if (pgn->made != DEFERRED) {
7063955d011SMarcel Moolenaar 	    /*
7073955d011SMarcel Moolenaar 	     * Either this parent is on a different branch of the tree,
7083955d011SMarcel Moolenaar 	     * or it on the RHS of a .WAIT directive
7093955d011SMarcel Moolenaar 	     * or it is already on the toBeMade list.
7103955d011SMarcel Moolenaar 	     */
711956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "- not deferred\n");
7123955d011SMarcel Moolenaar 	    continue;
7133955d011SMarcel Moolenaar 	}
714*e2eeea75SSimon J. Gerraty 
715*e2eeea75SSimon J. Gerraty 	if (IsWaitingForOrder(pgn))
7163955d011SMarcel Moolenaar 	    continue;
717*e2eeea75SSimon J. Gerraty 
7183955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
719956e45f6SSimon J. Gerraty 	    debug_printf("- %s%s made, schedule %s%s (made %d)\n",
7203955d011SMarcel Moolenaar 			 cgn->name, cgn->cohort_num,
7213955d011SMarcel Moolenaar 			 pgn->name, pgn->cohort_num, pgn->made);
722956e45f6SSimon J. Gerraty 	    Targ_PrintNode(pgn, 2);
7233955d011SMarcel Moolenaar 	}
7243955d011SMarcel Moolenaar 	/* Ok, we can schedule the parent again */
7253955d011SMarcel Moolenaar 	pgn->made = REQUESTED;
7262c3632d1SSimon J. Gerraty 	Lst_Enqueue(toBeMade, pgn);
7273955d011SMarcel Moolenaar     }
7283955d011SMarcel Moolenaar 
729956e45f6SSimon J. Gerraty     UpdateImplicitParentsVars(cgn, cname);
730956e45f6SSimon J. Gerraty }
731956e45f6SSimon J. Gerraty 
732956e45f6SSimon J. Gerraty static void
733956e45f6SSimon J. Gerraty UnmarkChildren(GNode *gn)
7342c3632d1SSimon J. Gerraty {
735956e45f6SSimon J. Gerraty     GNodeListNode *ln;
7363955d011SMarcel Moolenaar 
737956e45f6SSimon J. Gerraty     for (ln = gn->children->first; ln != NULL; ln = ln->next) {
738956e45f6SSimon J. Gerraty 	GNode *child = ln->datum;
739956e45f6SSimon J. Gerraty 	child->type &= ~OP_MARK;
7403955d011SMarcel Moolenaar     }
7413955d011SMarcel Moolenaar }
7422c3632d1SSimon J. Gerraty 
743956e45f6SSimon J. Gerraty /* Add a child's name to the ALLSRC and OODATE variables of the given
744956e45f6SSimon J. Gerraty  * node, but only if it has not been given the .EXEC, .USE or .INVISIBLE
745956e45f6SSimon J. Gerraty  * attributes. .EXEC and .USE children are very rarely going to be files,
746956e45f6SSimon J. Gerraty  * so...
747956e45f6SSimon J. Gerraty  *
7483955d011SMarcel Moolenaar  * If the child is a .JOIN node, its ALLSRC is propagated to the parent.
7493955d011SMarcel Moolenaar  *
7503955d011SMarcel Moolenaar  * A child is added to the OODATE variable if its modification time is
7513955d011SMarcel Moolenaar  * later than that of its parent, as defined by Make, except if the
7523955d011SMarcel Moolenaar  * parent is a .JOIN node. In that case, it is only added to the OODATE
7533955d011SMarcel Moolenaar  * variable if it was actually made (since .JOIN nodes don't have
7543955d011SMarcel Moolenaar  * modification times, the comparison is rather unfair...)..
7553955d011SMarcel Moolenaar  *
7563955d011SMarcel Moolenaar  * Input:
757956e45f6SSimon J. Gerraty  *	cgn		The child to add
758956e45f6SSimon J. Gerraty  *	pgn		The parent to whose ALLSRC variable it should
7593955d011SMarcel Moolenaar  *			be added
7603955d011SMarcel Moolenaar  */
761956e45f6SSimon J. Gerraty static void
762956e45f6SSimon J. Gerraty MakeAddAllSrc(GNode *cgn, GNode *pgn)
7633955d011SMarcel Moolenaar {
7643955d011SMarcel Moolenaar     if (cgn->type & OP_MARK)
765956e45f6SSimon J. Gerraty 	return;
7663955d011SMarcel Moolenaar     cgn->type |= OP_MARK;
7673955d011SMarcel Moolenaar 
768*e2eeea75SSimon J. Gerraty     if (!(cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE))) {
7692c3632d1SSimon J. Gerraty 	const char *child, *allsrc;
7703955d011SMarcel Moolenaar 
7713955d011SMarcel Moolenaar 	if (cgn->type & OP_ARCHV)
772956e45f6SSimon J. Gerraty 	    child = GNode_VarMember(cgn);
7733955d011SMarcel Moolenaar 	else
774956e45f6SSimon J. Gerraty 	    child = GNode_Path(cgn);
7753955d011SMarcel Moolenaar 	if (cgn->type & OP_JOIN) {
776956e45f6SSimon J. Gerraty 	    allsrc = GNode_VarAllsrc(cgn);
7773955d011SMarcel Moolenaar 	} else {
7783955d011SMarcel Moolenaar 	    allsrc = child;
7793955d011SMarcel Moolenaar 	}
7803955d011SMarcel Moolenaar 	if (allsrc != NULL)
7813955d011SMarcel Moolenaar 		Var_Append(ALLSRC, allsrc, pgn);
7823955d011SMarcel Moolenaar 	if (pgn->type & OP_JOIN) {
7833955d011SMarcel Moolenaar 	    if (cgn->made == MADE) {
7843955d011SMarcel Moolenaar 		Var_Append(OODATE, child, pgn);
7853955d011SMarcel Moolenaar 	    }
7863955d011SMarcel Moolenaar 	} else if ((pgn->mtime < cgn->mtime) ||
7873955d011SMarcel Moolenaar 		   (cgn->mtime >= now && cgn->made == MADE))
7883955d011SMarcel Moolenaar 	{
7893955d011SMarcel Moolenaar 	    /*
7903955d011SMarcel Moolenaar 	     * It goes in the OODATE variable if the parent is younger than the
7913955d011SMarcel Moolenaar 	     * child or if the child has been modified more recently than
7923955d011SMarcel Moolenaar 	     * the start of the make. This is to keep pmake from getting
7933955d011SMarcel Moolenaar 	     * confused if something else updates the parent after the
7943955d011SMarcel Moolenaar 	     * make starts (shouldn't happen, I know, but sometimes it
795*e2eeea75SSimon J. Gerraty 	     * does). In such a case, if we've updated the child, the parent
7963955d011SMarcel Moolenaar 	     * is likely to have a modification time later than that of
797*e2eeea75SSimon J. Gerraty 	     * the child and anything that relies on the OODATE variable will
7983955d011SMarcel Moolenaar 	     * be hosed.
7993955d011SMarcel Moolenaar 	     *
8003955d011SMarcel Moolenaar 	     * XXX: This will cause all made children to go in the OODATE
8013955d011SMarcel Moolenaar 	     * variable, even if they're not touched, if RECHECK isn't defined,
8023955d011SMarcel Moolenaar 	     * since cgn->mtime is set to now in Make_Update. According to
8033955d011SMarcel Moolenaar 	     * some people, this is good...
8043955d011SMarcel Moolenaar 	     */
8053955d011SMarcel Moolenaar 	    Var_Append(OODATE, child, pgn);
8063955d011SMarcel Moolenaar 	}
8073955d011SMarcel Moolenaar     }
8083955d011SMarcel Moolenaar }
8092c3632d1SSimon J. Gerraty 
810956e45f6SSimon J. Gerraty /* Set up the ALLSRC and OODATE variables. Sad to say, it must be
8113955d011SMarcel Moolenaar  * done separately, rather than while traversing the graph. This is
8123955d011SMarcel Moolenaar  * because Make defined OODATE to contain all sources whose modification
8133955d011SMarcel Moolenaar  * times were later than that of the target, *not* those sources that
8143955d011SMarcel Moolenaar  * were out-of-date. Since in both compatibility and native modes,
8153955d011SMarcel Moolenaar  * the modification time of the parent isn't found until the child
8163955d011SMarcel Moolenaar  * has been dealt with, we have to wait until now to fill in the
8173955d011SMarcel Moolenaar  * variable. As for ALLSRC, the ordering is important and not
8183955d011SMarcel Moolenaar  * guaranteed when in native mode, so it must be set here, too.
8193955d011SMarcel Moolenaar  *
8203955d011SMarcel Moolenaar  * If the node is a .JOIN node, its TARGET variable will be set to
8213955d011SMarcel Moolenaar  * match its ALLSRC variable.
8223955d011SMarcel Moolenaar  */
8233955d011SMarcel Moolenaar void
8243955d011SMarcel Moolenaar Make_DoAllVar(GNode *gn)
8253955d011SMarcel Moolenaar {
826956e45f6SSimon J. Gerraty     GNodeListNode *ln;
827956e45f6SSimon J. Gerraty 
8283955d011SMarcel Moolenaar     if (gn->flags & DONE_ALLSRC)
8293955d011SMarcel Moolenaar 	return;
8303955d011SMarcel Moolenaar 
831956e45f6SSimon J. Gerraty     UnmarkChildren(gn);
832956e45f6SSimon J. Gerraty     for (ln = gn->children->first; ln != NULL; ln = ln->next)
833956e45f6SSimon J. Gerraty 	MakeAddAllSrc(ln->datum, gn);
8343955d011SMarcel Moolenaar 
835*e2eeea75SSimon J. Gerraty     if (!Var_Exists(OODATE, gn))
8363841c287SSimon J. Gerraty 	Var_Set(OODATE, "", gn);
837*e2eeea75SSimon J. Gerraty     if (!Var_Exists(ALLSRC, gn))
8383841c287SSimon J. Gerraty 	Var_Set(ALLSRC, "", gn);
8393955d011SMarcel Moolenaar 
840956e45f6SSimon J. Gerraty     if (gn->type & OP_JOIN)
841956e45f6SSimon J. Gerraty 	Var_Set(TARGET, GNode_VarAllsrc(gn), gn);
8423955d011SMarcel Moolenaar     gn->flags |= DONE_ALLSRC;
8433955d011SMarcel Moolenaar }
8442c3632d1SSimon J. Gerraty 
8453955d011SMarcel Moolenaar static int
8463955d011SMarcel Moolenaar MakeBuildChild(void *v_cn, void *toBeMade_next)
8473955d011SMarcel Moolenaar {
8483955d011SMarcel Moolenaar     GNode *cn = v_cn;
8493955d011SMarcel Moolenaar 
850*e2eeea75SSimon J. Gerraty     if (DEBUG(MAKE)) {
851*e2eeea75SSimon J. Gerraty 	debug_printf("MakeBuildChild: inspect %s%s, ",
852*e2eeea75SSimon J. Gerraty 	       cn->name, cn->cohort_num);
853*e2eeea75SSimon J. Gerraty 	GNode_FprintDetails(opts.debug_file, "", cn, "\n");
854*e2eeea75SSimon J. Gerraty     }
8553955d011SMarcel Moolenaar     if (cn->made > DEFERRED)
8563955d011SMarcel Moolenaar 	return 0;
8573955d011SMarcel Moolenaar 
8583955d011SMarcel Moolenaar     /* If this node is on the RHS of a .ORDER, check LHSs. */
859*e2eeea75SSimon J. Gerraty     if (IsWaitingForOrder(cn)) {
8603955d011SMarcel Moolenaar 	/* Can't build this (or anything else in this child list) yet */
8613955d011SMarcel Moolenaar 	cn->made = DEFERRED;
86259a02420SSimon J. Gerraty 	return 0;			/* but keep looking */
8633955d011SMarcel Moolenaar     }
8643955d011SMarcel Moolenaar 
865956e45f6SSimon J. Gerraty     DEBUG2(MAKE, "MakeBuildChild: schedule %s%s\n", cn->name, cn->cohort_num);
8663955d011SMarcel Moolenaar 
8673955d011SMarcel Moolenaar     cn->made = REQUESTED;
8683955d011SMarcel Moolenaar     if (toBeMade_next == NULL)
8692c3632d1SSimon J. Gerraty 	Lst_Append(toBeMade, cn);
8703955d011SMarcel Moolenaar     else
8713955d011SMarcel Moolenaar 	Lst_InsertBefore(toBeMade, toBeMade_next, cn);
8723955d011SMarcel Moolenaar 
8733955d011SMarcel Moolenaar     if (cn->unmade_cohorts != 0)
874956e45f6SSimon J. Gerraty 	Lst_ForEachUntil(cn->cohorts, MakeBuildChild, toBeMade_next);
8753955d011SMarcel Moolenaar 
8763955d011SMarcel Moolenaar     /*
877956e45f6SSimon J. Gerraty      * If this node is a .WAIT node with unmade children
8783955d011SMarcel Moolenaar      * then don't add the next sibling.
8793955d011SMarcel Moolenaar      */
8803955d011SMarcel Moolenaar     return cn->type & OP_WAIT && cn->unmade > 0;
8813955d011SMarcel Moolenaar }
8823955d011SMarcel Moolenaar 
883*e2eeea75SSimon J. Gerraty /* When a .ORDER LHS node completes, we do this on each RHS. */
8843955d011SMarcel Moolenaar static int
8853955d011SMarcel Moolenaar MakeBuildParent(void *v_pn, void *toBeMade_next)
8863955d011SMarcel Moolenaar {
8873955d011SMarcel Moolenaar     GNode *pn = v_pn;
8883955d011SMarcel Moolenaar 
8893955d011SMarcel Moolenaar     if (pn->made != DEFERRED)
8903955d011SMarcel Moolenaar 	return 0;
8913955d011SMarcel Moolenaar 
8923955d011SMarcel Moolenaar     if (MakeBuildChild(pn, toBeMade_next) == 0) {
8933955d011SMarcel Moolenaar 	/* Mark so that when this node is built we reschedule its parents */
8943955d011SMarcel Moolenaar 	pn->flags |= DONE_ORDER;
8953955d011SMarcel Moolenaar     }
8963955d011SMarcel Moolenaar 
8973955d011SMarcel Moolenaar     return 0;
8983955d011SMarcel Moolenaar }
8993955d011SMarcel Moolenaar 
900956e45f6SSimon J. Gerraty /* Start as many jobs as possible, taking them from the toBeMade queue.
901956e45f6SSimon J. Gerraty  *
902*e2eeea75SSimon J. Gerraty  * If the -q option was given, no job will be started,
903956e45f6SSimon J. Gerraty  * but as soon as an out-of-date target is found, this function
904*e2eeea75SSimon J. Gerraty  * returns TRUE. In all other cases, this function returns FALSE.
905956e45f6SSimon J. Gerraty  */
9063955d011SMarcel Moolenaar static Boolean
9073955d011SMarcel Moolenaar MakeStartJobs(void)
9083955d011SMarcel Moolenaar {
9093955d011SMarcel Moolenaar     GNode *gn;
910*e2eeea75SSimon J. Gerraty     Boolean have_token = FALSE;
9113955d011SMarcel Moolenaar 
9123955d011SMarcel Moolenaar     while (!Lst_IsEmpty(toBeMade)) {
9133955d011SMarcel Moolenaar 	/* Get token now to avoid cycling job-list when we only have 1 token */
9143955d011SMarcel Moolenaar 	if (!have_token && !Job_TokenWithdraw())
9153955d011SMarcel Moolenaar 	    break;
916*e2eeea75SSimon J. Gerraty 	have_token = TRUE;
9173955d011SMarcel Moolenaar 
9182c3632d1SSimon J. Gerraty 	gn = Lst_Dequeue(toBeMade);
919956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num);
9203955d011SMarcel Moolenaar 
9213955d011SMarcel Moolenaar 	if (gn->made != REQUESTED) {
922956e45f6SSimon J. Gerraty 	    DEBUG1(MAKE, "state %d\n", gn->made);
9233955d011SMarcel Moolenaar 
9243955d011SMarcel Moolenaar 	    make_abort(gn, __LINE__);
9253955d011SMarcel Moolenaar 	}
9263955d011SMarcel Moolenaar 
927*e2eeea75SSimon J. Gerraty 	if (gn->checked_seqno == checked_seqno) {
9283955d011SMarcel Moolenaar 	    /* We've already looked at this node since a job finished... */
929956e45f6SSimon J. Gerraty 	    DEBUG2(MAKE, "already checked %s%s\n", gn->name, gn->cohort_num);
9303955d011SMarcel Moolenaar 	    gn->made = DEFERRED;
9313955d011SMarcel Moolenaar 	    continue;
9323955d011SMarcel Moolenaar 	}
933*e2eeea75SSimon J. Gerraty 	gn->checked_seqno = checked_seqno;
9343955d011SMarcel Moolenaar 
9353955d011SMarcel Moolenaar 	if (gn->unmade != 0) {
9363955d011SMarcel Moolenaar 	    /*
9373955d011SMarcel Moolenaar 	     * We can't build this yet, add all unmade children to toBeMade,
9383955d011SMarcel Moolenaar 	     * just before the current first element.
9393955d011SMarcel Moolenaar 	     */
9403955d011SMarcel Moolenaar 	    gn->made = DEFERRED;
941956e45f6SSimon J. Gerraty 	    Lst_ForEachUntil(gn->children, MakeBuildChild, toBeMade->first);
9423955d011SMarcel Moolenaar 	    /* and drop this node on the floor */
943956e45f6SSimon J. Gerraty 	    DEBUG2(MAKE, "dropped %s%s\n", gn->name, gn->cohort_num);
9443955d011SMarcel Moolenaar 	    continue;
9453955d011SMarcel Moolenaar 	}
9463955d011SMarcel Moolenaar 
9473955d011SMarcel Moolenaar 	gn->made = BEINGMADE;
948*e2eeea75SSimon J. Gerraty 	if (GNode_IsOODate(gn)) {
949956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "out-of-date\n");
950*e2eeea75SSimon J. Gerraty 	    if (opts.queryFlag)
9513841c287SSimon J. Gerraty 		return TRUE;
9523955d011SMarcel Moolenaar 	    Make_DoAllVar(gn);
9533955d011SMarcel Moolenaar 	    Job_Make(gn);
954*e2eeea75SSimon J. Gerraty 	    have_token = FALSE;
9553955d011SMarcel Moolenaar 	} else {
956956e45f6SSimon J. Gerraty 	    DEBUG0(MAKE, "up-to-date\n");
9573955d011SMarcel Moolenaar 	    gn->made = UPTODATE;
9583955d011SMarcel Moolenaar 	    if (gn->type & OP_JOIN) {
9593955d011SMarcel Moolenaar 		/*
9603955d011SMarcel Moolenaar 		 * Even for an up-to-date .JOIN node, we need it to have its
9613955d011SMarcel Moolenaar 		 * context variables so references to it get the correct
9623955d011SMarcel Moolenaar 		 * value for .TARGET when building up the context variables
9633955d011SMarcel Moolenaar 		 * of its parent(s)...
9643955d011SMarcel Moolenaar 		 */
9653955d011SMarcel Moolenaar 		Make_DoAllVar(gn);
9663955d011SMarcel Moolenaar 	    }
9673955d011SMarcel Moolenaar 	    Make_Update(gn);
9683955d011SMarcel Moolenaar 	}
9693955d011SMarcel Moolenaar     }
9703955d011SMarcel Moolenaar 
9713955d011SMarcel Moolenaar     if (have_token)
9723955d011SMarcel Moolenaar 	Job_TokenReturn();
9733955d011SMarcel Moolenaar 
9743841c287SSimon J. Gerraty     return FALSE;
9753955d011SMarcel Moolenaar }
9762c3632d1SSimon J. Gerraty 
977*e2eeea75SSimon J. Gerraty /* Print the status of a .ORDER node. */
978956e45f6SSimon J. Gerraty static void
979956e45f6SSimon J. Gerraty MakePrintStatusOrderNode(GNode *ogn, GNode *gn)
9803955d011SMarcel Moolenaar {
9813955d011SMarcel Moolenaar     if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED)
9823955d011SMarcel Moolenaar 	/* not waiting for this one */
983956e45f6SSimon J. Gerraty 	return;
9843955d011SMarcel Moolenaar 
9852c3632d1SSimon J. Gerraty     printf("    `%s%s' has .ORDER dependency against %s%s ",
9862c3632d1SSimon J. Gerraty 	   gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
9872c3632d1SSimon J. Gerraty     GNode_FprintDetails(stdout, "(", ogn, ")\n");
9882c3632d1SSimon J. Gerraty 
989956e45f6SSimon J. Gerraty     if (DEBUG(MAKE) && opts.debug_file != stdout) {
990956e45f6SSimon J. Gerraty 	debug_printf("    `%s%s' has .ORDER dependency against %s%s ",
9912c3632d1SSimon J. Gerraty 		     gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
992956e45f6SSimon J. Gerraty 	GNode_FprintDetails(opts.debug_file, "(", ogn, ")\n");
9932c3632d1SSimon J. Gerraty     }
9943955d011SMarcel Moolenaar }
9953955d011SMarcel Moolenaar 
996956e45f6SSimon J. Gerraty static void
997956e45f6SSimon J. Gerraty MakePrintStatusOrder(GNode *gn)
9983955d011SMarcel Moolenaar {
999956e45f6SSimon J. Gerraty     GNodeListNode *ln;
1000956e45f6SSimon J. Gerraty     for (ln = gn->order_pred->first; ln != NULL; ln = ln->next)
1001956e45f6SSimon J. Gerraty 	MakePrintStatusOrderNode(ln->datum, gn);
1002956e45f6SSimon J. Gerraty }
10033955d011SMarcel Moolenaar 
1004956e45f6SSimon J. Gerraty static void MakePrintStatusList(GNodeList *, int *);
1005956e45f6SSimon J. Gerraty 
1006956e45f6SSimon J. Gerraty /* Print the status of a top-level node, viz. it being up-to-date already
1007956e45f6SSimon J. Gerraty  * or not created due to an error in a lower level.
1008956e45f6SSimon J. Gerraty  * Callback function for Make_Run via Lst_ForEachUntil.
1009956e45f6SSimon J. Gerraty  */
1010956e45f6SSimon J. Gerraty static Boolean
1011956e45f6SSimon J. Gerraty MakePrintStatus(GNode *gn, int *errors)
1012956e45f6SSimon J. Gerraty {
10133955d011SMarcel Moolenaar     if (gn->flags & DONECYCLE)
10143955d011SMarcel Moolenaar 	/* We've completely processed this node before, don't do it again. */
1015956e45f6SSimon J. Gerraty 	return FALSE;
10163955d011SMarcel Moolenaar 
10173955d011SMarcel Moolenaar     if (gn->unmade == 0) {
10183955d011SMarcel Moolenaar 	gn->flags |= DONECYCLE;
10193955d011SMarcel Moolenaar 	switch (gn->made) {
10203955d011SMarcel Moolenaar 	case UPTODATE:
10213955d011SMarcel Moolenaar 	    printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num);
10223955d011SMarcel Moolenaar 	    break;
10233955d011SMarcel Moolenaar 	case MADE:
10243955d011SMarcel Moolenaar 	    break;
10253955d011SMarcel Moolenaar 	case UNMADE:
10263955d011SMarcel Moolenaar 	case DEFERRED:
10273955d011SMarcel Moolenaar 	case REQUESTED:
10283955d011SMarcel Moolenaar 	case BEINGMADE:
10293955d011SMarcel Moolenaar 	    (*errors)++;
10302c3632d1SSimon J. Gerraty 	    printf("`%s%s' was not built", gn->name, gn->cohort_num);
10312c3632d1SSimon J. Gerraty 	    GNode_FprintDetails(stdout, " (", gn, ")!\n");
1032956e45f6SSimon J. Gerraty 	    if (DEBUG(MAKE) && opts.debug_file != stdout) {
1033956e45f6SSimon J. Gerraty 		debug_printf("`%s%s' was not built", gn->name, gn->cohort_num);
1034956e45f6SSimon J. Gerraty 		GNode_FprintDetails(opts.debug_file, " (", gn, ")!\n");
10352c3632d1SSimon J. Gerraty 	    }
10363955d011SMarcel Moolenaar 	    /* Most likely problem is actually caused by .ORDER */
1037956e45f6SSimon J. Gerraty 	    MakePrintStatusOrder(gn);
10383955d011SMarcel Moolenaar 	    break;
10393955d011SMarcel Moolenaar 	default:
10403955d011SMarcel Moolenaar 	    /* Errors - already counted */
10413955d011SMarcel Moolenaar 	    printf("`%s%s' not remade because of errors.\n",
10423955d011SMarcel Moolenaar 		    gn->name, gn->cohort_num);
1043956e45f6SSimon J. Gerraty 	    if (DEBUG(MAKE) && opts.debug_file != stdout)
1044956e45f6SSimon J. Gerraty 		debug_printf("`%s%s' not remade because of errors.\n",
10453955d011SMarcel Moolenaar 			     gn->name, gn->cohort_num);
10463955d011SMarcel Moolenaar 	    break;
10473955d011SMarcel Moolenaar 	}
1048956e45f6SSimon J. Gerraty 	return FALSE;
10493955d011SMarcel Moolenaar     }
10503955d011SMarcel Moolenaar 
1051956e45f6SSimon J. Gerraty     DEBUG3(MAKE, "MakePrintStatus: %s%s has %d unmade children\n",
10523955d011SMarcel Moolenaar 	   gn->name, gn->cohort_num, gn->unmade);
10533955d011SMarcel Moolenaar     /*
10543955d011SMarcel Moolenaar      * If printing cycles and came to one that has unmade children,
10553955d011SMarcel Moolenaar      * print out the cycle by recursing on its children.
10563955d011SMarcel Moolenaar      */
10573955d011SMarcel Moolenaar     if (!(gn->flags & CYCLE)) {
1058*e2eeea75SSimon J. Gerraty 	/* First time we've seen this node, check all children */
10593955d011SMarcel Moolenaar 	gn->flags |= CYCLE;
1060956e45f6SSimon J. Gerraty 	MakePrintStatusList(gn->children, errors);
10613955d011SMarcel Moolenaar 	/* Mark that this node needn't be processed again */
10623955d011SMarcel Moolenaar 	gn->flags |= DONECYCLE;
1063956e45f6SSimon J. Gerraty 	return FALSE;
10643955d011SMarcel Moolenaar     }
10653955d011SMarcel Moolenaar 
10663955d011SMarcel Moolenaar     /* Only output the error once per node */
10673955d011SMarcel Moolenaar     gn->flags |= DONECYCLE;
10683955d011SMarcel Moolenaar     Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
10693955d011SMarcel Moolenaar     if ((*errors)++ > 100)
10703955d011SMarcel Moolenaar 	/* Abandon the whole error report */
1071956e45f6SSimon J. Gerraty 	return TRUE;
10723955d011SMarcel Moolenaar 
10733955d011SMarcel Moolenaar     /* Reporting for our children will give the rest of the loop */
1074956e45f6SSimon J. Gerraty     MakePrintStatusList(gn->children, errors);
1075956e45f6SSimon J. Gerraty     return FALSE;
10763955d011SMarcel Moolenaar }
10772c3632d1SSimon J. Gerraty 
1078956e45f6SSimon J. Gerraty static void
1079956e45f6SSimon J. Gerraty MakePrintStatusList(GNodeList *gnodes, int *errors)
1080956e45f6SSimon J. Gerraty {
1081956e45f6SSimon J. Gerraty     GNodeListNode *ln;
1082956e45f6SSimon J. Gerraty     for (ln = gnodes->first; ln != NULL; ln = ln->next)
1083956e45f6SSimon J. Gerraty 	if (MakePrintStatus(ln->datum, errors))
1084956e45f6SSimon J. Gerraty 	    break;
1085956e45f6SSimon J. Gerraty }
10863955d011SMarcel Moolenaar 
1087*e2eeea75SSimon J. Gerraty static void
1088*e2eeea75SSimon J. Gerraty ExamineLater(GNodeList *examine, GNodeList *toBeExamined)
1089*e2eeea75SSimon J. Gerraty {
1090*e2eeea75SSimon J. Gerraty     ListNode *ln;
1091*e2eeea75SSimon J. Gerraty 
1092*e2eeea75SSimon J. Gerraty     for (ln = toBeExamined->first; ln != NULL; ln = ln->next) {
1093*e2eeea75SSimon J. Gerraty 	GNode *gn = ln->datum;
1094*e2eeea75SSimon J. Gerraty 
1095*e2eeea75SSimon J. Gerraty 	if (gn->flags & REMAKE)
1096*e2eeea75SSimon J. Gerraty 	    continue;
1097*e2eeea75SSimon J. Gerraty 	if (gn->type & (OP_USE | OP_USEBEFORE))
1098*e2eeea75SSimon J. Gerraty 	    continue;
1099*e2eeea75SSimon J. Gerraty 
1100*e2eeea75SSimon J. Gerraty 	DEBUG2(MAKE, "ExamineLater: need to examine \"%s%s\"\n",
1101*e2eeea75SSimon J. Gerraty 	       gn->name, gn->cohort_num);
1102*e2eeea75SSimon J. Gerraty 	Lst_Enqueue(examine, gn);
1103*e2eeea75SSimon J. Gerraty     }
1104*e2eeea75SSimon J. Gerraty }
1105*e2eeea75SSimon J. Gerraty 
1106956e45f6SSimon J. Gerraty /* Expand .USE nodes and create a new targets list.
11073955d011SMarcel Moolenaar  *
11083955d011SMarcel Moolenaar  * Input:
11093955d011SMarcel Moolenaar  *	targs		the initial list of targets
11103955d011SMarcel Moolenaar  */
11113955d011SMarcel Moolenaar void
1112956e45f6SSimon J. Gerraty Make_ExpandUse(GNodeList *targs)
11133955d011SMarcel Moolenaar {
1114*e2eeea75SSimon J. Gerraty     GNodeList *examine = Lst_New();	/* Queue of targets to examine */
1115*e2eeea75SSimon J. Gerraty     Lst_AppendAll(examine, targs);
11163955d011SMarcel Moolenaar 
11173955d011SMarcel Moolenaar     /*
11183955d011SMarcel Moolenaar      * Make an initial downward pass over the graph, marking nodes to be made
11193955d011SMarcel Moolenaar      * as we go down. We call Suff_FindDeps to find where a node is and
11203955d011SMarcel Moolenaar      * to get some children for it if it has none and also has no commands.
11213955d011SMarcel Moolenaar      * If the node is a leaf, we stick it on the toBeMade queue to
11223955d011SMarcel Moolenaar      * be looked at in a minute, otherwise we add its children to our queue
11233955d011SMarcel Moolenaar      * and go on about our business.
11243955d011SMarcel Moolenaar      */
11253955d011SMarcel Moolenaar     while (!Lst_IsEmpty(examine)) {
1126956e45f6SSimon J. Gerraty 	GNode *gn = Lst_Dequeue(examine);
11273955d011SMarcel Moolenaar 
11283955d011SMarcel Moolenaar 	if (gn->flags & REMAKE)
11293955d011SMarcel Moolenaar 	    /* We've looked at this one already */
11303955d011SMarcel Moolenaar 	    continue;
11313955d011SMarcel Moolenaar 	gn->flags |= REMAKE;
1132956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, "Make_ExpandUse: examine %s%s\n",
11333955d011SMarcel Moolenaar 	       gn->name, gn->cohort_num);
11343955d011SMarcel Moolenaar 
11352c3632d1SSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP)
11362c3632d1SSimon J. Gerraty 	    Lst_PrependAll(examine, gn->cohorts);
11373955d011SMarcel Moolenaar 
11383955d011SMarcel Moolenaar 	/*
11393955d011SMarcel Moolenaar 	 * Apply any .USE rules before looking for implicit dependencies
11403955d011SMarcel Moolenaar 	 * to make sure everything has commands that should...
11413955d011SMarcel Moolenaar 	 * Make sure that the TARGET is set, so that we can make
11423955d011SMarcel Moolenaar 	 * expansions.
11433955d011SMarcel Moolenaar 	 */
11443955d011SMarcel Moolenaar 	if (gn->type & OP_ARCHV) {
1145*e2eeea75SSimon J. Gerraty 	    char *eoa = strchr(gn->name, '(');
1146*e2eeea75SSimon J. Gerraty 	    char *eon = strchr(gn->name, ')');
11473955d011SMarcel Moolenaar 	    if (eoa == NULL || eon == NULL)
11483955d011SMarcel Moolenaar 		continue;
11493955d011SMarcel Moolenaar 	    *eoa = '\0';
11503955d011SMarcel Moolenaar 	    *eon = '\0';
11513841c287SSimon J. Gerraty 	    Var_Set(MEMBER, eoa + 1, gn);
11523841c287SSimon J. Gerraty 	    Var_Set(ARCHIVE, gn->name, gn);
11533955d011SMarcel Moolenaar 	    *eoa = '(';
11543955d011SMarcel Moolenaar 	    *eon = ')';
11553955d011SMarcel Moolenaar 	}
11563955d011SMarcel Moolenaar 
1157*e2eeea75SSimon J. Gerraty 	Dir_UpdateMTime(gn, FALSE);
1158956e45f6SSimon J. Gerraty 	Var_Set(TARGET, GNode_Path(gn), gn);
1159956e45f6SSimon J. Gerraty 	UnmarkChildren(gn);
1160956e45f6SSimon J. Gerraty 	HandleUseNodes(gn);
11613955d011SMarcel Moolenaar 
1162*e2eeea75SSimon J. Gerraty 	if (!(gn->type & OP_MADE))
11633955d011SMarcel Moolenaar 	    Suff_FindDeps(gn);
11643955d011SMarcel Moolenaar 	else {
1165*e2eeea75SSimon J. Gerraty 	    PretendAllChildrenAreMade(gn);
11663955d011SMarcel Moolenaar 	    if (gn->unmade != 0)
11673955d011SMarcel Moolenaar 		printf("Warning: %s%s still has %d unmade children\n",
11683955d011SMarcel Moolenaar 		       gn->name, gn->cohort_num, gn->unmade);
11693955d011SMarcel Moolenaar 	}
11703955d011SMarcel Moolenaar 
11713955d011SMarcel Moolenaar 	if (gn->unmade != 0)
1172*e2eeea75SSimon J. Gerraty 	    ExamineLater(examine, gn->children);
11733955d011SMarcel Moolenaar     }
11743955d011SMarcel Moolenaar 
11752c3632d1SSimon J. Gerraty     Lst_Free(examine);
11763955d011SMarcel Moolenaar }
11773955d011SMarcel Moolenaar 
1178956e45f6SSimon J. Gerraty /* Make the .WAIT node depend on the previous children */
1179956e45f6SSimon J. Gerraty static void
1180956e45f6SSimon J. Gerraty add_wait_dependency(GNodeListNode *owln, GNode *wn)
11813955d011SMarcel Moolenaar {
1182956e45f6SSimon J. Gerraty     GNodeListNode *cln;
1183956e45f6SSimon J. Gerraty     GNode *cn;
11843955d011SMarcel Moolenaar 
1185956e45f6SSimon J. Gerraty     for (cln = owln; (cn = cln->datum) != wn; cln = cln->next) {
1186956e45f6SSimon J. Gerraty 	DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n",
11873955d011SMarcel Moolenaar 	       cn->name, cn->cohort_num, wn->name);
11883955d011SMarcel Moolenaar 
1189956e45f6SSimon J. Gerraty 	/* XXX: This pattern should be factored out, it repeats often */
11902c3632d1SSimon J. Gerraty 	Lst_Append(wn->children, cn);
11913955d011SMarcel Moolenaar 	wn->unmade++;
11922c3632d1SSimon J. Gerraty 	Lst_Append(cn->parents, wn);
1193956e45f6SSimon J. Gerraty     }
11943955d011SMarcel Moolenaar }
11953955d011SMarcel Moolenaar 
1196956e45f6SSimon J. Gerraty /* Convert .WAIT nodes into dependencies. */
11973955d011SMarcel Moolenaar static void
1198956e45f6SSimon J. Gerraty Make_ProcessWait(GNodeList *targs)
11993955d011SMarcel Moolenaar {
12003955d011SMarcel Moolenaar     GNode  *pgn;		/* 'parent' node we are examining */
1201956e45f6SSimon J. Gerraty     GNodeListNode *owln;	/* Previous .WAIT node */
1202956e45f6SSimon J. Gerraty     GNodeList *examine;		/* List of targets to examine */
12033955d011SMarcel Moolenaar 
12043955d011SMarcel Moolenaar     /*
12053955d011SMarcel Moolenaar      * We need all the nodes to have a common parent in order for the
12063955d011SMarcel Moolenaar      * .WAIT and .ORDER scheduling to work.
12073955d011SMarcel Moolenaar      * Perhaps this should be done earlier...
12083955d011SMarcel Moolenaar      */
12093955d011SMarcel Moolenaar 
1210*e2eeea75SSimon J. Gerraty     pgn = GNode_New(".MAIN");
12113955d011SMarcel Moolenaar     pgn->flags = REMAKE;
12123955d011SMarcel Moolenaar     pgn->type = OP_PHONY | OP_DEPENDS;
12133955d011SMarcel Moolenaar     /* Get it displayed in the diag dumps */
12142c3632d1SSimon J. Gerraty     Lst_Prepend(Targ_List(), pgn);
12153955d011SMarcel Moolenaar 
1216956e45f6SSimon J. Gerraty     {
1217956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
1218956e45f6SSimon J. Gerraty 	for (ln = targs->first; ln != NULL; ln = ln->next) {
1219956e45f6SSimon J. Gerraty 	    GNode *cgn = ln->datum;
1220956e45f6SSimon J. Gerraty 
1221956e45f6SSimon J. Gerraty 	    Lst_Append(pgn->children, cgn);
1222956e45f6SSimon J. Gerraty 	    Lst_Append(cgn->parents, pgn);
1223956e45f6SSimon J. Gerraty 	    pgn->unmade++;
1224956e45f6SSimon J. Gerraty 	}
1225956e45f6SSimon J. Gerraty     }
12263955d011SMarcel Moolenaar 
12273955d011SMarcel Moolenaar     /* Start building with the 'dummy' .MAIN' node */
12283955d011SMarcel Moolenaar     MakeBuildChild(pgn, NULL);
12293955d011SMarcel Moolenaar 
1230956e45f6SSimon J. Gerraty     examine = Lst_New();
12312c3632d1SSimon J. Gerraty     Lst_Append(examine, pgn);
12323955d011SMarcel Moolenaar 
12333955d011SMarcel Moolenaar     while (!Lst_IsEmpty(examine)) {
1234956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
1235956e45f6SSimon J. Gerraty 
12362c3632d1SSimon J. Gerraty 	pgn = Lst_Dequeue(examine);
12373955d011SMarcel Moolenaar 
12383955d011SMarcel Moolenaar 	/* We only want to process each child-list once */
12393955d011SMarcel Moolenaar 	if (pgn->flags & DONE_WAIT)
12403955d011SMarcel Moolenaar 	    continue;
12413955d011SMarcel Moolenaar 	pgn->flags |= DONE_WAIT;
1242956e45f6SSimon J. Gerraty 	DEBUG1(MAKE, "Make_ProcessWait: examine %s\n", pgn->name);
12433955d011SMarcel Moolenaar 
12442c3632d1SSimon J. Gerraty 	if (pgn->type & OP_DOUBLEDEP)
12452c3632d1SSimon J. Gerraty 	    Lst_PrependAll(examine, pgn->cohorts);
12463955d011SMarcel Moolenaar 
1247956e45f6SSimon J. Gerraty 	owln = pgn->children->first;
1248956e45f6SSimon J. Gerraty 	for (ln = pgn->children->first; ln != NULL; ln = ln->next) {
1249956e45f6SSimon J. Gerraty 	    GNode *cgn = ln->datum;
12503955d011SMarcel Moolenaar 	    if (cgn->type & OP_WAIT) {
1251956e45f6SSimon J. Gerraty 		add_wait_dependency(owln, cgn);
12523955d011SMarcel Moolenaar 		owln = ln;
12533955d011SMarcel Moolenaar 	    } else {
12542c3632d1SSimon J. Gerraty 		Lst_Append(examine, cgn);
12553955d011SMarcel Moolenaar 	    }
12563955d011SMarcel Moolenaar 	}
12573955d011SMarcel Moolenaar     }
12583955d011SMarcel Moolenaar 
12592c3632d1SSimon J. Gerraty     Lst_Free(examine);
12603955d011SMarcel Moolenaar }
12613955d011SMarcel Moolenaar 
12623955d011SMarcel Moolenaar /*-
12633955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
12643955d011SMarcel Moolenaar  * Make_Run --
12653955d011SMarcel Moolenaar  *	Initialize the nodes to remake and the list of nodes which are
12663955d011SMarcel Moolenaar  *	ready to be made by doing a breadth-first traversal of the graph
12673955d011SMarcel Moolenaar  *	starting from the nodes in the given list. Once this traversal
12683955d011SMarcel Moolenaar  *	is finished, all the 'leaves' of the graph are in the toBeMade
12693955d011SMarcel Moolenaar  *	queue.
12703955d011SMarcel Moolenaar  *	Using this queue and the Job module, work back up the graph,
12713955d011SMarcel Moolenaar  *	calling on MakeStartJobs to keep the job table as full as
12723955d011SMarcel Moolenaar  *	possible.
12733955d011SMarcel Moolenaar  *
12743955d011SMarcel Moolenaar  * Input:
12753955d011SMarcel Moolenaar  *	targs		the initial list of targets
12763955d011SMarcel Moolenaar  *
12773955d011SMarcel Moolenaar  * Results:
12783955d011SMarcel Moolenaar  *	TRUE if work was done. FALSE otherwise.
12793955d011SMarcel Moolenaar  *
12803955d011SMarcel Moolenaar  * Side Effects:
12813955d011SMarcel Moolenaar  *	The make field of all nodes involved in the creation of the given
12823955d011SMarcel Moolenaar  *	targets is set to 1. The toBeMade list is set to contain all the
12833955d011SMarcel Moolenaar  *	'leaves' of these subgraphs.
12843955d011SMarcel Moolenaar  *-----------------------------------------------------------------------
12853955d011SMarcel Moolenaar  */
12863955d011SMarcel Moolenaar Boolean
1287956e45f6SSimon J. Gerraty Make_Run(GNodeList *targs)
12883955d011SMarcel Moolenaar {
12893955d011SMarcel Moolenaar     int errors;			/* Number of errors the Job module reports */
12903955d011SMarcel Moolenaar 
12913955d011SMarcel Moolenaar     /* Start trying to make the current targets... */
1292956e45f6SSimon J. Gerraty     toBeMade = Lst_New();
12933955d011SMarcel Moolenaar 
12943955d011SMarcel Moolenaar     Make_ExpandUse(targs);
12953955d011SMarcel Moolenaar     Make_ProcessWait(targs);
12963955d011SMarcel Moolenaar 
12973955d011SMarcel Moolenaar     if (DEBUG(MAKE)) {
1298956e45f6SSimon J. Gerraty 	 debug_printf("#***# full graph\n");
12993955d011SMarcel Moolenaar 	 Targ_PrintGraph(1);
13003955d011SMarcel Moolenaar     }
13013955d011SMarcel Moolenaar 
1302956e45f6SSimon J. Gerraty     if (opts.queryFlag) {
13033955d011SMarcel Moolenaar 	/*
13043955d011SMarcel Moolenaar 	 * We wouldn't do any work unless we could start some jobs in the
13053955d011SMarcel Moolenaar 	 * next loop... (we won't actually start any, of course, this is just
13063955d011SMarcel Moolenaar 	 * to see if any of the targets was out of date)
13073955d011SMarcel Moolenaar 	 */
13083841c287SSimon J. Gerraty 	return MakeStartJobs();
13093955d011SMarcel Moolenaar     }
13103955d011SMarcel Moolenaar     /*
13113955d011SMarcel Moolenaar      * Initialization. At the moment, no jobs are running and until some
13123955d011SMarcel Moolenaar      * get started, nothing will happen since the remaining upward
13133955d011SMarcel Moolenaar      * traversal of the graph is performed by the routines in job.c upon
13143955d011SMarcel Moolenaar      * the finishing of a job. So we fill the Job table as much as we can
13153955d011SMarcel Moolenaar      * before going into our loop.
13163955d011SMarcel Moolenaar      */
13173955d011SMarcel Moolenaar     (void)MakeStartJobs();
13183955d011SMarcel Moolenaar 
13193955d011SMarcel Moolenaar     /*
13203955d011SMarcel Moolenaar      * Main Loop: The idea here is that the ending of jobs will take
13213955d011SMarcel Moolenaar      * care of the maintenance of data structures and the waiting for output
13223955d011SMarcel Moolenaar      * will cause us to be idle most of the time while our children run as
13233955d011SMarcel Moolenaar      * much as possible. Because the job table is kept as full as possible,
13243955d011SMarcel Moolenaar      * the only time when it will be empty is when all the jobs which need
13253955d011SMarcel Moolenaar      * running have been run, so that is the end condition of this loop.
13263955d011SMarcel Moolenaar      * Note that the Job module will exit if there were any errors unless the
13273955d011SMarcel Moolenaar      * keepgoing flag was given.
13283955d011SMarcel Moolenaar      */
13293955d011SMarcel Moolenaar     while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) {
13303955d011SMarcel Moolenaar 	Job_CatchOutput();
13313955d011SMarcel Moolenaar 	(void)MakeStartJobs();
13323955d011SMarcel Moolenaar     }
13333955d011SMarcel Moolenaar 
13343955d011SMarcel Moolenaar     errors = Job_Finish();
13353955d011SMarcel Moolenaar 
13363955d011SMarcel Moolenaar     /*
13373955d011SMarcel Moolenaar      * Print the final status of each target. E.g. if it wasn't made
13383955d011SMarcel Moolenaar      * because some inferior reported an error.
13393955d011SMarcel Moolenaar      */
1340956e45f6SSimon J. Gerraty     DEBUG1(MAKE, "done: errors %d\n", errors);
13413955d011SMarcel Moolenaar     if (errors == 0) {
1342956e45f6SSimon J. Gerraty 	MakePrintStatusList(targs, &errors);
13433955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
1344956e45f6SSimon J. Gerraty 	    debug_printf("done: errors %d\n", errors);
1345*e2eeea75SSimon J. Gerraty 	    if (errors > 0)
13463955d011SMarcel Moolenaar 		Targ_PrintGraph(4);
13473955d011SMarcel Moolenaar 	}
13483955d011SMarcel Moolenaar     }
1349*e2eeea75SSimon J. Gerraty     return errors > 0;
13503955d011SMarcel Moolenaar }
1351