xref: /freebsd/contrib/bmake/make.c (revision d5e0a182)
1d5e0a182SSimon J. Gerraty /*	$NetBSD: make.c,v 1.262 2024/01/05 23:22:06 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:
75b0c40a00SSimon 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
81dba7b0efSSimon J. Gerraty  *			of the IMPSRC variable, etc. Place the parent on the
82dba7b0efSSimon 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  *
88b0c40a00SSimon J. Gerraty  *	GNode_SetLocalVars
89b0c40a00SSimon J. Gerraty  *			Set up the various local variables for a
903955d011SMarcel Moolenaar  *			target, including the .ALLSRC variable, making
913955d011SMarcel Moolenaar  *			sure that any variable that needs to exist
923955d011SMarcel Moolenaar  *			at the very least has the empty value.
933955d011SMarcel Moolenaar  *
94e2eeea75SSimon J. Gerraty  *	GNode_IsOODate	Determine if a target is out-of-date.
953955d011SMarcel Moolenaar  *
963955d011SMarcel Moolenaar  *	Make_HandleUse	See if a child is a .USE node for a parent
973955d011SMarcel Moolenaar  *			and perform the .USE actions if so.
983955d011SMarcel Moolenaar  *
993955d011SMarcel Moolenaar  *	Make_ExpandUse	Expand .USE nodes
1003955d011SMarcel Moolenaar  */
1013955d011SMarcel Moolenaar 
1023955d011SMarcel Moolenaar #include "make.h"
1033955d011SMarcel Moolenaar #include "dir.h"
1043955d011SMarcel Moolenaar #include "job.h"
1053955d011SMarcel Moolenaar 
106956e45f6SSimon J. Gerraty /*	"@(#)make.c	8.1 (Berkeley) 6/6/93"	*/
107d5e0a182SSimon J. Gerraty MAKE_RCSID("$NetBSD: make.c,v 1.262 2024/01/05 23:22:06 rillig Exp $");
1083955d011SMarcel Moolenaar 
109956e45f6SSimon J. Gerraty /* Sequence # to detect recursion. */
110e2eeea75SSimon J. Gerraty static unsigned int checked_seqno = 1;
111956e45f6SSimon J. Gerraty 
11206b9b3e0SSimon J. Gerraty /*
11306b9b3e0SSimon J. Gerraty  * The current fringe of the graph.
114956e45f6SSimon J. Gerraty  * These are nodes which await examination by MakeOODate.
11506b9b3e0SSimon J. Gerraty  * It is added to by Make_Update and subtracted from by MakeStartJobs
11606b9b3e0SSimon J. Gerraty  */
11706b9b3e0SSimon J. Gerraty static GNodeList toBeMade = LST_INIT;
118956e45f6SSimon J. Gerraty 
1193955d011SMarcel Moolenaar 
120956e45f6SSimon J. Gerraty void
debug_printf(const char * fmt,...)121956e45f6SSimon J. Gerraty debug_printf(const char *fmt, ...)
122956e45f6SSimon J. Gerraty {
1239f45a3c8SSimon J. Gerraty 	va_list ap;
124956e45f6SSimon J. Gerraty 
1259f45a3c8SSimon J. Gerraty 	va_start(ap, fmt);
1269f45a3c8SSimon J. Gerraty 	vfprintf(opts.debug_file, fmt, ap);
1279f45a3c8SSimon J. Gerraty 	va_end(ap);
128956e45f6SSimon J. Gerraty }
129956e45f6SSimon J. Gerraty 
13012904384SSimon J. Gerraty static const char *
GNodeType_ToString(GNodeType type,void ** freeIt)13112904384SSimon J. Gerraty GNodeType_ToString(GNodeType type, void **freeIt)
13212904384SSimon J. Gerraty {
13312904384SSimon J. Gerraty 	Buffer buf;
1342c3632d1SSimon J. Gerraty 
135d5e0a182SSimon J. Gerraty 	Buf_Init(&buf);
13612904384SSimon J. Gerraty #define ADD(flag) Buf_AddFlag(&buf, (type & (flag)) != OP_NONE, #flag)
13712904384SSimon J. Gerraty 	ADD(OP_DEPENDS);
13812904384SSimon J. Gerraty 	ADD(OP_FORCE);
13912904384SSimon J. Gerraty 	ADD(OP_DOUBLEDEP);
14012904384SSimon J. Gerraty 	ADD(OP_OPTIONAL);
14112904384SSimon J. Gerraty 	ADD(OP_USE);
14212904384SSimon J. Gerraty 	ADD(OP_EXEC);
14312904384SSimon J. Gerraty 	ADD(OP_IGNORE);
14412904384SSimon J. Gerraty 	ADD(OP_PRECIOUS);
14512904384SSimon J. Gerraty 	ADD(OP_SILENT);
14612904384SSimon J. Gerraty 	ADD(OP_MAKE);
14712904384SSimon J. Gerraty 	ADD(OP_JOIN);
14812904384SSimon J. Gerraty 	ADD(OP_MADE);
14912904384SSimon J. Gerraty 	ADD(OP_SPECIAL);
15012904384SSimon J. Gerraty 	ADD(OP_USEBEFORE);
15112904384SSimon J. Gerraty 	ADD(OP_INVISIBLE);
15212904384SSimon J. Gerraty 	ADD(OP_NOTMAIN);
15312904384SSimon J. Gerraty 	ADD(OP_PHONY);
15412904384SSimon J. Gerraty 	ADD(OP_NOPATH);
15512904384SSimon J. Gerraty 	ADD(OP_WAIT);
15612904384SSimon J. Gerraty 	ADD(OP_NOMETA);
15712904384SSimon J. Gerraty 	ADD(OP_META);
15812904384SSimon J. Gerraty 	ADD(OP_NOMETA_CMP);
15912904384SSimon J. Gerraty 	ADD(OP_SUBMAKE);
16012904384SSimon J. Gerraty 	ADD(OP_TRANSFORM);
16112904384SSimon J. Gerraty 	ADD(OP_MEMBER);
16212904384SSimon J. Gerraty 	ADD(OP_LIB);
16312904384SSimon J. Gerraty 	ADD(OP_ARCHV);
16412904384SSimon J. Gerraty 	ADD(OP_HAS_COMMANDS);
16512904384SSimon J. Gerraty 	ADD(OP_SAVE_CMDS);
16612904384SSimon J. Gerraty 	ADD(OP_DEPS_FOUND);
16712904384SSimon J. Gerraty 	ADD(OP_MARK);
16812904384SSimon J. Gerraty #undef ADD
16912904384SSimon J. Gerraty 	return buf.len == 0 ? "none" : (*freeIt = Buf_DoneData(&buf));
17012904384SSimon J. Gerraty }
17112904384SSimon J. Gerraty 
17212904384SSimon J. Gerraty static const char *
GNodeFlags_ToString(GNodeFlags flags,void ** freeIt)17312904384SSimon J. Gerraty GNodeFlags_ToString(GNodeFlags flags, void **freeIt)
17412904384SSimon J. Gerraty {
17512904384SSimon J. Gerraty 	Buffer buf;
17612904384SSimon J. Gerraty 
177d5e0a182SSimon J. Gerraty 	Buf_Init(&buf);
1784fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.remake, "REMAKE");
1794fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.childMade, "CHILDMADE");
1804fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.force, "FORCE");
1814fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.doneWait, "DONE_WAIT");
1824fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.doneOrder, "DONE_ORDER");
1834fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.fromDepend, "FROM_DEPEND");
1844fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.doneAllsrc, "DONE_ALLSRC");
1854fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.cycle, "CYCLE");
1864fde40d9SSimon J. Gerraty 	Buf_AddFlag(&buf, flags.doneCycle, "DONECYCLE");
18712904384SSimon J. Gerraty 	return buf.len == 0 ? "none" : (*freeIt = Buf_DoneData(&buf));
18812904384SSimon J. Gerraty }
1892c3632d1SSimon J. Gerraty 
1902c3632d1SSimon J. Gerraty void
GNode_FprintDetails(FILE * f,const char * prefix,const GNode * gn,const char * suffix)1912c3632d1SSimon J. Gerraty GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn,
1922c3632d1SSimon J. Gerraty 		    const char *suffix)
1932c3632d1SSimon J. Gerraty {
19412904384SSimon J. Gerraty 	void *type_freeIt = NULL;
19512904384SSimon J. Gerraty 	void *flags_freeIt = NULL;
1962c3632d1SSimon J. Gerraty 
197dba7b0efSSimon J. Gerraty 	fprintf(f, "%s%s, type %s, flags %s%s",
1982c3632d1SSimon J. Gerraty 	    prefix,
199dba7b0efSSimon J. Gerraty 	    GNodeMade_Name(gn->made),
20012904384SSimon J. Gerraty 	    GNodeType_ToString(gn->type, &type_freeIt),
20112904384SSimon J. Gerraty 	    GNodeFlags_ToString(gn->flags, &flags_freeIt),
2022c3632d1SSimon J. Gerraty 	    suffix);
20312904384SSimon J. Gerraty 	free(type_freeIt);
20412904384SSimon J. Gerraty 	free(flags_freeIt);
2052c3632d1SSimon J. Gerraty }
2062c3632d1SSimon J. Gerraty 
207b0c40a00SSimon J. Gerraty bool
GNode_ShouldExecute(GNode * gn)208956e45f6SSimon J. Gerraty GNode_ShouldExecute(GNode *gn)
209956e45f6SSimon J. Gerraty {
21006b9b3e0SSimon J. Gerraty 	return !((gn->type & OP_MAKE)
21106b9b3e0SSimon J. Gerraty 	    ? opts.noRecursiveExecute
21206b9b3e0SSimon J. Gerraty 	    : opts.noExecute);
213956e45f6SSimon J. Gerraty }
214956e45f6SSimon J. Gerraty 
215956e45f6SSimon J. Gerraty /* Update the youngest child of the node, according to the given child. */
216956e45f6SSimon J. Gerraty void
GNode_UpdateYoungestChild(GNode * gn,GNode * cgn)217e2eeea75SSimon J. Gerraty GNode_UpdateYoungestChild(GNode *gn, GNode *cgn)
2183955d011SMarcel Moolenaar {
219e2eeea75SSimon J. Gerraty 	if (gn->youngestChild == NULL || cgn->mtime > gn->youngestChild->mtime)
220e2eeea75SSimon J. Gerraty 		gn->youngestChild = cgn;
2213955d011SMarcel Moolenaar }
222e2eeea75SSimon J. Gerraty 
223b0c40a00SSimon J. Gerraty static bool
IsOODateRegular(GNode * gn)224e2eeea75SSimon J. Gerraty IsOODateRegular(GNode *gn)
225e2eeea75SSimon J. Gerraty {
226e2eeea75SSimon J. Gerraty 	/* These rules are inherited from the original Make. */
227e2eeea75SSimon J. Gerraty 
228e2eeea75SSimon J. Gerraty 	if (gn->youngestChild != NULL) {
229e2eeea75SSimon J. Gerraty 		if (gn->mtime < gn->youngestChild->mtime) {
230e2eeea75SSimon J. Gerraty 			DEBUG1(MAKE, "modified before source \"%s\"...",
231e2eeea75SSimon J. Gerraty 			    GNode_Path(gn->youngestChild));
232b0c40a00SSimon J. Gerraty 			return true;
233e2eeea75SSimon J. Gerraty 		}
234b0c40a00SSimon J. Gerraty 		return false;
235e2eeea75SSimon J. Gerraty 	}
236e2eeea75SSimon J. Gerraty 
237e2eeea75SSimon J. Gerraty 	if (gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) {
23806b9b3e0SSimon J. Gerraty 		DEBUG0(MAKE, "nonexistent and no sources...");
239b0c40a00SSimon J. Gerraty 		return true;
240e2eeea75SSimon J. Gerraty 	}
241e2eeea75SSimon J. Gerraty 
242e2eeea75SSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP) {
243e2eeea75SSimon J. Gerraty 		DEBUG0(MAKE, ":: operator and no sources...");
244b0c40a00SSimon J. Gerraty 		return true;
245e2eeea75SSimon J. Gerraty 	}
246e2eeea75SSimon J. Gerraty 
247b0c40a00SSimon J. Gerraty 	return false;
2483955d011SMarcel Moolenaar }
2493955d011SMarcel Moolenaar 
25006b9b3e0SSimon J. Gerraty /*
25106b9b3e0SSimon J. Gerraty  * See if the node is out of date with respect to its sources.
2523955d011SMarcel Moolenaar  *
2533955d011SMarcel Moolenaar  * Used by Make_Run when deciding which nodes to place on the
254956e45f6SSimon J. Gerraty  * toBeMade queue initially and by Make_Update to screen out .USE and
255956e45f6SSimon J. Gerraty  * .EXEC nodes. In the latter case, however, any other sort of node
2563955d011SMarcel Moolenaar  * must be considered out-of-date since at least one of its children
2573955d011SMarcel Moolenaar  * will have been recreated.
2583955d011SMarcel Moolenaar  *
259956e45f6SSimon J. Gerraty  * The mtime field of the node and the youngestChild field of its parents
260956e45f6SSimon J. Gerraty  * may be changed.
2613955d011SMarcel Moolenaar  */
262b0c40a00SSimon J. Gerraty bool
GNode_IsOODate(GNode * gn)263e2eeea75SSimon J. Gerraty GNode_IsOODate(GNode *gn)
2643955d011SMarcel Moolenaar {
265b0c40a00SSimon J. Gerraty 	bool oodate;
2663955d011SMarcel Moolenaar 
2673955d011SMarcel Moolenaar 	/*
2683955d011SMarcel Moolenaar 	 * Certain types of targets needn't even be sought as their datedness
2693955d011SMarcel Moolenaar 	 * doesn't depend on their modification time...
2703955d011SMarcel Moolenaar 	 */
271e2eeea75SSimon J. Gerraty 	if (!(gn->type & (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC))) {
272b0c40a00SSimon J. Gerraty 		Dir_UpdateMTime(gn, true);
2733955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
274e2eeea75SSimon J. Gerraty 			if (gn->mtime != 0)
27506b9b3e0SSimon J. Gerraty 				debug_printf("modified %s...",
27606b9b3e0SSimon J. Gerraty 				    Targ_FmtTime(gn->mtime));
277e2eeea75SSimon J. Gerraty 			else
27806b9b3e0SSimon J. Gerraty 				debug_printf("nonexistent...");
2793955d011SMarcel Moolenaar 		}
2803955d011SMarcel Moolenaar 	}
2813955d011SMarcel Moolenaar 
2823955d011SMarcel Moolenaar 	/*
2833955d011SMarcel Moolenaar 	 * A target is remade in one of the following circumstances:
28406b9b3e0SSimon J. Gerraty 	 *
28506b9b3e0SSimon J. Gerraty 	 *	its modification time is smaller than that of its youngest
28606b9b3e0SSimon J. Gerraty 	 *	child and it would actually be run (has commands or is not
28706b9b3e0SSimon J. Gerraty 	 *	GNode_IsTarget)
28806b9b3e0SSimon J. Gerraty 	 *
2893955d011SMarcel Moolenaar 	 *	it's the object of a force operator
2903955d011SMarcel Moolenaar 	 *
29106b9b3e0SSimon J. Gerraty 	 *	it has no children, was on the lhs of an operator and doesn't
29206b9b3e0SSimon J. Gerraty 	 *	exist already.
2933955d011SMarcel Moolenaar 	 *
29406b9b3e0SSimon J. Gerraty 	 * Libraries are only considered out-of-date if the archive module
29506b9b3e0SSimon J. Gerraty 	 * says they are.
29606b9b3e0SSimon J. Gerraty 	 *
29706b9b3e0SSimon J. Gerraty 	 * These weird rules are brought to you by Backward-Compatibility
29806b9b3e0SSimon J. Gerraty 	 * and the strange people who wrote 'Make'.
2993955d011SMarcel Moolenaar 	 */
3003955d011SMarcel Moolenaar 	if (gn->type & (OP_USE | OP_USEBEFORE)) {
3013955d011SMarcel Moolenaar 		/*
3023955d011SMarcel Moolenaar 		 * If the node is a USE node it is *never* out of date
3033955d011SMarcel Moolenaar 		 * no matter *what*.
3043955d011SMarcel Moolenaar 		 */
305956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, ".USE node...");
306b0c40a00SSimon J. Gerraty 		oodate = false;
307e2eeea75SSimon J. Gerraty 	} else if ((gn->type & OP_LIB) && (gn->mtime == 0 || Arch_IsLib(gn))) {
308956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, "library...");
3093955d011SMarcel Moolenaar 
3103955d011SMarcel Moolenaar 		/*
3113955d011SMarcel Moolenaar 		 * always out of date if no children and :: target
31206b9b3e0SSimon J. Gerraty 		 * or nonexistent.
3133955d011SMarcel Moolenaar 		 */
3143955d011SMarcel Moolenaar 		oodate = (gn->mtime == 0 || Arch_LibOODate(gn) ||
31506b9b3e0SSimon J. Gerraty 			  (gn->youngestChild == NULL &&
31606b9b3e0SSimon J. Gerraty 			   (gn->type & OP_DOUBLEDEP)));
3173955d011SMarcel Moolenaar 	} else if (gn->type & OP_JOIN) {
3183955d011SMarcel Moolenaar 		/*
3193955d011SMarcel Moolenaar 		 * A target with the .JOIN attribute is only considered
3203955d011SMarcel Moolenaar 		 * out-of-date if any of its children was out-of-date.
3213955d011SMarcel Moolenaar 		 */
322956e45f6SSimon J. Gerraty 		DEBUG0(MAKE, ".JOIN node...");
32306b9b3e0SSimon J. Gerraty 		DEBUG1(MAKE, "source %smade...",
32412904384SSimon J. Gerraty 		    gn->flags.childMade ? "" : "not ");
32512904384SSimon J. Gerraty 		oodate = gn->flags.childMade;
3263955d011SMarcel Moolenaar 	} else if (gn->type & (OP_FORCE | OP_EXEC | OP_PHONY)) {
3273955d011SMarcel Moolenaar 		/*
32806b9b3e0SSimon J. Gerraty 		 * A node which is the object of the force (!) operator or
32906b9b3e0SSimon J. Gerraty 		 * which has the .EXEC attribute is always considered
33006b9b3e0SSimon J. Gerraty 		 * out-of-date.
3313955d011SMarcel Moolenaar 		 */
3323955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
333d5e0a182SSimon J. Gerraty 			if (gn->type & OP_FORCE)
334956e45f6SSimon J. Gerraty 				debug_printf("! operator...");
335d5e0a182SSimon J. Gerraty 			else if (gn->type & OP_PHONY)
336956e45f6SSimon J. Gerraty 				debug_printf(".PHONY node...");
337d5e0a182SSimon J. Gerraty 			else
338956e45f6SSimon J. Gerraty 				debug_printf(".EXEC node...");
3393955d011SMarcel Moolenaar 		}
340b0c40a00SSimon J. Gerraty 		oodate = true;
341e2eeea75SSimon J. Gerraty 	} else if (IsOODateRegular(gn)) {
342b0c40a00SSimon J. Gerraty 		oodate = true;
3433955d011SMarcel Moolenaar 	} else {
3443955d011SMarcel Moolenaar 		/*
34506b9b3e0SSimon J. Gerraty 		 * When a nonexistent child with no sources
3463955d011SMarcel Moolenaar 		 * (such as a typically used FORCE source) has been made and
3473955d011SMarcel Moolenaar 		 * the target of the child (usually a directory) has the same
34806b9b3e0SSimon J. Gerraty 		 * timestamp as the timestamp just given to the nonexistent
34906b9b3e0SSimon J. Gerraty 		 * child after it was considered made.
3503955d011SMarcel Moolenaar 		 */
3513955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
35212904384SSimon J. Gerraty 			if (gn->flags.force)
353956e45f6SSimon J. Gerraty 				debug_printf("non existing child...");
3543955d011SMarcel Moolenaar 		}
35512904384SSimon J. Gerraty 		oodate = gn->flags.force;
3563955d011SMarcel Moolenaar 	}
3573955d011SMarcel Moolenaar 
3583955d011SMarcel Moolenaar #ifdef USE_META
3599f45a3c8SSimon J. Gerraty 	if (useMeta)
3603955d011SMarcel Moolenaar 		oodate = meta_oodate(gn, oodate);
3613955d011SMarcel Moolenaar #endif
3623955d011SMarcel Moolenaar 
3633955d011SMarcel Moolenaar 	/*
3643955d011SMarcel Moolenaar 	 * If the target isn't out-of-date, the parents need to know its
3653955d011SMarcel Moolenaar 	 * modification time. Note that targets that appear to be out-of-date
366956e45f6SSimon J. Gerraty 	 * but aren't, because they have no commands and are GNode_IsTarget,
36706b9b3e0SSimon J. Gerraty 	 * have their mtime stay below their children's mtime to keep parents
36806b9b3e0SSimon J. Gerraty 	 * from thinking they're out-of-date.
3693955d011SMarcel Moolenaar 	 */
3703955d011SMarcel Moolenaar 	if (!oodate) {
371956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
37206b9b3e0SSimon J. Gerraty 		for (ln = gn->parents.first; ln != NULL; ln = ln->next)
373e2eeea75SSimon J. Gerraty 			GNode_UpdateYoungestChild(ln->datum, gn);
3743955d011SMarcel Moolenaar 	}
3753955d011SMarcel Moolenaar 
3763841c287SSimon J. Gerraty 	return oodate;
3773955d011SMarcel Moolenaar }
3782c3632d1SSimon J. Gerraty 
379e2eeea75SSimon J. Gerraty static void
PretendAllChildrenAreMade(GNode * pgn)380e2eeea75SSimon J. Gerraty PretendAllChildrenAreMade(GNode *pgn)
3813955d011SMarcel Moolenaar {
382e2eeea75SSimon J. Gerraty 	GNodeListNode *ln;
3833955d011SMarcel Moolenaar 
38406b9b3e0SSimon J. Gerraty 	for (ln = pgn->children.first; ln != NULL; ln = ln->next) {
385e2eeea75SSimon J. Gerraty 		GNode *cgn = ln->datum;
3862c3632d1SSimon J. Gerraty 
38706b9b3e0SSimon J. Gerraty 		/* This may also update cgn->path. */
388b0c40a00SSimon J. Gerraty 		Dir_UpdateMTime(cgn, false);
389e2eeea75SSimon J. Gerraty 		GNode_UpdateYoungestChild(pgn, cgn);
3903955d011SMarcel Moolenaar 		pgn->unmade--;
391e2eeea75SSimon J. Gerraty 	}
3923955d011SMarcel Moolenaar }
3932c3632d1SSimon J. Gerraty 
39406b9b3e0SSimon J. Gerraty /*
39506b9b3e0SSimon J. Gerraty  * Called by Make_Run and SuffApplyTransform on the downward pass to handle
3962c3632d1SSimon J. Gerraty  * .USE and transformation nodes, by copying the child node's commands, type
3972c3632d1SSimon J. Gerraty  * flags and children to the parent node.
3983955d011SMarcel Moolenaar  *
3992c3632d1SSimon J. Gerraty  * A .USE node is much like an explicit transformation rule, except its
4002c3632d1SSimon J. Gerraty  * commands are always added to the target node, even if the target already
4012c3632d1SSimon J. Gerraty  * has commands.
4023955d011SMarcel Moolenaar  *
4033955d011SMarcel Moolenaar  * Input:
404956e45f6SSimon J. Gerraty  *	cgn		The source node, which is either a .USE/.USEBEFORE
405956e45f6SSimon J. Gerraty  *			node or a transformation node (OP_TRANSFORM).
406956e45f6SSimon J. Gerraty  *	pgn		The target node
4073955d011SMarcel Moolenaar  */
4083955d011SMarcel Moolenaar void
Make_HandleUse(GNode * cgn,GNode * pgn)4093955d011SMarcel Moolenaar Make_HandleUse(GNode *cgn, GNode *pgn)
4103955d011SMarcel Moolenaar {
411956e45f6SSimon J. Gerraty 	GNodeListNode *ln;	/* An element in the children list */
4123955d011SMarcel Moolenaar 
4133955d011SMarcel Moolenaar #ifdef DEBUG_SRC
414e2eeea75SSimon J. Gerraty 	if (!(cgn->type & (OP_USE | OP_USEBEFORE | OP_TRANSFORM))) {
41506b9b3e0SSimon J. Gerraty 		debug_printf("Make_HandleUse: called for plain node %s\n",
41606b9b3e0SSimon J. Gerraty 		    cgn->name);
41706b9b3e0SSimon J. Gerraty 		/* XXX: debug mode should not affect control flow */
41806b9b3e0SSimon J. Gerraty 		return;
4193955d011SMarcel Moolenaar 	}
4203955d011SMarcel Moolenaar #endif
4213955d011SMarcel Moolenaar 
42206b9b3e0SSimon J. Gerraty 	if ((cgn->type & (OP_USE | OP_USEBEFORE)) ||
42306b9b3e0SSimon J. Gerraty 	    Lst_IsEmpty(&pgn->commands)) {
4243955d011SMarcel Moolenaar 		if (cgn->type & OP_USEBEFORE) {
4252c3632d1SSimon J. Gerraty 			/* .USEBEFORE */
42606b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&pgn->commands, &cgn->commands);
4273955d011SMarcel Moolenaar 		} else {
4282c3632d1SSimon J. Gerraty 			/* .USE, or target has no commands */
42906b9b3e0SSimon J. Gerraty 			Lst_AppendAll(&pgn->commands, &cgn->commands);
4303955d011SMarcel Moolenaar 		}
4313955d011SMarcel Moolenaar 	}
4323955d011SMarcel Moolenaar 
43306b9b3e0SSimon J. Gerraty 	for (ln = cgn->children.first; ln != NULL; ln = ln->next) {
434956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
4353955d011SMarcel Moolenaar 
4363955d011SMarcel Moolenaar 		/*
4373955d011SMarcel Moolenaar 		 * Expand variables in the .USE node's name
4383955d011SMarcel Moolenaar 		 * and save the unexpanded form.
4393955d011SMarcel Moolenaar 		 * We don't need to do this for commands.
4403955d011SMarcel Moolenaar 		 * They get expanded properly when we execute.
4413955d011SMarcel Moolenaar 		 */
442d5e0a182SSimon J. Gerraty 		if (gn->uname == NULL)
4433955d011SMarcel Moolenaar 			gn->uname = gn->name;
444d5e0a182SSimon J. Gerraty 		else
4453955d011SMarcel Moolenaar 			free(gn->name);
4468c973ee2SSimon J. Gerraty 		gn->name = Var_Subst(gn->uname, pgn, VARE_WANTRES);
447956e45f6SSimon J. Gerraty 		/* TODO: handle errors */
44806b9b3e0SSimon J. Gerraty 		if (gn->uname != NULL && strcmp(gn->name, gn->uname) != 0) {
4493955d011SMarcel Moolenaar 			/* See if we have a target for this node. */
450956e45f6SSimon J. Gerraty 			GNode *tgn = Targ_FindNode(gn->name);
4513955d011SMarcel Moolenaar 			if (tgn != NULL)
4523955d011SMarcel Moolenaar 				gn = tgn;
4533955d011SMarcel Moolenaar 		}
4543955d011SMarcel Moolenaar 
45506b9b3e0SSimon J. Gerraty 		Lst_Append(&pgn->children, gn);
45606b9b3e0SSimon J. Gerraty 		Lst_Append(&gn->parents, pgn);
457956e45f6SSimon J. Gerraty 		pgn->unmade++;
4583955d011SMarcel Moolenaar 	}
4593955d011SMarcel Moolenaar 
46006b9b3e0SSimon J. Gerraty 	pgn->type |=
4614fde40d9SSimon J. Gerraty 	    cgn->type & (unsigned)~(OP_OPMASK | OP_USE | OP_USEBEFORE | OP_TRANSFORM);
4623955d011SMarcel Moolenaar }
4633955d011SMarcel Moolenaar 
46406b9b3e0SSimon J. Gerraty /*
46506b9b3e0SSimon J. Gerraty  * Used by Make_Run on the downward pass to handle .USE nodes. Should be
466956e45f6SSimon J. Gerraty  * called before the children are enqueued to be looked at by MakeAddChild.
467956e45f6SSimon J. Gerraty  *
468956e45f6SSimon J. Gerraty  * For a .USE child, the commands, type flags and children are copied to the
469956e45f6SSimon J. Gerraty  * parent node, and since the relation to the .USE node is then no longer
470956e45f6SSimon J. Gerraty  * needed, that relation is removed.
4713955d011SMarcel Moolenaar  *
4723955d011SMarcel Moolenaar  * Input:
473956e45f6SSimon J. Gerraty  *	cgn		the child, which may be a .USE node
474956e45f6SSimon J. Gerraty  *	pgn		the current parent
4753955d011SMarcel Moolenaar  */
476956e45f6SSimon J. Gerraty static void
MakeHandleUse(GNode * cgn,GNode * pgn,GNodeListNode * ln)477956e45f6SSimon J. Gerraty MakeHandleUse(GNode *cgn, GNode *pgn, GNodeListNode *ln)
4783955d011SMarcel Moolenaar {
479b0c40a00SSimon J. Gerraty 	bool unmarked;
4803955d011SMarcel Moolenaar 
481e2eeea75SSimon J. Gerraty 	unmarked = !(cgn->type & OP_MARK);
4823955d011SMarcel Moolenaar 	cgn->type |= OP_MARK;
4833955d011SMarcel Moolenaar 
484e2eeea75SSimon J. Gerraty 	if (!(cgn->type & (OP_USE | OP_USEBEFORE)))
485956e45f6SSimon J. Gerraty 		return;
4863955d011SMarcel Moolenaar 
4873955d011SMarcel Moolenaar 	if (unmarked)
4883955d011SMarcel Moolenaar 		Make_HandleUse(cgn, pgn);
4893955d011SMarcel Moolenaar 
4903955d011SMarcel Moolenaar 	/*
4913955d011SMarcel Moolenaar 	 * This child node is now "made", so we decrement the count of
4923955d011SMarcel Moolenaar 	 * unmade children in the parent... We also remove the child
4933955d011SMarcel Moolenaar 	 * from the parent's list to accurately reflect the number of decent
4943955d011SMarcel Moolenaar 	 * children the parent has. This is used by Make_Run to decide
4953955d011SMarcel Moolenaar 	 * whether to queue the parent or examine its children...
4963955d011SMarcel Moolenaar 	 */
49706b9b3e0SSimon J. Gerraty 	Lst_Remove(&pgn->children, ln);
4983955d011SMarcel Moolenaar 	pgn->unmade--;
4993955d011SMarcel Moolenaar }
500956e45f6SSimon J. Gerraty 
501956e45f6SSimon J. Gerraty static void
HandleUseNodes(GNode * gn)502956e45f6SSimon J. Gerraty HandleUseNodes(GNode *gn)
503956e45f6SSimon J. Gerraty {
504956e45f6SSimon J. Gerraty 	GNodeListNode *ln, *nln;
50506b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = nln) {
506956e45f6SSimon J. Gerraty 		nln = ln->next;
507956e45f6SSimon J. Gerraty 		MakeHandleUse(ln->datum, gn, ln);
508956e45f6SSimon J. Gerraty 	}
5093955d011SMarcel Moolenaar }
5103955d011SMarcel Moolenaar 
5113955d011SMarcel Moolenaar 
51206b9b3e0SSimon J. Gerraty /*
51306b9b3e0SSimon J. Gerraty  * Check the modification time of a gnode, and update it if necessary.
51406b9b3e0SSimon J. Gerraty  * Return 0 if the gnode does not exist, or its filesystem time if it does.
51506b9b3e0SSimon J. Gerraty  */
5163955d011SMarcel Moolenaar time_t
Make_Recheck(GNode * gn)5173955d011SMarcel Moolenaar Make_Recheck(GNode *gn)
5183955d011SMarcel Moolenaar {
519e2eeea75SSimon J. Gerraty 	time_t mtime;
520e2eeea75SSimon J. Gerraty 
521b0c40a00SSimon J. Gerraty 	Dir_UpdateMTime(gn, true);
522e2eeea75SSimon J. Gerraty 	mtime = gn->mtime;
5233955d011SMarcel Moolenaar 
5243955d011SMarcel Moolenaar #ifndef RECHECK
5253955d011SMarcel Moolenaar 	/*
5263955d011SMarcel Moolenaar 	 * We can't re-stat the thing, but we can at least take care of rules
5273955d011SMarcel Moolenaar 	 * where a target depends on a source that actually creates the
5283955d011SMarcel Moolenaar 	 * target, but only if it has changed, e.g.
5293955d011SMarcel Moolenaar 	 *
5303955d011SMarcel Moolenaar 	 * parse.h : parse.o
5313955d011SMarcel Moolenaar 	 *
5323955d011SMarcel Moolenaar 	 * parse.o : parse.y
5333955d011SMarcel Moolenaar 	 *		yacc -d parse.y
5343955d011SMarcel Moolenaar 	 *		cc -c y.tab.c
5353955d011SMarcel Moolenaar 	 *		mv y.tab.o parse.o
5363955d011SMarcel Moolenaar 	 *		cmp -s y.tab.h parse.h || mv y.tab.h parse.h
5373955d011SMarcel Moolenaar 	 *
5383955d011SMarcel Moolenaar 	 * In this case, if the definitions produced by yacc haven't changed
5393955d011SMarcel Moolenaar 	 * from before, parse.h won't have been updated and gn->mtime will
5403955d011SMarcel Moolenaar 	 * reflect the current modification time for parse.h. This is
541e2eeea75SSimon J. Gerraty 	 * something of a kludge, I admit, but it's a useful one.
5423955d011SMarcel Moolenaar 	 *
543e2eeea75SSimon J. Gerraty 	 * XXX: People like to use a rule like "FRC:" to force things that
544e2eeea75SSimon J. Gerraty 	 * depend on FRC to be made, so we have to check for gn->children
545e2eeea75SSimon J. Gerraty 	 * being empty as well.
5463955d011SMarcel Moolenaar 	 */
547d5e0a182SSimon J. Gerraty 	if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children))
5483955d011SMarcel Moolenaar 		gn->mtime = now;
5493955d011SMarcel Moolenaar #else
5503955d011SMarcel Moolenaar 	/*
5513955d011SMarcel Moolenaar 	 * This is what Make does and it's actually a good thing, as it
5523955d011SMarcel Moolenaar 	 * allows rules like
5533955d011SMarcel Moolenaar 	 *
5543955d011SMarcel Moolenaar 	 *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
5553955d011SMarcel Moolenaar 	 *
5563955d011SMarcel Moolenaar 	 * to function as intended. Unfortunately, thanks to the stateless
5573955d011SMarcel Moolenaar 	 * nature of NFS (by which I mean the loose coupling of two clients
55806b9b3e0SSimon J. Gerraty 	 * using the same file from a common server), there are times when
55906b9b3e0SSimon J. Gerraty 	 * the modification time of a file created on a remote machine
56006b9b3e0SSimon J. Gerraty 	 * will not be modified before the local stat() implied by the
56106b9b3e0SSimon J. Gerraty 	 * Dir_UpdateMTime occurs, thus leading us to believe that the file
5623955d011SMarcel Moolenaar 	 * is unchanged, wreaking havoc with files that depend on this one.
5633955d011SMarcel Moolenaar 	 *
5643955d011SMarcel Moolenaar 	 * I have decided it is better to make too much than to make too
5653955d011SMarcel Moolenaar 	 * little, so this stuff is commented out unless you're sure it's ok.
5663955d011SMarcel Moolenaar 	 * -- ardeb 1/12/88
5673955d011SMarcel Moolenaar 	 */
5683955d011SMarcel Moolenaar 	/*
569e2eeea75SSimon J. Gerraty 	 * Christos, 4/9/92: If we are saving commands, pretend that
570e2eeea75SSimon J. Gerraty 	 * the target is made now. Otherwise archives with '...' rules
5713955d011SMarcel Moolenaar 	 * don't work!
5723955d011SMarcel Moolenaar 	 */
573956e45f6SSimon J. Gerraty 	if (!GNode_ShouldExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
5743955d011SMarcel Moolenaar 	    (mtime == 0 && !(gn->type & OP_WAIT))) {
575956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, " recheck(%s): update time from %s to now\n",
57606b9b3e0SSimon J. Gerraty 		    gn->name,
57706b9b3e0SSimon J. Gerraty 		    gn->mtime == 0 ? "nonexistent" : Targ_FmtTime(gn->mtime));
5783955d011SMarcel Moolenaar 		gn->mtime = now;
579e2eeea75SSimon J. Gerraty 	} else {
580956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, " recheck(%s): current update time: %s\n",
5813955d011SMarcel Moolenaar 		    gn->name, Targ_FmtTime(gn->mtime));
5823955d011SMarcel Moolenaar 	}
5833955d011SMarcel Moolenaar #endif
584e2eeea75SSimon J. Gerraty 
5859f45a3c8SSimon J. Gerraty 	/*
5869f45a3c8SSimon J. Gerraty 	 * XXX: The returned mtime may differ from gn->mtime. Intentionally?
5879f45a3c8SSimon J. Gerraty 	 */
5883955d011SMarcel Moolenaar 	return mtime;
5893955d011SMarcel Moolenaar }
5903955d011SMarcel Moolenaar 
591956e45f6SSimon J. Gerraty /*
592956e45f6SSimon J. Gerraty  * Set the .PREFIX and .IMPSRC variables for all the implied parents
593956e45f6SSimon J. Gerraty  * of this node.
594956e45f6SSimon J. Gerraty  */
595956e45f6SSimon J. Gerraty static void
UpdateImplicitParentsVars(GNode * cgn,const char * cname)596956e45f6SSimon J. Gerraty UpdateImplicitParentsVars(GNode *cgn, const char *cname)
597956e45f6SSimon J. Gerraty {
598956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
599956e45f6SSimon J. Gerraty 	const char *cpref = GNode_VarPrefix(cgn);
600956e45f6SSimon J. Gerraty 
60106b9b3e0SSimon J. Gerraty 	for (ln = cgn->implicitParents.first; ln != NULL; ln = ln->next) {
602956e45f6SSimon J. Gerraty 		GNode *pgn = ln->datum;
60312904384SSimon J. Gerraty 		if (pgn->flags.remake) {
604dba7b0efSSimon J. Gerraty 			Var_Set(pgn, IMPSRC, cname);
605956e45f6SSimon J. Gerraty 			if (cpref != NULL)
606dba7b0efSSimon J. Gerraty 				Var_Set(pgn, PREFIX, cpref);
607956e45f6SSimon J. Gerraty 		}
608956e45f6SSimon J. Gerraty 	}
609956e45f6SSimon J. Gerraty }
610956e45f6SSimon J. Gerraty 
611e2eeea75SSimon J. Gerraty /* See if a .ORDER rule stops us from building this node. */
612b0c40a00SSimon J. Gerraty static bool
IsWaitingForOrder(GNode * gn)613e2eeea75SSimon J. Gerraty IsWaitingForOrder(GNode *gn)
614e2eeea75SSimon J. Gerraty {
615e2eeea75SSimon J. Gerraty 	GNodeListNode *ln;
616e2eeea75SSimon J. Gerraty 
61706b9b3e0SSimon J. Gerraty 	for (ln = gn->order_pred.first; ln != NULL; ln = ln->next) {
618e2eeea75SSimon J. Gerraty 		GNode *ogn = ln->datum;
619e2eeea75SSimon J. Gerraty 
62012904384SSimon J. Gerraty 		if (GNode_IsDone(ogn) || !ogn->flags.remake)
621e2eeea75SSimon J. Gerraty 			continue;
622e2eeea75SSimon J. Gerraty 
62306b9b3e0SSimon J. Gerraty 		DEBUG2(MAKE,
62406b9b3e0SSimon J. Gerraty 		    "IsWaitingForOrder: Waiting for .ORDER node \"%s%s\"\n",
625e2eeea75SSimon J. Gerraty 		    ogn->name, ogn->cohort_num);
626b0c40a00SSimon J. Gerraty 		return true;
627e2eeea75SSimon J. Gerraty 	}
628b0c40a00SSimon J. Gerraty 	return false;
629e2eeea75SSimon J. Gerraty }
630e2eeea75SSimon J. Gerraty 
631954401e6SSimon J. Gerraty static bool MakeBuildChild(GNode *, GNodeListNode *);
63206b9b3e0SSimon J. Gerraty 
63306b9b3e0SSimon J. Gerraty static void
ScheduleOrderSuccessors(GNode * gn)63406b9b3e0SSimon J. Gerraty ScheduleOrderSuccessors(GNode *gn)
63506b9b3e0SSimon J. Gerraty {
63606b9b3e0SSimon J. Gerraty 	GNodeListNode *toBeMadeNext = toBeMade.first;
63706b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
63806b9b3e0SSimon J. Gerraty 
639954401e6SSimon J. Gerraty 	for (ln = gn->order_succ.first; ln != NULL; ln = ln->next) {
640954401e6SSimon J. Gerraty 		GNode *succ = ln->datum;
641954401e6SSimon J. Gerraty 
642954401e6SSimon J. Gerraty 		if (succ->made == DEFERRED &&
643954401e6SSimon J. Gerraty 		    !MakeBuildChild(succ, toBeMadeNext))
644954401e6SSimon J. Gerraty 			succ->flags.doneOrder = true;
645954401e6SSimon J. Gerraty 	}
64606b9b3e0SSimon J. Gerraty }
64706b9b3e0SSimon J. Gerraty 
64806b9b3e0SSimon J. Gerraty /*
64906b9b3e0SSimon J. Gerraty  * Perform update on the parents of a node. Used by JobFinish once
6503955d011SMarcel Moolenaar  * a node has been dealt with and by MakeStartJobs if it finds an
6513955d011SMarcel Moolenaar  * up-to-date node.
6523955d011SMarcel Moolenaar  *
6533955d011SMarcel Moolenaar  * The unmade field of pgn is decremented and pgn may be placed on
6543955d011SMarcel Moolenaar  * the toBeMade queue if this field becomes 0.
6553955d011SMarcel Moolenaar  *
6563955d011SMarcel Moolenaar  * If the child was made, the parent's flag CHILDMADE field will be
6573955d011SMarcel Moolenaar  * set true.
6583955d011SMarcel Moolenaar  *
6593955d011SMarcel Moolenaar  * If the child is not up-to-date and still does not exist,
6603955d011SMarcel Moolenaar  * set the FORCE flag on the parents.
6613955d011SMarcel Moolenaar  *
662956e45f6SSimon J. Gerraty  * If the child wasn't made, the youngestChild field of the parent will be
6633955d011SMarcel Moolenaar  * altered if the child's mtime is big enough.
6643955d011SMarcel Moolenaar  *
6653955d011SMarcel Moolenaar  * Finally, if the child is the implied source for the parent, the
6663955d011SMarcel Moolenaar  * parent's IMPSRC variable is set appropriately.
6673955d011SMarcel Moolenaar  */
6683955d011SMarcel Moolenaar void
Make_Update(GNode * cgn)6693955d011SMarcel Moolenaar Make_Update(GNode *cgn)
6703955d011SMarcel Moolenaar {
6712c3632d1SSimon J. Gerraty 	const char *cname;	/* the child's name */
6723955d011SMarcel Moolenaar 	time_t mtime = -1;
673956e45f6SSimon J. Gerraty 	GNodeList *parents;
674956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
6753955d011SMarcel Moolenaar 	GNode *centurion;
6763955d011SMarcel Moolenaar 
6773955d011SMarcel Moolenaar 	/* It is save to re-examine any nodes again */
678e2eeea75SSimon J. Gerraty 	checked_seqno++;
6793955d011SMarcel Moolenaar 
680956e45f6SSimon J. Gerraty 	cname = GNode_VarTarget(cgn);
6813955d011SMarcel Moolenaar 
682956e45f6SSimon J. Gerraty 	DEBUG2(MAKE, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
6833955d011SMarcel Moolenaar 
6843955d011SMarcel Moolenaar 	/*
6853955d011SMarcel Moolenaar 	 * If the child was actually made, see what its modification time is
68606b9b3e0SSimon J. Gerraty 	 * now -- some rules won't actually update the file. If the file
68706b9b3e0SSimon J. Gerraty 	 * still doesn't exist, make its mtime now.
6883955d011SMarcel Moolenaar 	 */
689d5e0a182SSimon J. Gerraty 	if (cgn->made != UPTODATE)
6903955d011SMarcel Moolenaar 		mtime = Make_Recheck(cgn);
6913955d011SMarcel Moolenaar 
6923955d011SMarcel Moolenaar 	/*
6933955d011SMarcel Moolenaar 	 * If this is a `::' node, we must consult its first instance
6943955d011SMarcel Moolenaar 	 * which is where all parents are linked.
6953955d011SMarcel Moolenaar 	 */
6963955d011SMarcel Moolenaar 	if ((centurion = cgn->centurion) != NULL) {
69706b9b3e0SSimon J. Gerraty 		if (!Lst_IsEmpty(&cgn->parents))
69806b9b3e0SSimon J. Gerraty 			Punt("%s%s: cohort has parents", cgn->name,
69906b9b3e0SSimon J. Gerraty 			    cgn->cohort_num);
700956e45f6SSimon J. Gerraty 		centurion->unmade_cohorts--;
7013955d011SMarcel Moolenaar 		if (centurion->unmade_cohorts < 0)
70206b9b3e0SSimon J. Gerraty 			Error("Graph cycles through centurion %s",
70306b9b3e0SSimon J. Gerraty 			    centurion->name);
7043955d011SMarcel Moolenaar 	} else {
7053955d011SMarcel Moolenaar 		centurion = cgn;
7063955d011SMarcel Moolenaar 	}
70706b9b3e0SSimon J. Gerraty 	parents = &centurion->parents;
7083955d011SMarcel Moolenaar 
7093955d011SMarcel Moolenaar 	/* If this was a .ORDER node, schedule the RHS */
71006b9b3e0SSimon J. Gerraty 	ScheduleOrderSuccessors(centurion);
7113955d011SMarcel Moolenaar 
7123955d011SMarcel Moolenaar 	/* Now mark all the parents as having one less unmade child */
713956e45f6SSimon J. Gerraty 	for (ln = parents->first; ln != NULL; ln = ln->next) {
714956e45f6SSimon J. Gerraty 		GNode *pgn = ln->datum;
715956e45f6SSimon J. Gerraty 
716e2eeea75SSimon J. Gerraty 		if (DEBUG(MAKE)) {
71706b9b3e0SSimon J. Gerraty 			debug_printf("inspect parent %s%s: ", pgn->name,
71806b9b3e0SSimon J. Gerraty 			    pgn->cohort_num);
719e2eeea75SSimon J. Gerraty 			GNode_FprintDetails(opts.debug_file, "", pgn, "");
720e2eeea75SSimon J. Gerraty 			debug_printf(", unmade %d ", pgn->unmade - 1);
721e2eeea75SSimon J. Gerraty 		}
7223955d011SMarcel Moolenaar 
72312904384SSimon J. Gerraty 		if (!pgn->flags.remake) {
7243955d011SMarcel Moolenaar 			/* This parent isn't needed */
725956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- not needed\n");
7263955d011SMarcel Moolenaar 			continue;
7273955d011SMarcel Moolenaar 		}
7283955d011SMarcel Moolenaar 		if (mtime == 0 && !(cgn->type & OP_WAIT))
72912904384SSimon J. Gerraty 			pgn->flags.force = true;
7303955d011SMarcel Moolenaar 
7313955d011SMarcel Moolenaar 		/*
7323955d011SMarcel Moolenaar 		 * If the parent has the .MADE attribute, its timestamp got
733956e45f6SSimon J. Gerraty 		 * updated to that of its newest child, and its unmade
7343955d011SMarcel Moolenaar 		 * child count got set to zero in Make_ExpandUse().
7353955d011SMarcel Moolenaar 		 * However other things might cause us to build one of its
7363955d011SMarcel Moolenaar 		 * children - and so we mustn't do any processing here when
7373955d011SMarcel Moolenaar 		 * the child build finishes.
7383955d011SMarcel Moolenaar 		 */
7393955d011SMarcel Moolenaar 		if (pgn->type & OP_MADE) {
740956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- .MADE\n");
7413955d011SMarcel Moolenaar 			continue;
7423955d011SMarcel Moolenaar 		}
7433955d011SMarcel Moolenaar 
7443955d011SMarcel Moolenaar 		if (!(cgn->type & (OP_EXEC | OP_USE | OP_USEBEFORE))) {
7453955d011SMarcel Moolenaar 			if (cgn->made == MADE)
74612904384SSimon J. Gerraty 				pgn->flags.childMade = true;
747e2eeea75SSimon J. Gerraty 			GNode_UpdateYoungestChild(pgn, cgn);
7483955d011SMarcel Moolenaar 		}
7493955d011SMarcel Moolenaar 
7503955d011SMarcel Moolenaar 		/*
7513955d011SMarcel Moolenaar 		 * A parent must wait for the completion of all instances
7523955d011SMarcel Moolenaar 		 * of a `::' dependency.
7533955d011SMarcel Moolenaar 		 */
75406b9b3e0SSimon J. Gerraty 		if (centurion->unmade_cohorts != 0 ||
75506b9b3e0SSimon J. Gerraty 		    !GNode_IsDone(centurion)) {
75606b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE,
75706b9b3e0SSimon J. Gerraty 			    "- centurion made %d, %d unmade cohorts\n",
7583955d011SMarcel Moolenaar 			    centurion->made, centurion->unmade_cohorts);
7593955d011SMarcel Moolenaar 			continue;
7603955d011SMarcel Moolenaar 		}
7613955d011SMarcel Moolenaar 
7623955d011SMarcel Moolenaar 		/* One more child of this parent is now made */
763956e45f6SSimon J. Gerraty 		pgn->unmade--;
7643955d011SMarcel Moolenaar 		if (pgn->unmade < 0) {
7653955d011SMarcel Moolenaar 			if (DEBUG(MAKE)) {
766956e45f6SSimon J. Gerraty 				debug_printf("Graph cycles through %s%s\n",
7673955d011SMarcel Moolenaar 				    pgn->name, pgn->cohort_num);
7683955d011SMarcel Moolenaar 				Targ_PrintGraph(2);
7693955d011SMarcel Moolenaar 			}
77006b9b3e0SSimon J. Gerraty 			Error("Graph cycles through %s%s", pgn->name,
77106b9b3e0SSimon J. Gerraty 			    pgn->cohort_num);
7723955d011SMarcel Moolenaar 		}
7733955d011SMarcel Moolenaar 
77406b9b3e0SSimon J. Gerraty 		/*
77506b9b3e0SSimon J. Gerraty 		 * We must always rescan the parents of .WAIT and .ORDER
77606b9b3e0SSimon J. Gerraty 		 * nodes.
77706b9b3e0SSimon J. Gerraty 		 */
7783955d011SMarcel Moolenaar 		if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
77912904384SSimon J. Gerraty 		    && !centurion->flags.doneOrder) {
780956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- unmade children\n");
7813955d011SMarcel Moolenaar 			continue;
7823955d011SMarcel Moolenaar 		}
7833955d011SMarcel Moolenaar 		if (pgn->made != DEFERRED) {
7843955d011SMarcel Moolenaar 			/*
78506b9b3e0SSimon J. Gerraty 			 * Either this parent is on a different branch of
78606b9b3e0SSimon J. Gerraty 			 * the tree, or it on the RHS of a .WAIT directive
7873955d011SMarcel Moolenaar 			 * or it is already on the toBeMade list.
7883955d011SMarcel Moolenaar 			 */
789956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "- not deferred\n");
7903955d011SMarcel Moolenaar 			continue;
7913955d011SMarcel Moolenaar 		}
792e2eeea75SSimon J. Gerraty 
793e2eeea75SSimon J. Gerraty 		if (IsWaitingForOrder(pgn))
7943955d011SMarcel Moolenaar 			continue;
795e2eeea75SSimon J. Gerraty 
7963955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
797956e45f6SSimon J. Gerraty 			debug_printf("- %s%s made, schedule %s%s (made %d)\n",
7983955d011SMarcel Moolenaar 			    cgn->name, cgn->cohort_num,
7993955d011SMarcel Moolenaar 			    pgn->name, pgn->cohort_num, pgn->made);
800956e45f6SSimon J. Gerraty 			Targ_PrintNode(pgn, 2);
8013955d011SMarcel Moolenaar 		}
8023955d011SMarcel Moolenaar 		/* Ok, we can schedule the parent again */
8033955d011SMarcel Moolenaar 		pgn->made = REQUESTED;
80406b9b3e0SSimon J. Gerraty 		Lst_Enqueue(&toBeMade, pgn);
8053955d011SMarcel Moolenaar 	}
8063955d011SMarcel Moolenaar 
807956e45f6SSimon J. Gerraty 	UpdateImplicitParentsVars(cgn, cname);
808956e45f6SSimon J. Gerraty }
809956e45f6SSimon J. Gerraty 
810956e45f6SSimon J. Gerraty static void
UnmarkChildren(GNode * gn)811956e45f6SSimon J. Gerraty UnmarkChildren(GNode *gn)
8122c3632d1SSimon J. Gerraty {
813956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
8143955d011SMarcel Moolenaar 
81506b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next) {
816956e45f6SSimon J. Gerraty 		GNode *child = ln->datum;
8174fde40d9SSimon J. Gerraty 		child->type &= (unsigned)~OP_MARK;
8183955d011SMarcel Moolenaar 	}
8193955d011SMarcel Moolenaar }
8202c3632d1SSimon J. Gerraty 
82106b9b3e0SSimon J. Gerraty /*
82206b9b3e0SSimon J. Gerraty  * Add a child's name to the ALLSRC and OODATE variables of the given
823956e45f6SSimon J. Gerraty  * node, but only if it has not been given the .EXEC, .USE or .INVISIBLE
824956e45f6SSimon J. Gerraty  * attributes. .EXEC and .USE children are very rarely going to be files,
825956e45f6SSimon J. Gerraty  * so...
826956e45f6SSimon J. Gerraty  *
8273955d011SMarcel Moolenaar  * If the child is a .JOIN node, its ALLSRC is propagated to the parent.
8283955d011SMarcel Moolenaar  *
8293955d011SMarcel Moolenaar  * A child is added to the OODATE variable if its modification time is
8303955d011SMarcel Moolenaar  * later than that of its parent, as defined by Make, except if the
8313955d011SMarcel Moolenaar  * parent is a .JOIN node. In that case, it is only added to the OODATE
8323955d011SMarcel Moolenaar  * variable if it was actually made (since .JOIN nodes don't have
8333955d011SMarcel Moolenaar  * modification times, the comparison is rather unfair...)..
8343955d011SMarcel Moolenaar  *
8353955d011SMarcel Moolenaar  * Input:
836956e45f6SSimon J. Gerraty  *	cgn		The child to add
837956e45f6SSimon J. Gerraty  *	pgn		The parent to whose ALLSRC variable it should
8383955d011SMarcel Moolenaar  *			be added
8393955d011SMarcel Moolenaar  */
840956e45f6SSimon J. Gerraty static void
MakeAddAllSrc(GNode * cgn,GNode * pgn)841956e45f6SSimon J. Gerraty MakeAddAllSrc(GNode *cgn, GNode *pgn)
8423955d011SMarcel Moolenaar {
843dba7b0efSSimon J. Gerraty 	const char *child, *allsrc;
844dba7b0efSSimon J. Gerraty 
8453955d011SMarcel Moolenaar 	if (cgn->type & OP_MARK)
846956e45f6SSimon J. Gerraty 		return;
8473955d011SMarcel Moolenaar 	cgn->type |= OP_MARK;
8483955d011SMarcel Moolenaar 
849dba7b0efSSimon J. Gerraty 	if (cgn->type & (OP_EXEC | OP_USE | OP_USEBEFORE | OP_INVISIBLE))
850dba7b0efSSimon J. Gerraty 		return;
8513955d011SMarcel Moolenaar 
8523955d011SMarcel Moolenaar 	if (cgn->type & OP_ARCHV)
853956e45f6SSimon J. Gerraty 		child = GNode_VarMember(cgn);
8543955d011SMarcel Moolenaar 	else
855956e45f6SSimon J. Gerraty 		child = GNode_Path(cgn);
856dba7b0efSSimon J. Gerraty 
857dba7b0efSSimon J. Gerraty 	if (cgn->type & OP_JOIN)
858956e45f6SSimon J. Gerraty 		allsrc = GNode_VarAllsrc(cgn);
859dba7b0efSSimon J. Gerraty 	else
8603955d011SMarcel Moolenaar 		allsrc = child;
861dba7b0efSSimon J. Gerraty 
8623955d011SMarcel Moolenaar 	if (allsrc != NULL)
863dba7b0efSSimon J. Gerraty 		Var_Append(pgn, ALLSRC, allsrc);
864dba7b0efSSimon J. Gerraty 
8653955d011SMarcel Moolenaar 	if (pgn->type & OP_JOIN) {
866dba7b0efSSimon J. Gerraty 		if (cgn->made == MADE)
867dba7b0efSSimon J. Gerraty 			Var_Append(pgn, OODATE, child);
868dba7b0efSSimon J. Gerraty 
8693955d011SMarcel Moolenaar 	} else if ((pgn->mtime < cgn->mtime) ||
87006b9b3e0SSimon J. Gerraty 		   (cgn->mtime >= now && cgn->made == MADE)) {
8713955d011SMarcel Moolenaar 		/*
87206b9b3e0SSimon J. Gerraty 		 * It goes in the OODATE variable if the parent is
87306b9b3e0SSimon J. Gerraty 		 * younger than the child or if the child has been
87406b9b3e0SSimon J. Gerraty 		 * modified more recently than the start of the make.
87506b9b3e0SSimon J. Gerraty 		 * This is to keep pmake from getting confused if
87606b9b3e0SSimon J. Gerraty 		 * something else updates the parent after the make
87706b9b3e0SSimon J. Gerraty 		 * starts (shouldn't happen, I know, but sometimes it
87806b9b3e0SSimon J. Gerraty 		 * does). In such a case, if we've updated the child,
87906b9b3e0SSimon J. Gerraty 		 * the parent is likely to have a modification time
88006b9b3e0SSimon J. Gerraty 		 * later than that of the child and anything that
88106b9b3e0SSimon J. Gerraty 		 * relies on the OODATE variable will be hosed.
8823955d011SMarcel Moolenaar 		 *
88306b9b3e0SSimon J. Gerraty 		 * XXX: This will cause all made children to go in
88406b9b3e0SSimon J. Gerraty 		 * the OODATE variable, even if they're not touched,
88506b9b3e0SSimon J. Gerraty 		 * if RECHECK isn't defined, since cgn->mtime is set
88606b9b3e0SSimon J. Gerraty 		 * to now in Make_Update. According to some people,
88706b9b3e0SSimon J. Gerraty 		 * this is good...
8883955d011SMarcel Moolenaar 		 */
889dba7b0efSSimon J. Gerraty 		Var_Append(pgn, OODATE, child);
8903955d011SMarcel Moolenaar 	}
8913955d011SMarcel Moolenaar }
8922c3632d1SSimon J. Gerraty 
89306b9b3e0SSimon J. Gerraty /*
89406b9b3e0SSimon J. Gerraty  * Set up the ALLSRC and OODATE variables. Sad to say, it must be
8953955d011SMarcel Moolenaar  * done separately, rather than while traversing the graph. This is
8963955d011SMarcel Moolenaar  * because Make defined OODATE to contain all sources whose modification
8973955d011SMarcel Moolenaar  * times were later than that of the target, *not* those sources that
8983955d011SMarcel Moolenaar  * were out-of-date. Since in both compatibility and native modes,
8993955d011SMarcel Moolenaar  * the modification time of the parent isn't found until the child
9003955d011SMarcel Moolenaar  * has been dealt with, we have to wait until now to fill in the
9013955d011SMarcel Moolenaar  * variable. As for ALLSRC, the ordering is important and not
9023955d011SMarcel Moolenaar  * guaranteed when in native mode, so it must be set here, too.
9033955d011SMarcel Moolenaar  *
9043955d011SMarcel Moolenaar  * If the node is a .JOIN node, its TARGET variable will be set to
9053955d011SMarcel Moolenaar  * match its ALLSRC variable.
9063955d011SMarcel Moolenaar  */
9073955d011SMarcel Moolenaar void
GNode_SetLocalVars(GNode * gn)908b0c40a00SSimon J. Gerraty GNode_SetLocalVars(GNode *gn)
9093955d011SMarcel Moolenaar {
910956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
911956e45f6SSimon J. Gerraty 
91212904384SSimon J. Gerraty 	if (gn->flags.doneAllsrc)
9133955d011SMarcel Moolenaar 		return;
9143955d011SMarcel Moolenaar 
915956e45f6SSimon J. Gerraty 	UnmarkChildren(gn);
91606b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next)
917956e45f6SSimon J. Gerraty 		MakeAddAllSrc(ln->datum, gn);
9183955d011SMarcel Moolenaar 
919dba7b0efSSimon J. Gerraty 	if (!Var_Exists(gn, OODATE))
920dba7b0efSSimon J. Gerraty 		Var_Set(gn, OODATE, "");
921dba7b0efSSimon J. Gerraty 	if (!Var_Exists(gn, ALLSRC))
922dba7b0efSSimon J. Gerraty 		Var_Set(gn, ALLSRC, "");
9233955d011SMarcel Moolenaar 
924956e45f6SSimon J. Gerraty 	if (gn->type & OP_JOIN)
925dba7b0efSSimon J. Gerraty 		Var_Set(gn, TARGET, GNode_VarAllsrc(gn));
92612904384SSimon J. Gerraty 	gn->flags.doneAllsrc = true;
9273955d011SMarcel Moolenaar }
9282c3632d1SSimon J. Gerraty 
929954401e6SSimon J. Gerraty static void
ScheduleRandomly(GNode * gn)930954401e6SSimon J. Gerraty ScheduleRandomly(GNode *gn)
931954401e6SSimon J. Gerraty {
932954401e6SSimon J. Gerraty 	GNodeListNode *ln;
933954401e6SSimon J. Gerraty 	size_t i, n;
934954401e6SSimon J. Gerraty 
935954401e6SSimon J. Gerraty 	n = 0;
936954401e6SSimon J. Gerraty 	for (ln = toBeMade.first; ln != NULL; ln = ln->next)
937954401e6SSimon J. Gerraty 		n++;
938954401e6SSimon J. Gerraty 	i = n > 0 ? (size_t)random() % (n + 1) : 0;
939954401e6SSimon J. Gerraty 
940954401e6SSimon J. Gerraty 	if (i == 0) {
941954401e6SSimon J. Gerraty 		Lst_Append(&toBeMade, gn);
942954401e6SSimon J. Gerraty 		return;
943954401e6SSimon J. Gerraty 	}
944954401e6SSimon J. Gerraty 	i--;
945954401e6SSimon J. Gerraty 
946954401e6SSimon J. Gerraty 	for (ln = toBeMade.first; i > 0; ln = ln->next)
947954401e6SSimon J. Gerraty 		i--;
948954401e6SSimon J. Gerraty 	Lst_InsertBefore(&toBeMade, ln, gn);
949954401e6SSimon J. Gerraty }
950954401e6SSimon J. Gerraty 
951b0c40a00SSimon J. Gerraty static bool
MakeBuildChild(GNode * cn,GNodeListNode * toBeMadeNext)95206b9b3e0SSimon J. Gerraty MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
9533955d011SMarcel Moolenaar {
9543955d011SMarcel Moolenaar 
955e2eeea75SSimon J. Gerraty 	if (DEBUG(MAKE)) {
956e2eeea75SSimon J. Gerraty 		debug_printf("MakeBuildChild: inspect %s%s, ",
957e2eeea75SSimon J. Gerraty 		    cn->name, cn->cohort_num);
958e2eeea75SSimon J. Gerraty 		GNode_FprintDetails(opts.debug_file, "", cn, "\n");
959e2eeea75SSimon J. Gerraty 	}
96006b9b3e0SSimon J. Gerraty 	if (GNode_IsReady(cn))
961b0c40a00SSimon J. Gerraty 		return false;
9623955d011SMarcel Moolenaar 
9633955d011SMarcel Moolenaar 	/* If this node is on the RHS of a .ORDER, check LHSs. */
964e2eeea75SSimon J. Gerraty 	if (IsWaitingForOrder(cn)) {
9659f45a3c8SSimon J. Gerraty 		/*
9669f45a3c8SSimon J. Gerraty 		 * Can't build this (or anything else in this child list) yet
9679f45a3c8SSimon J. Gerraty 		 */
9683955d011SMarcel Moolenaar 		cn->made = DEFERRED;
969b0c40a00SSimon J. Gerraty 		return false;	/* but keep looking */
9703955d011SMarcel Moolenaar 	}
9713955d011SMarcel Moolenaar 
97206b9b3e0SSimon J. Gerraty 	DEBUG2(MAKE, "MakeBuildChild: schedule %s%s\n",
97306b9b3e0SSimon J. Gerraty 	    cn->name, cn->cohort_num);
9743955d011SMarcel Moolenaar 
9753955d011SMarcel Moolenaar 	cn->made = REQUESTED;
976954401e6SSimon J. Gerraty 	if (opts.randomizeTargets && !(cn->type & OP_WAIT))
977954401e6SSimon J. Gerraty 		ScheduleRandomly(cn);
978954401e6SSimon J. Gerraty 	else if (toBeMadeNext == NULL)
97906b9b3e0SSimon J. Gerraty 		Lst_Append(&toBeMade, cn);
9803955d011SMarcel Moolenaar 	else
98106b9b3e0SSimon J. Gerraty 		Lst_InsertBefore(&toBeMade, toBeMadeNext, cn);
9823955d011SMarcel Moolenaar 
98306b9b3e0SSimon J. Gerraty 	if (cn->unmade_cohorts != 0) {
98406b9b3e0SSimon J. Gerraty 		ListNode *ln;
98506b9b3e0SSimon J. Gerraty 
98606b9b3e0SSimon J. Gerraty 		for (ln = cn->cohorts.first; ln != NULL; ln = ln->next)
987dba7b0efSSimon J. Gerraty 			if (MakeBuildChild(ln->datum, toBeMadeNext))
98806b9b3e0SSimon J. Gerraty 				break;
98906b9b3e0SSimon J. Gerraty 	}
9903955d011SMarcel Moolenaar 
9913955d011SMarcel Moolenaar 	/*
992956e45f6SSimon J. Gerraty 	 * If this node is a .WAIT node with unmade children
9933955d011SMarcel Moolenaar 	 * then don't add the next sibling.
9943955d011SMarcel Moolenaar 	 */
9953955d011SMarcel Moolenaar 	return cn->type & OP_WAIT && cn->unmade > 0;
9963955d011SMarcel Moolenaar }
9973955d011SMarcel Moolenaar 
99806b9b3e0SSimon J. Gerraty static void
MakeChildren(GNode * gn)99906b9b3e0SSimon J. Gerraty MakeChildren(GNode *gn)
100006b9b3e0SSimon J. Gerraty {
100106b9b3e0SSimon J. Gerraty 	GNodeListNode *toBeMadeNext = toBeMade.first;
100206b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
100306b9b3e0SSimon J. Gerraty 
100406b9b3e0SSimon J. Gerraty 	for (ln = gn->children.first; ln != NULL; ln = ln->next)
1005dba7b0efSSimon J. Gerraty 		if (MakeBuildChild(ln->datum, toBeMadeNext))
100606b9b3e0SSimon J. Gerraty 			break;
100706b9b3e0SSimon J. Gerraty }
100806b9b3e0SSimon J. Gerraty 
100906b9b3e0SSimon J. Gerraty /*
101006b9b3e0SSimon J. Gerraty  * Start as many jobs as possible, taking them from the toBeMade queue.
1011956e45f6SSimon J. Gerraty  *
1012e2eeea75SSimon J. Gerraty  * If the -q option was given, no job will be started,
1013956e45f6SSimon J. Gerraty  * but as soon as an out-of-date target is found, this function
1014b0c40a00SSimon J. Gerraty  * returns true. In all other cases, this function returns false.
1015956e45f6SSimon J. Gerraty  */
1016b0c40a00SSimon J. Gerraty static bool
MakeStartJobs(void)10173955d011SMarcel Moolenaar MakeStartJobs(void)
10183955d011SMarcel Moolenaar {
10193955d011SMarcel Moolenaar 	GNode *gn;
1020b0c40a00SSimon J. Gerraty 	bool have_token = false;
10213955d011SMarcel Moolenaar 
102206b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&toBeMade)) {
102306b9b3e0SSimon J. Gerraty 		/*
102406b9b3e0SSimon J. Gerraty 		 * Get token now to avoid cycling job-list when we only
102506b9b3e0SSimon J. Gerraty 		 * have 1 token
102606b9b3e0SSimon J. Gerraty 		 */
10273955d011SMarcel Moolenaar 		if (!have_token && !Job_TokenWithdraw())
10283955d011SMarcel Moolenaar 			break;
1029b0c40a00SSimon J. Gerraty 		have_token = true;
10303955d011SMarcel Moolenaar 
103106b9b3e0SSimon J. Gerraty 		gn = Lst_Dequeue(&toBeMade);
1032956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num);
10333955d011SMarcel Moolenaar 
10343955d011SMarcel Moolenaar 		if (gn->made != REQUESTED) {
1035954401e6SSimon J. Gerraty 			debug_printf("internal error: made = %s\n",
1036954401e6SSimon J. Gerraty 			    GNodeMade_Name(gn->made));
1037954401e6SSimon J. Gerraty 			Targ_PrintNode(gn, 2);
1038954401e6SSimon J. Gerraty 			Targ_PrintNodes(&toBeMade, 2);
1039954401e6SSimon J. Gerraty 			Targ_PrintGraph(3);
1040954401e6SSimon J. Gerraty 			abort();
10413955d011SMarcel Moolenaar 		}
10423955d011SMarcel Moolenaar 
1043e2eeea75SSimon J. Gerraty 		if (gn->checked_seqno == checked_seqno) {
104406b9b3e0SSimon J. Gerraty 			/*
104506b9b3e0SSimon J. Gerraty 			 * We've already looked at this node since a job
104606b9b3e0SSimon J. Gerraty 			 * finished...
104706b9b3e0SSimon J. Gerraty 			 */
104806b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE, "already checked %s%s\n", gn->name,
104906b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
10503955d011SMarcel Moolenaar 			gn->made = DEFERRED;
10513955d011SMarcel Moolenaar 			continue;
10523955d011SMarcel Moolenaar 		}
1053e2eeea75SSimon J. Gerraty 		gn->checked_seqno = checked_seqno;
10543955d011SMarcel Moolenaar 
10553955d011SMarcel Moolenaar 		if (gn->unmade != 0) {
10563955d011SMarcel Moolenaar 			/*
105706b9b3e0SSimon J. Gerraty 			 * We can't build this yet, add all unmade children
105806b9b3e0SSimon J. Gerraty 			 * to toBeMade, just before the current first element.
10593955d011SMarcel Moolenaar 			 */
10603955d011SMarcel Moolenaar 			gn->made = DEFERRED;
106106b9b3e0SSimon J. Gerraty 
106206b9b3e0SSimon J. Gerraty 			MakeChildren(gn);
106306b9b3e0SSimon J. Gerraty 
10643955d011SMarcel Moolenaar 			/* and drop this node on the floor */
106506b9b3e0SSimon J. Gerraty 			DEBUG2(MAKE, "dropped %s%s\n", gn->name,
106606b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
10673955d011SMarcel Moolenaar 			continue;
10683955d011SMarcel Moolenaar 		}
10693955d011SMarcel Moolenaar 
10703955d011SMarcel Moolenaar 		gn->made = BEINGMADE;
1071e2eeea75SSimon J. Gerraty 		if (GNode_IsOODate(gn)) {
1072956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "out-of-date\n");
10739f45a3c8SSimon J. Gerraty 			if (opts.query)
10744fde40d9SSimon J. Gerraty 				return strcmp(gn->name, ".MAIN") != 0;
1075b0c40a00SSimon J. Gerraty 			GNode_SetLocalVars(gn);
10763955d011SMarcel Moolenaar 			Job_Make(gn);
1077b0c40a00SSimon J. Gerraty 			have_token = false;
10783955d011SMarcel Moolenaar 		} else {
1079956e45f6SSimon J. Gerraty 			DEBUG0(MAKE, "up-to-date\n");
10803955d011SMarcel Moolenaar 			gn->made = UPTODATE;
10813955d011SMarcel Moolenaar 			if (gn->type & OP_JOIN) {
10823955d011SMarcel Moolenaar 				/*
108306b9b3e0SSimon J. Gerraty 				 * Even for an up-to-date .JOIN node, we
1084dba7b0efSSimon J. Gerraty 				 * need it to have its local variables so
108506b9b3e0SSimon J. Gerraty 				 * references to it get the correct value
1086dba7b0efSSimon J. Gerraty 				 * for .TARGET when building up the local
108706b9b3e0SSimon J. Gerraty 				 * variables of its parent(s)...
10883955d011SMarcel Moolenaar 				 */
1089b0c40a00SSimon J. Gerraty 				GNode_SetLocalVars(gn);
10903955d011SMarcel Moolenaar 			}
10913955d011SMarcel Moolenaar 			Make_Update(gn);
10923955d011SMarcel Moolenaar 		}
10933955d011SMarcel Moolenaar 	}
10943955d011SMarcel Moolenaar 
10953955d011SMarcel Moolenaar 	if (have_token)
10963955d011SMarcel Moolenaar 		Job_TokenReturn();
10973955d011SMarcel Moolenaar 
1098b0c40a00SSimon J. Gerraty 	return false;
10993955d011SMarcel Moolenaar }
11002c3632d1SSimon J. Gerraty 
1101e2eeea75SSimon J. Gerraty /* Print the status of a .ORDER node. */
1102956e45f6SSimon J. Gerraty static void
MakePrintStatusOrderNode(GNode * ogn,GNode * gn)1103956e45f6SSimon J. Gerraty MakePrintStatusOrderNode(GNode *ogn, GNode *gn)
11043955d011SMarcel Moolenaar {
110506b9b3e0SSimon J. Gerraty 	if (!GNode_IsWaitingFor(ogn))
1106956e45f6SSimon J. Gerraty 		return;
11073955d011SMarcel Moolenaar 
11082c3632d1SSimon J. Gerraty 	printf("    `%s%s' has .ORDER dependency against %s%s ",
11092c3632d1SSimon J. Gerraty 	    gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
11102c3632d1SSimon J. Gerraty 	GNode_FprintDetails(stdout, "(", ogn, ")\n");
11112c3632d1SSimon J. Gerraty 
1112956e45f6SSimon J. Gerraty 	if (DEBUG(MAKE) && opts.debug_file != stdout) {
1113956e45f6SSimon J. Gerraty 		debug_printf("    `%s%s' has .ORDER dependency against %s%s ",
11142c3632d1SSimon J. Gerraty 		    gn->name, gn->cohort_num, ogn->name, ogn->cohort_num);
1115956e45f6SSimon J. Gerraty 		GNode_FprintDetails(opts.debug_file, "(", ogn, ")\n");
11162c3632d1SSimon J. Gerraty 	}
11173955d011SMarcel Moolenaar }
11183955d011SMarcel Moolenaar 
1119956e45f6SSimon J. Gerraty static void
MakePrintStatusOrder(GNode * gn)1120956e45f6SSimon J. Gerraty MakePrintStatusOrder(GNode *gn)
11213955d011SMarcel Moolenaar {
1122956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
112306b9b3e0SSimon J. Gerraty 	for (ln = gn->order_pred.first; ln != NULL; ln = ln->next)
1124956e45f6SSimon J. Gerraty 		MakePrintStatusOrderNode(ln->datum, gn);
1125956e45f6SSimon J. Gerraty }
11263955d011SMarcel Moolenaar 
1127956e45f6SSimon J. Gerraty static void MakePrintStatusList(GNodeList *, int *);
1128956e45f6SSimon J. Gerraty 
112906b9b3e0SSimon J. Gerraty /*
113006b9b3e0SSimon J. Gerraty  * Print the status of a top-level node, viz. it being up-to-date already
1131956e45f6SSimon J. Gerraty  * or not created due to an error in a lower level.
1132956e45f6SSimon J. Gerraty  */
1133b0c40a00SSimon J. Gerraty static bool
MakePrintStatus(GNode * gn,int * errors)1134956e45f6SSimon J. Gerraty MakePrintStatus(GNode *gn, int *errors)
1135956e45f6SSimon J. Gerraty {
113612904384SSimon J. Gerraty 	if (gn->flags.doneCycle) {
113706b9b3e0SSimon J. Gerraty 		/*
113806b9b3e0SSimon J. Gerraty 		 * We've completely processed this node before, don't do
113906b9b3e0SSimon J. Gerraty 		 * it again.
114006b9b3e0SSimon J. Gerraty 		 */
1141b0c40a00SSimon J. Gerraty 		return false;
114206b9b3e0SSimon J. Gerraty 	}
11433955d011SMarcel Moolenaar 
11443955d011SMarcel Moolenaar 	if (gn->unmade == 0) {
114512904384SSimon J. Gerraty 		gn->flags.doneCycle = true;
11463955d011SMarcel Moolenaar 		switch (gn->made) {
11473955d011SMarcel Moolenaar 		case UPTODATE:
114806b9b3e0SSimon J. Gerraty 			printf("`%s%s' is up to date.\n", gn->name,
114906b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
11503955d011SMarcel Moolenaar 			break;
11513955d011SMarcel Moolenaar 		case MADE:
11523955d011SMarcel Moolenaar 			break;
11533955d011SMarcel Moolenaar 		case UNMADE:
11543955d011SMarcel Moolenaar 		case DEFERRED:
11553955d011SMarcel Moolenaar 		case REQUESTED:
11563955d011SMarcel Moolenaar 		case BEINGMADE:
11573955d011SMarcel Moolenaar 			(*errors)++;
115806b9b3e0SSimon J. Gerraty 			printf("`%s%s' was not built", gn->name,
115906b9b3e0SSimon J. Gerraty 			    gn->cohort_num);
11602c3632d1SSimon J. Gerraty 			GNode_FprintDetails(stdout, " (", gn, ")!\n");
1161956e45f6SSimon J. Gerraty 			if (DEBUG(MAKE) && opts.debug_file != stdout) {
116206b9b3e0SSimon J. Gerraty 				debug_printf("`%s%s' was not built", gn->name,
116306b9b3e0SSimon J. Gerraty 				    gn->cohort_num);
116406b9b3e0SSimon J. Gerraty 				GNode_FprintDetails(opts.debug_file, " (", gn,
116506b9b3e0SSimon J. Gerraty 				    ")!\n");
11662c3632d1SSimon J. Gerraty 			}
11673955d011SMarcel Moolenaar 			/* Most likely problem is actually caused by .ORDER */
1168956e45f6SSimon J. Gerraty 			MakePrintStatusOrder(gn);
11693955d011SMarcel Moolenaar 			break;
11703955d011SMarcel Moolenaar 		default:
11713955d011SMarcel Moolenaar 			/* Errors - already counted */
11723955d011SMarcel Moolenaar 			printf("`%s%s' not remade because of errors.\n",
11733955d011SMarcel Moolenaar 			    gn->name, gn->cohort_num);
1174956e45f6SSimon J. Gerraty 			if (DEBUG(MAKE) && opts.debug_file != stdout)
117506b9b3e0SSimon J. Gerraty 				debug_printf(
117606b9b3e0SSimon J. Gerraty 				    "`%s%s' not remade because of errors.\n",
11773955d011SMarcel Moolenaar 				    gn->name, gn->cohort_num);
11783955d011SMarcel Moolenaar 			break;
11793955d011SMarcel Moolenaar 		}
1180b0c40a00SSimon J. Gerraty 		return false;
11813955d011SMarcel Moolenaar 	}
11823955d011SMarcel Moolenaar 
1183956e45f6SSimon J. Gerraty 	DEBUG3(MAKE, "MakePrintStatus: %s%s has %d unmade children\n",
11843955d011SMarcel Moolenaar 	    gn->name, gn->cohort_num, gn->unmade);
11853955d011SMarcel Moolenaar 	/*
11863955d011SMarcel Moolenaar 	 * If printing cycles and came to one that has unmade children,
11873955d011SMarcel Moolenaar 	 * print out the cycle by recursing on its children.
11883955d011SMarcel Moolenaar 	 */
118912904384SSimon J. Gerraty 	if (!gn->flags.cycle) {
1190e2eeea75SSimon J. Gerraty 		/* First time we've seen this node, check all children */
119112904384SSimon J. Gerraty 		gn->flags.cycle = true;
119206b9b3e0SSimon J. Gerraty 		MakePrintStatusList(&gn->children, errors);
11933955d011SMarcel Moolenaar 		/* Mark that this node needn't be processed again */
119412904384SSimon J. Gerraty 		gn->flags.doneCycle = true;
1195b0c40a00SSimon J. Gerraty 		return false;
11963955d011SMarcel Moolenaar 	}
11973955d011SMarcel Moolenaar 
11983955d011SMarcel Moolenaar 	/* Only output the error once per node */
119912904384SSimon J. Gerraty 	gn->flags.doneCycle = true;
12003955d011SMarcel Moolenaar 	Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
12013955d011SMarcel Moolenaar 	if ((*errors)++ > 100)
12023955d011SMarcel Moolenaar 		/* Abandon the whole error report */
1203b0c40a00SSimon J. Gerraty 		return true;
12043955d011SMarcel Moolenaar 
12053955d011SMarcel Moolenaar 	/* Reporting for our children will give the rest of the loop */
120606b9b3e0SSimon J. Gerraty 	MakePrintStatusList(&gn->children, errors);
1207b0c40a00SSimon J. Gerraty 	return false;
12083955d011SMarcel Moolenaar }
12092c3632d1SSimon J. Gerraty 
1210956e45f6SSimon J. Gerraty static void
MakePrintStatusList(GNodeList * gnodes,int * errors)1211956e45f6SSimon J. Gerraty MakePrintStatusList(GNodeList *gnodes, int *errors)
1212956e45f6SSimon J. Gerraty {
1213956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
121406b9b3e0SSimon J. Gerraty 
1215956e45f6SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
1216956e45f6SSimon J. Gerraty 		if (MakePrintStatus(ln->datum, errors))
1217956e45f6SSimon J. Gerraty 			break;
1218956e45f6SSimon J. Gerraty }
12193955d011SMarcel Moolenaar 
1220e2eeea75SSimon J. Gerraty static void
ExamineLater(GNodeList * examine,GNodeList * toBeExamined)1221e2eeea75SSimon J. Gerraty ExamineLater(GNodeList *examine, GNodeList *toBeExamined)
1222e2eeea75SSimon J. Gerraty {
1223d5e0a182SSimon J. Gerraty 	GNodeListNode *ln;
1224e2eeea75SSimon J. Gerraty 
1225e2eeea75SSimon J. Gerraty 	for (ln = toBeExamined->first; ln != NULL; ln = ln->next) {
1226e2eeea75SSimon J. Gerraty 		GNode *gn = ln->datum;
1227e2eeea75SSimon J. Gerraty 
122812904384SSimon J. Gerraty 		if (gn->flags.remake)
1229e2eeea75SSimon J. Gerraty 			continue;
1230e2eeea75SSimon J. Gerraty 		if (gn->type & (OP_USE | OP_USEBEFORE))
1231e2eeea75SSimon J. Gerraty 			continue;
1232e2eeea75SSimon J. Gerraty 
1233e2eeea75SSimon J. Gerraty 		DEBUG2(MAKE, "ExamineLater: need to examine \"%s%s\"\n",
1234e2eeea75SSimon J. Gerraty 		    gn->name, gn->cohort_num);
1235e2eeea75SSimon J. Gerraty 		Lst_Enqueue(examine, gn);
1236e2eeea75SSimon J. Gerraty 	}
1237e2eeea75SSimon J. Gerraty }
1238e2eeea75SSimon J. Gerraty 
123906b9b3e0SSimon J. Gerraty /*
124006b9b3e0SSimon J. Gerraty  * Expand .USE nodes and create a new targets list.
12413955d011SMarcel Moolenaar  *
12423955d011SMarcel Moolenaar  * Input:
12433955d011SMarcel Moolenaar  *	targs		the initial list of targets
12443955d011SMarcel Moolenaar  */
12453955d011SMarcel Moolenaar void
Make_ExpandUse(GNodeList * targs)1246956e45f6SSimon J. Gerraty Make_ExpandUse(GNodeList *targs)
12473955d011SMarcel Moolenaar {
124806b9b3e0SSimon J. Gerraty 	GNodeList examine = LST_INIT;	/* Queue of targets to examine */
124906b9b3e0SSimon J. Gerraty 	Lst_AppendAll(&examine, targs);
12503955d011SMarcel Moolenaar 
12513955d011SMarcel Moolenaar 	/*
125206b9b3e0SSimon J. Gerraty 	 * Make an initial downward pass over the graph, marking nodes to
125306b9b3e0SSimon J. Gerraty 	 * be made as we go down.
125406b9b3e0SSimon J. Gerraty 	 *
125506b9b3e0SSimon J. Gerraty 	 * We call Suff_FindDeps to find where a node is and to get some
125606b9b3e0SSimon J. Gerraty 	 * children for it if it has none and also has no commands. If the
125706b9b3e0SSimon J. Gerraty 	 * node is a leaf, we stick it on the toBeMade queue to be looked
125806b9b3e0SSimon J. Gerraty 	 * at in a minute, otherwise we add its children to our queue and
125906b9b3e0SSimon J. Gerraty 	 * go on about our business.
12603955d011SMarcel Moolenaar 	 */
126106b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&examine)) {
126206b9b3e0SSimon J. Gerraty 		GNode *gn = Lst_Dequeue(&examine);
12633955d011SMarcel Moolenaar 
126412904384SSimon J. Gerraty 		if (gn->flags.remake)
12653955d011SMarcel Moolenaar 			/* We've looked at this one already */
12663955d011SMarcel Moolenaar 			continue;
126712904384SSimon J. Gerraty 		gn->flags.remake = true;
1268956e45f6SSimon J. Gerraty 		DEBUG2(MAKE, "Make_ExpandUse: examine %s%s\n",
12693955d011SMarcel Moolenaar 		    gn->name, gn->cohort_num);
12703955d011SMarcel Moolenaar 
12712c3632d1SSimon J. Gerraty 		if (gn->type & OP_DOUBLEDEP)
127206b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&examine, &gn->cohorts);
12733955d011SMarcel Moolenaar 
12743955d011SMarcel Moolenaar 		/*
127506b9b3e0SSimon J. Gerraty 		 * Apply any .USE rules before looking for implicit
127606b9b3e0SSimon J. Gerraty 		 * dependencies to make sure everything has commands that
127706b9b3e0SSimon J. Gerraty 		 * should.
127806b9b3e0SSimon J. Gerraty 		 *
12793955d011SMarcel Moolenaar 		 * Make sure that the TARGET is set, so that we can make
12803955d011SMarcel Moolenaar 		 * expansions.
12813955d011SMarcel Moolenaar 		 */
12823955d011SMarcel Moolenaar 		if (gn->type & OP_ARCHV) {
1283e2eeea75SSimon J. Gerraty 			char *eoa = strchr(gn->name, '(');
1284e2eeea75SSimon J. Gerraty 			char *eon = strchr(gn->name, ')');
12853955d011SMarcel Moolenaar 			if (eoa == NULL || eon == NULL)
12863955d011SMarcel Moolenaar 				continue;
12873955d011SMarcel Moolenaar 			*eoa = '\0';
12883955d011SMarcel Moolenaar 			*eon = '\0';
1289dba7b0efSSimon J. Gerraty 			Var_Set(gn, MEMBER, eoa + 1);
1290dba7b0efSSimon J. Gerraty 			Var_Set(gn, ARCHIVE, gn->name);
12913955d011SMarcel Moolenaar 			*eoa = '(';
12923955d011SMarcel Moolenaar 			*eon = ')';
12933955d011SMarcel Moolenaar 		}
12943955d011SMarcel Moolenaar 
1295b0c40a00SSimon J. Gerraty 		Dir_UpdateMTime(gn, false);
1296dba7b0efSSimon J. Gerraty 		Var_Set(gn, TARGET, GNode_Path(gn));
1297956e45f6SSimon J. Gerraty 		UnmarkChildren(gn);
1298956e45f6SSimon J. Gerraty 		HandleUseNodes(gn);
12993955d011SMarcel Moolenaar 
1300e2eeea75SSimon J. Gerraty 		if (!(gn->type & OP_MADE))
13013955d011SMarcel Moolenaar 			Suff_FindDeps(gn);
13023955d011SMarcel Moolenaar 		else {
1303e2eeea75SSimon J. Gerraty 			PretendAllChildrenAreMade(gn);
130406b9b3e0SSimon J. Gerraty 			if (gn->unmade != 0) {
130506b9b3e0SSimon J. Gerraty 				printf(
130606b9b3e0SSimon J. Gerraty 				    "Warning: "
130706b9b3e0SSimon J. Gerraty 				    "%s%s still has %d unmade children\n",
13083955d011SMarcel Moolenaar 				    gn->name, gn->cohort_num, gn->unmade);
13093955d011SMarcel Moolenaar 			}
13103955d011SMarcel Moolenaar 		}
13113955d011SMarcel Moolenaar 
131206b9b3e0SSimon J. Gerraty 		if (gn->unmade != 0)
131306b9b3e0SSimon J. Gerraty 			ExamineLater(&examine, &gn->children);
131406b9b3e0SSimon J. Gerraty 	}
131506b9b3e0SSimon J. Gerraty 
131606b9b3e0SSimon J. Gerraty 	Lst_Done(&examine);
13173955d011SMarcel Moolenaar }
13183955d011SMarcel Moolenaar 
1319956e45f6SSimon J. Gerraty /* Make the .WAIT node depend on the previous children */
1320956e45f6SSimon J. Gerraty static void
add_wait_dependency(GNodeListNode * owln,GNode * wn)1321956e45f6SSimon J. Gerraty add_wait_dependency(GNodeListNode *owln, GNode *wn)
13223955d011SMarcel Moolenaar {
1323956e45f6SSimon J. Gerraty 	GNodeListNode *cln;
1324956e45f6SSimon J. Gerraty 	GNode *cn;
13253955d011SMarcel Moolenaar 
1326956e45f6SSimon J. Gerraty 	for (cln = owln; (cn = cln->datum) != wn; cln = cln->next) {
1327956e45f6SSimon J. Gerraty 		DEBUG3(MAKE, ".WAIT: add dependency %s%s -> %s\n",
13283955d011SMarcel Moolenaar 		    cn->name, cn->cohort_num, wn->name);
13293955d011SMarcel Moolenaar 
13309f45a3c8SSimon J. Gerraty 		/*
13319f45a3c8SSimon J. Gerraty 		 * XXX: This pattern should be factored out, it repeats often
13329f45a3c8SSimon J. Gerraty 		 */
133306b9b3e0SSimon J. Gerraty 		Lst_Append(&wn->children, cn);
13343955d011SMarcel Moolenaar 		wn->unmade++;
133506b9b3e0SSimon J. Gerraty 		Lst_Append(&cn->parents, wn);
1336956e45f6SSimon J. Gerraty 	}
13373955d011SMarcel Moolenaar }
13383955d011SMarcel Moolenaar 
1339956e45f6SSimon J. Gerraty /* Convert .WAIT nodes into dependencies. */
13403955d011SMarcel Moolenaar static void
Make_ProcessWait(GNodeList * targs)1341956e45f6SSimon J. Gerraty Make_ProcessWait(GNodeList *targs)
13423955d011SMarcel Moolenaar {
13433955d011SMarcel Moolenaar 	GNode *pgn;		/* 'parent' node we are examining */
1344956e45f6SSimon J. Gerraty 	GNodeListNode *owln;	/* Previous .WAIT node */
134506b9b3e0SSimon J. Gerraty 	GNodeList examine;	/* List of targets to examine */
13463955d011SMarcel Moolenaar 
13473955d011SMarcel Moolenaar 	/*
13483955d011SMarcel Moolenaar 	 * We need all the nodes to have a common parent in order for the
13493955d011SMarcel Moolenaar 	 * .WAIT and .ORDER scheduling to work.
13503955d011SMarcel Moolenaar 	 * Perhaps this should be done earlier...
13513955d011SMarcel Moolenaar 	 */
13523955d011SMarcel Moolenaar 
1353e2eeea75SSimon J. Gerraty 	pgn = GNode_New(".MAIN");
135412904384SSimon J. Gerraty 	pgn->flags.remake = true;
13553955d011SMarcel Moolenaar 	pgn->type = OP_PHONY | OP_DEPENDS;
13563955d011SMarcel Moolenaar 	/* Get it displayed in the diag dumps */
13572c3632d1SSimon J. Gerraty 	Lst_Prepend(Targ_List(), pgn);
13583955d011SMarcel Moolenaar 
1359956e45f6SSimon J. Gerraty 	{
1360956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
1361956e45f6SSimon J. Gerraty 		for (ln = targs->first; ln != NULL; ln = ln->next) {
1362956e45f6SSimon J. Gerraty 			GNode *cgn = ln->datum;
1363956e45f6SSimon J. Gerraty 
136406b9b3e0SSimon J. Gerraty 			Lst_Append(&pgn->children, cgn);
136506b9b3e0SSimon J. Gerraty 			Lst_Append(&cgn->parents, pgn);
1366956e45f6SSimon J. Gerraty 			pgn->unmade++;
1367956e45f6SSimon J. Gerraty 		}
1368956e45f6SSimon J. Gerraty 	}
13693955d011SMarcel Moolenaar 
13703955d011SMarcel Moolenaar 	/* Start building with the 'dummy' .MAIN' node */
13713955d011SMarcel Moolenaar 	MakeBuildChild(pgn, NULL);
13723955d011SMarcel Moolenaar 
137306b9b3e0SSimon J. Gerraty 	Lst_Init(&examine);
137406b9b3e0SSimon J. Gerraty 	Lst_Append(&examine, pgn);
13753955d011SMarcel Moolenaar 
137606b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&examine)) {
1377956e45f6SSimon J. Gerraty 		GNodeListNode *ln;
1378956e45f6SSimon J. Gerraty 
137906b9b3e0SSimon J. Gerraty 		pgn = Lst_Dequeue(&examine);
13803955d011SMarcel Moolenaar 
13813955d011SMarcel Moolenaar 		/* We only want to process each child-list once */
138212904384SSimon J. Gerraty 		if (pgn->flags.doneWait)
13833955d011SMarcel Moolenaar 			continue;
138412904384SSimon J. Gerraty 		pgn->flags.doneWait = true;
1385956e45f6SSimon J. Gerraty 		DEBUG1(MAKE, "Make_ProcessWait: examine %s\n", pgn->name);
13863955d011SMarcel Moolenaar 
13872c3632d1SSimon J. Gerraty 		if (pgn->type & OP_DOUBLEDEP)
138806b9b3e0SSimon J. Gerraty 			Lst_PrependAll(&examine, &pgn->cohorts);
13893955d011SMarcel Moolenaar 
139006b9b3e0SSimon J. Gerraty 		owln = pgn->children.first;
139106b9b3e0SSimon J. Gerraty 		for (ln = pgn->children.first; ln != NULL; ln = ln->next) {
1392956e45f6SSimon J. Gerraty 			GNode *cgn = ln->datum;
13933955d011SMarcel Moolenaar 			if (cgn->type & OP_WAIT) {
1394956e45f6SSimon J. Gerraty 				add_wait_dependency(owln, cgn);
13953955d011SMarcel Moolenaar 				owln = ln;
13963955d011SMarcel Moolenaar 			} else {
139706b9b3e0SSimon J. Gerraty 				Lst_Append(&examine, cgn);
13983955d011SMarcel Moolenaar 			}
13993955d011SMarcel Moolenaar 		}
14003955d011SMarcel Moolenaar 	}
14013955d011SMarcel Moolenaar 
140206b9b3e0SSimon J. Gerraty 	Lst_Done(&examine);
14033955d011SMarcel Moolenaar }
14043955d011SMarcel Moolenaar 
140506b9b3e0SSimon J. Gerraty /*
140606b9b3e0SSimon J. Gerraty  * Initialize the nodes to remake and the list of nodes which are ready to
140706b9b3e0SSimon J. Gerraty  * be made by doing a breadth-first traversal of the graph starting from the
140806b9b3e0SSimon J. Gerraty  * nodes in the given list. Once this traversal is finished, all the 'leaves'
140906b9b3e0SSimon J. Gerraty  * of the graph are in the toBeMade queue.
141006b9b3e0SSimon J. Gerraty  *
141106b9b3e0SSimon J. Gerraty  * Using this queue and the Job module, work back up the graph, calling on
141206b9b3e0SSimon J. Gerraty  * MakeStartJobs to keep the job table as full as possible.
14133955d011SMarcel Moolenaar  *
14143955d011SMarcel Moolenaar  * Input:
14153955d011SMarcel Moolenaar  *	targs		the initial list of targets
14163955d011SMarcel Moolenaar  *
14173955d011SMarcel Moolenaar  * Results:
1418b0c40a00SSimon J. Gerraty  *	True if work was done, false otherwise.
14193955d011SMarcel Moolenaar  *
14203955d011SMarcel Moolenaar  * Side Effects:
14213955d011SMarcel Moolenaar  *	The make field of all nodes involved in the creation of the given
14223955d011SMarcel Moolenaar  *	targets is set to 1. The toBeMade list is set to contain all the
14233955d011SMarcel Moolenaar  *	'leaves' of these subgraphs.
14243955d011SMarcel Moolenaar  */
1425b0c40a00SSimon J. Gerraty bool
Make_Run(GNodeList * targs)1426956e45f6SSimon J. Gerraty Make_Run(GNodeList *targs)
14273955d011SMarcel Moolenaar {
14283955d011SMarcel Moolenaar 	int errors;		/* Number of errors the Job module reports */
14293955d011SMarcel Moolenaar 
14303955d011SMarcel Moolenaar 	/* Start trying to make the current targets... */
143106b9b3e0SSimon J. Gerraty 	Lst_Init(&toBeMade);
14323955d011SMarcel Moolenaar 
14333955d011SMarcel Moolenaar 	Make_ExpandUse(targs);
14343955d011SMarcel Moolenaar 	Make_ProcessWait(targs);
14353955d011SMarcel Moolenaar 
14363955d011SMarcel Moolenaar 	if (DEBUG(MAKE)) {
1437956e45f6SSimon J. Gerraty 		debug_printf("#***# full graph\n");
14383955d011SMarcel Moolenaar 		Targ_PrintGraph(1);
14393955d011SMarcel Moolenaar 	}
14403955d011SMarcel Moolenaar 
14419f45a3c8SSimon J. Gerraty 	if (opts.query) {
14423955d011SMarcel Moolenaar 		/*
144306b9b3e0SSimon J. Gerraty 		 * We wouldn't do any work unless we could start some jobs
144406b9b3e0SSimon J. Gerraty 		 * in the next loop... (we won't actually start any, of
144506b9b3e0SSimon J. Gerraty 		 * course, this is just to see if any of the targets was out
144606b9b3e0SSimon J. Gerraty 		 * of date)
14473955d011SMarcel Moolenaar 		 */
14483841c287SSimon J. Gerraty 		return MakeStartJobs();
14493955d011SMarcel Moolenaar 	}
14503955d011SMarcel Moolenaar 	/*
14513955d011SMarcel Moolenaar 	 * Initialization. At the moment, no jobs are running and until some
14523955d011SMarcel Moolenaar 	 * get started, nothing will happen since the remaining upward
14533955d011SMarcel Moolenaar 	 * traversal of the graph is performed by the routines in job.c upon
14543955d011SMarcel Moolenaar 	 * the finishing of a job. So we fill the Job table as much as we can
14553955d011SMarcel Moolenaar 	 * before going into our loop.
14563955d011SMarcel Moolenaar 	 */
14573955d011SMarcel Moolenaar 	(void)MakeStartJobs();
14583955d011SMarcel Moolenaar 
14593955d011SMarcel Moolenaar 	/*
14603955d011SMarcel Moolenaar 	 * Main Loop: The idea here is that the ending of jobs will take
146106b9b3e0SSimon J. Gerraty 	 * care of the maintenance of data structures and the waiting for
146206b9b3e0SSimon J. Gerraty 	 * output will cause us to be idle most of the time while our
146306b9b3e0SSimon J. Gerraty 	 * children run as much as possible. Because the job table is kept
146406b9b3e0SSimon J. Gerraty 	 * as full as possible, the only time when it will be empty is when
146506b9b3e0SSimon J. Gerraty 	 * all the jobs which need running have been run, so that is the end
146606b9b3e0SSimon J. Gerraty 	 * condition of this loop. Note that the Job module will exit if
146706b9b3e0SSimon J. Gerraty 	 * there were any errors unless the keepgoing flag was given.
14683955d011SMarcel Moolenaar 	 */
146906b9b3e0SSimon J. Gerraty 	while (!Lst_IsEmpty(&toBeMade) || jobTokensRunning > 0) {
14703955d011SMarcel Moolenaar 		Job_CatchOutput();
14713955d011SMarcel Moolenaar 		(void)MakeStartJobs();
14723955d011SMarcel Moolenaar 	}
14733955d011SMarcel Moolenaar 
14743955d011SMarcel Moolenaar 	errors = Job_Finish();
14753955d011SMarcel Moolenaar 
14763955d011SMarcel Moolenaar 	/*
14773955d011SMarcel Moolenaar 	 * Print the final status of each target. E.g. if it wasn't made
14783955d011SMarcel Moolenaar 	 * because some inferior reported an error.
14793955d011SMarcel Moolenaar 	 */
1480956e45f6SSimon J. Gerraty 	DEBUG1(MAKE, "done: errors %d\n", errors);
14813955d011SMarcel Moolenaar 	if (errors == 0) {
1482956e45f6SSimon J. Gerraty 		MakePrintStatusList(targs, &errors);
14833955d011SMarcel Moolenaar 		if (DEBUG(MAKE)) {
1484956e45f6SSimon J. Gerraty 			debug_printf("done: errors %d\n", errors);
1485e2eeea75SSimon J. Gerraty 			if (errors > 0)
14863955d011SMarcel Moolenaar 				Targ_PrintGraph(4);
14873955d011SMarcel Moolenaar 		}
14883955d011SMarcel Moolenaar 	}
1489e2eeea75SSimon J. Gerraty 	return errors > 0;
14903955d011SMarcel Moolenaar }
1491