1*0a6a1f1dSLionel Sambuc /* $NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $ */
22e2caf59SThomas Veerman
32e2caf59SThomas Veerman /*
42e2caf59SThomas Veerman * Copyright (c) 1988, 1989, 1990, 1993
52e2caf59SThomas Veerman * The Regents of the University of California. All rights reserved.
62e2caf59SThomas Veerman *
72e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by
82e2caf59SThomas Veerman * Adam de Boor.
92e2caf59SThomas Veerman *
102e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without
112e2caf59SThomas Veerman * modification, are permitted provided that the following conditions
122e2caf59SThomas Veerman * are met:
132e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright
142e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer.
152e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright
162e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the
172e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution.
182e2caf59SThomas Veerman * 3. Neither the name of the University nor the names of its contributors
192e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software
202e2caf59SThomas Veerman * without specific prior written permission.
212e2caf59SThomas Veerman *
222e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322e2caf59SThomas Veerman * SUCH DAMAGE.
332e2caf59SThomas Veerman */
342e2caf59SThomas Veerman
352e2caf59SThomas Veerman /*
362e2caf59SThomas Veerman * Copyright (c) 1989 by Berkeley Softworks
372e2caf59SThomas Veerman * All rights reserved.
382e2caf59SThomas Veerman *
392e2caf59SThomas Veerman * This code is derived from software contributed to Berkeley by
402e2caf59SThomas Veerman * Adam de Boor.
412e2caf59SThomas Veerman *
422e2caf59SThomas Veerman * Redistribution and use in source and binary forms, with or without
432e2caf59SThomas Veerman * modification, are permitted provided that the following conditions
442e2caf59SThomas Veerman * are met:
452e2caf59SThomas Veerman * 1. Redistributions of source code must retain the above copyright
462e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer.
472e2caf59SThomas Veerman * 2. Redistributions in binary form must reproduce the above copyright
482e2caf59SThomas Veerman * notice, this list of conditions and the following disclaimer in the
492e2caf59SThomas Veerman * documentation and/or other materials provided with the distribution.
502e2caf59SThomas Veerman * 3. All advertising materials mentioning features or use of this software
512e2caf59SThomas Veerman * must display the following acknowledgement:
522e2caf59SThomas Veerman * This product includes software developed by the University of
532e2caf59SThomas Veerman * California, Berkeley and its contributors.
542e2caf59SThomas Veerman * 4. Neither the name of the University nor the names of its contributors
552e2caf59SThomas Veerman * may be used to endorse or promote products derived from this software
562e2caf59SThomas Veerman * without specific prior written permission.
572e2caf59SThomas Veerman *
582e2caf59SThomas Veerman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
592e2caf59SThomas Veerman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
602e2caf59SThomas Veerman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
612e2caf59SThomas Veerman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
622e2caf59SThomas Veerman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
632e2caf59SThomas Veerman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
642e2caf59SThomas Veerman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
652e2caf59SThomas Veerman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
662e2caf59SThomas Veerman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
672e2caf59SThomas Veerman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
682e2caf59SThomas Veerman * SUCH DAMAGE.
692e2caf59SThomas Veerman */
702e2caf59SThomas Veerman
712e2caf59SThomas Veerman #ifndef MAKE_NATIVE
72*0a6a1f1dSLionel Sambuc static char rcsid[] = "$NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $";
732e2caf59SThomas Veerman #else
742e2caf59SThomas Veerman #include <sys/cdefs.h>
752e2caf59SThomas Veerman #ifndef lint
762e2caf59SThomas Veerman #if 0
772e2caf59SThomas Veerman static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";
782e2caf59SThomas Veerman #else
79*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: make.c,v 1.91 2014/10/18 08:33:30 snj Exp $");
802e2caf59SThomas Veerman #endif
812e2caf59SThomas Veerman #endif /* not lint */
822e2caf59SThomas Veerman #endif
832e2caf59SThomas Veerman
842e2caf59SThomas Veerman /*-
852e2caf59SThomas Veerman * make.c --
862e2caf59SThomas Veerman * The functions which perform the examination of targets and
872e2caf59SThomas Veerman * their suitability for creation
882e2caf59SThomas Veerman *
892e2caf59SThomas Veerman * Interface:
902e2caf59SThomas Veerman * Make_Run Initialize things for the module and recreate
912e2caf59SThomas Veerman * whatever needs recreating. Returns TRUE if
922e2caf59SThomas Veerman * work was (or would have been) done and FALSE
932e2caf59SThomas Veerman * otherwise.
942e2caf59SThomas Veerman *
952e2caf59SThomas Veerman * Make_Update Update all parents of a given child. Performs
962e2caf59SThomas Veerman * various bookkeeping chores like the updating
972e2caf59SThomas Veerman * of the cmgn field of the parent, filling
982e2caf59SThomas Veerman * of the IMPSRC context variable, etc. It will
992e2caf59SThomas Veerman * place the parent on the toBeMade queue if it
1002e2caf59SThomas Veerman * should be.
1012e2caf59SThomas Veerman *
1022e2caf59SThomas Veerman * Make_TimeStamp Function to set the parent's cmgn field
1032e2caf59SThomas Veerman * based on a child's modification time.
1042e2caf59SThomas Veerman *
1052e2caf59SThomas Veerman * Make_DoAllVar Set up the various local variables for a
1062e2caf59SThomas Veerman * target, including the .ALLSRC variable, making
1072e2caf59SThomas Veerman * sure that any variable that needs to exist
1082e2caf59SThomas Veerman * at the very least has the empty value.
1092e2caf59SThomas Veerman *
1102e2caf59SThomas Veerman * Make_OODate Determine if a target is out-of-date.
1112e2caf59SThomas Veerman *
1122e2caf59SThomas Veerman * Make_HandleUse See if a child is a .USE node for a parent
1132e2caf59SThomas Veerman * and perform the .USE actions if so.
1142e2caf59SThomas Veerman *
1152e2caf59SThomas Veerman * Make_ExpandUse Expand .USE nodes
1162e2caf59SThomas Veerman */
1172e2caf59SThomas Veerman
1182e2caf59SThomas Veerman #include "make.h"
1192e2caf59SThomas Veerman #include "hash.h"
1202e2caf59SThomas Veerman #include "dir.h"
1212e2caf59SThomas Veerman #include "job.h"
1222e2caf59SThomas Veerman
1232e2caf59SThomas Veerman static unsigned int checked = 1;/* Sequence # to detect recursion */
1242e2caf59SThomas Veerman static Lst toBeMade; /* The current fringe of the graph. These
1252e2caf59SThomas Veerman * are nodes which await examination by
1262e2caf59SThomas Veerman * MakeOODate. It is added to by
1272e2caf59SThomas Veerman * Make_Update and subtracted from by
1282e2caf59SThomas Veerman * MakeStartJobs */
1292e2caf59SThomas Veerman
1302e2caf59SThomas Veerman static int MakeAddChild(void *, void *);
1312e2caf59SThomas Veerman static int MakeFindChild(void *, void *);
1322e2caf59SThomas Veerman static int MakeUnmark(void *, void *);
1332e2caf59SThomas Veerman static int MakeAddAllSrc(void *, void *);
1342e2caf59SThomas Veerman static int MakeTimeStamp(void *, void *);
1352e2caf59SThomas Veerman static int MakeHandleUse(void *, void *);
1362e2caf59SThomas Veerman static Boolean MakeStartJobs(void);
1372e2caf59SThomas Veerman static int MakePrintStatus(void *, void *);
1382e2caf59SThomas Veerman static int MakeCheckOrder(void *, void *);
1392e2caf59SThomas Veerman static int MakeBuildChild(void *, void *);
1402e2caf59SThomas Veerman static int MakeBuildParent(void *, void *);
1412e2caf59SThomas Veerman
1422bc7c627SLionel Sambuc MAKE_ATTR_DEAD static void
make_abort(GNode * gn,int line)1432e2caf59SThomas Veerman make_abort(GNode *gn, int line)
1442e2caf59SThomas Veerman {
1452e2caf59SThomas Veerman static int two = 2;
1462e2caf59SThomas Veerman
1472e2caf59SThomas Veerman fprintf(debug_file, "make_abort from line %d\n", line);
1482e2caf59SThomas Veerman Targ_PrintNode(gn, &two);
1492e2caf59SThomas Veerman Lst_ForEach(toBeMade, Targ_PrintNode, &two);
1502e2caf59SThomas Veerman Targ_PrintGraph(3);
1512e2caf59SThomas Veerman abort();
1522e2caf59SThomas Veerman }
1532e2caf59SThomas Veerman
1542e2caf59SThomas Veerman /*-
1552e2caf59SThomas Veerman *-----------------------------------------------------------------------
1562e2caf59SThomas Veerman * Make_TimeStamp --
1572e2caf59SThomas Veerman * Set the cmgn field of a parent node based on the mtime stamp in its
1582e2caf59SThomas Veerman * child. Called from MakeOODate via Lst_ForEach.
1592e2caf59SThomas Veerman *
1602e2caf59SThomas Veerman * Input:
1612e2caf59SThomas Veerman * pgn the current parent
1622e2caf59SThomas Veerman * cgn the child we've just examined
1632e2caf59SThomas Veerman *
1642e2caf59SThomas Veerman * Results:
1652e2caf59SThomas Veerman * Always returns 0.
1662e2caf59SThomas Veerman *
1672e2caf59SThomas Veerman * Side Effects:
1682e2caf59SThomas Veerman * The cmgn of the parent node will be changed if the mtime
1692e2caf59SThomas Veerman * field of the child is greater than it.
1702e2caf59SThomas Veerman *-----------------------------------------------------------------------
1712e2caf59SThomas Veerman */
1722e2caf59SThomas Veerman int
Make_TimeStamp(GNode * pgn,GNode * cgn)1732e2caf59SThomas Veerman Make_TimeStamp(GNode *pgn, GNode *cgn)
1742e2caf59SThomas Veerman {
1752e2caf59SThomas Veerman if (pgn->cmgn == NULL || cgn->mtime > pgn->cmgn->mtime) {
1762e2caf59SThomas Veerman pgn->cmgn = cgn;
1772e2caf59SThomas Veerman }
1782e2caf59SThomas Veerman return (0);
1792e2caf59SThomas Veerman }
1802e2caf59SThomas Veerman
1812e2caf59SThomas Veerman /*
1822e2caf59SThomas Veerman * Input:
1832e2caf59SThomas Veerman * pgn the current parent
1842e2caf59SThomas Veerman * cgn the child we've just examined
1852e2caf59SThomas Veerman *
1862e2caf59SThomas Veerman */
1872e2caf59SThomas Veerman static int
MakeTimeStamp(void * pgn,void * cgn)1882e2caf59SThomas Veerman MakeTimeStamp(void *pgn, void *cgn)
1892e2caf59SThomas Veerman {
1902e2caf59SThomas Veerman return Make_TimeStamp((GNode *)pgn, (GNode *)cgn);
1912e2caf59SThomas Veerman }
1922e2caf59SThomas Veerman
1932e2caf59SThomas Veerman /*-
1942e2caf59SThomas Veerman *-----------------------------------------------------------------------
1952e2caf59SThomas Veerman * Make_OODate --
1962e2caf59SThomas Veerman * See if a given node is out of date with respect to its sources.
1972e2caf59SThomas Veerman * Used by Make_Run when deciding which nodes to place on the
1982e2caf59SThomas Veerman * toBeMade queue initially and by Make_Update to screen out USE and
1992e2caf59SThomas Veerman * EXEC nodes. In the latter case, however, any other sort of node
2002e2caf59SThomas Veerman * must be considered out-of-date since at least one of its children
2012e2caf59SThomas Veerman * will have been recreated.
2022e2caf59SThomas Veerman *
2032e2caf59SThomas Veerman * Input:
2042e2caf59SThomas Veerman * gn the node to check
2052e2caf59SThomas Veerman *
2062e2caf59SThomas Veerman * Results:
2072e2caf59SThomas Veerman * TRUE if the node is out of date. FALSE otherwise.
2082e2caf59SThomas Veerman *
2092e2caf59SThomas Veerman * Side Effects:
2102e2caf59SThomas Veerman * The mtime field of the node and the cmgn field of its parents
2112e2caf59SThomas Veerman * will/may be changed.
2122e2caf59SThomas Veerman *-----------------------------------------------------------------------
2132e2caf59SThomas Veerman */
2142e2caf59SThomas Veerman Boolean
Make_OODate(GNode * gn)2152e2caf59SThomas Veerman Make_OODate(GNode *gn)
2162e2caf59SThomas Veerman {
2172e2caf59SThomas Veerman Boolean oodate;
2182e2caf59SThomas Veerman
2192e2caf59SThomas Veerman /*
2202e2caf59SThomas Veerman * Certain types of targets needn't even be sought as their datedness
2212e2caf59SThomas Veerman * doesn't depend on their modification time...
2222e2caf59SThomas Veerman */
2232e2caf59SThomas Veerman if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) {
2242bc7c627SLionel Sambuc (void)Dir_MTime(gn, 1);
2252e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2262e2caf59SThomas Veerman if (gn->mtime != 0) {
2272e2caf59SThomas Veerman fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime));
2282e2caf59SThomas Veerman } else {
2292e2caf59SThomas Veerman fprintf(debug_file, "non-existent...");
2302e2caf59SThomas Veerman }
2312e2caf59SThomas Veerman }
2322e2caf59SThomas Veerman }
2332e2caf59SThomas Veerman
2342e2caf59SThomas Veerman /*
2352e2caf59SThomas Veerman * A target is remade in one of the following circumstances:
2362e2caf59SThomas Veerman * its modification time is smaller than that of its youngest child
2372e2caf59SThomas Veerman * and it would actually be run (has commands or type OP_NOP)
2382e2caf59SThomas Veerman * it's the object of a force operator
2392e2caf59SThomas Veerman * it has no children, was on the lhs of an operator and doesn't exist
2402e2caf59SThomas Veerman * already.
2412e2caf59SThomas Veerman *
2422e2caf59SThomas Veerman * Libraries are only considered out-of-date if the archive module says
2432e2caf59SThomas Veerman * they are.
2442e2caf59SThomas Veerman *
2452e2caf59SThomas Veerman * These weird rules are brought to you by Backward-Compatibility and
2462e2caf59SThomas Veerman * the strange people who wrote 'Make'.
2472e2caf59SThomas Veerman */
2482e2caf59SThomas Veerman if (gn->type & (OP_USE|OP_USEBEFORE)) {
2492e2caf59SThomas Veerman /*
2502e2caf59SThomas Veerman * If the node is a USE node it is *never* out of date
2512e2caf59SThomas Veerman * no matter *what*.
2522e2caf59SThomas Veerman */
2532e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2542e2caf59SThomas Veerman fprintf(debug_file, ".USE node...");
2552e2caf59SThomas Veerman }
2562e2caf59SThomas Veerman oodate = FALSE;
2572e2caf59SThomas Veerman } else if ((gn->type & OP_LIB) &&
2582e2caf59SThomas Veerman ((gn->mtime==0) || Arch_IsLib(gn))) {
2592e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2602e2caf59SThomas Veerman fprintf(debug_file, "library...");
2612e2caf59SThomas Veerman }
2622e2caf59SThomas Veerman
2632e2caf59SThomas Veerman /*
2642e2caf59SThomas Veerman * always out of date if no children and :: target
2652e2caf59SThomas Veerman * or non-existent.
2662e2caf59SThomas Veerman */
2672e2caf59SThomas Veerman oodate = (gn->mtime == 0 || Arch_LibOODate(gn) ||
2682e2caf59SThomas Veerman (gn->cmgn == NULL && (gn->type & OP_DOUBLEDEP)));
2692e2caf59SThomas Veerman } else if (gn->type & OP_JOIN) {
2702e2caf59SThomas Veerman /*
2712e2caf59SThomas Veerman * A target with the .JOIN attribute is only considered
2722e2caf59SThomas Veerman * out-of-date if any of its children was out-of-date.
2732e2caf59SThomas Veerman */
2742e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2752e2caf59SThomas Veerman fprintf(debug_file, ".JOIN node...");
2762e2caf59SThomas Veerman }
2772e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2782e2caf59SThomas Veerman fprintf(debug_file, "source %smade...", gn->flags & CHILDMADE ? "" : "not ");
2792e2caf59SThomas Veerman }
2802e2caf59SThomas Veerman oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE;
2812e2caf59SThomas Veerman } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) {
2822e2caf59SThomas Veerman /*
2832e2caf59SThomas Veerman * A node which is the object of the force (!) operator or which has
2842e2caf59SThomas Veerman * the .EXEC attribute is always considered out-of-date.
2852e2caf59SThomas Veerman */
2862e2caf59SThomas Veerman if (DEBUG(MAKE)) {
2872e2caf59SThomas Veerman if (gn->type & OP_FORCE) {
2882e2caf59SThomas Veerman fprintf(debug_file, "! operator...");
2892e2caf59SThomas Veerman } else if (gn->type & OP_PHONY) {
2902e2caf59SThomas Veerman fprintf(debug_file, ".PHONY node...");
2912e2caf59SThomas Veerman } else {
2922e2caf59SThomas Veerman fprintf(debug_file, ".EXEC node...");
2932e2caf59SThomas Veerman }
2942e2caf59SThomas Veerman }
2952e2caf59SThomas Veerman oodate = TRUE;
2962e2caf59SThomas Veerman } else if ((gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) ||
2972e2caf59SThomas Veerman (gn->cmgn == NULL &&
2982e2caf59SThomas Veerman ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL))
2992e2caf59SThomas Veerman || gn->type & OP_DOUBLEDEP)))
3002e2caf59SThomas Veerman {
3012e2caf59SThomas Veerman /*
3022e2caf59SThomas Veerman * A node whose modification time is less than that of its
3032e2caf59SThomas Veerman * youngest child or that has no children (cmgn == NULL) and
3042e2caf59SThomas Veerman * either doesn't exist (mtime == 0) and it isn't optional
3052e2caf59SThomas Veerman * or was the object of a * :: operator is out-of-date.
3062e2caf59SThomas Veerman * Why? Because that's the way Make does it.
3072e2caf59SThomas Veerman */
3082e2caf59SThomas Veerman if (DEBUG(MAKE)) {
3092e2caf59SThomas Veerman if (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) {
3102e2caf59SThomas Veerman fprintf(debug_file, "modified before source %s...",
3112e2caf59SThomas Veerman gn->cmgn->path);
3122e2caf59SThomas Veerman } else if (gn->mtime == 0) {
3132e2caf59SThomas Veerman fprintf(debug_file, "non-existent and no sources...");
3142e2caf59SThomas Veerman } else {
3152e2caf59SThomas Veerman fprintf(debug_file, ":: operator and no sources...");
3162e2caf59SThomas Veerman }
3172e2caf59SThomas Veerman }
3182e2caf59SThomas Veerman oodate = TRUE;
3192e2caf59SThomas Veerman } else {
3202e2caf59SThomas Veerman /*
3212e2caf59SThomas Veerman * When a non-existing child with no sources
3222e2caf59SThomas Veerman * (such as a typically used FORCE source) has been made and
3232e2caf59SThomas Veerman * the target of the child (usually a directory) has the same
3242e2caf59SThomas Veerman * timestamp as the timestamp just given to the non-existing child
3252e2caf59SThomas Veerman * after it was considered made.
3262e2caf59SThomas Veerman */
3272e2caf59SThomas Veerman if (DEBUG(MAKE)) {
3282e2caf59SThomas Veerman if (gn->flags & FORCE)
3292e2caf59SThomas Veerman fprintf(debug_file, "non existing child...");
3302e2caf59SThomas Veerman }
3312e2caf59SThomas Veerman oodate = (gn->flags & FORCE) ? TRUE : FALSE;
3322e2caf59SThomas Veerman }
3332e2caf59SThomas Veerman
3342e2caf59SThomas Veerman #ifdef USE_META
3352e2caf59SThomas Veerman if (useMeta) {
3362e2caf59SThomas Veerman oodate = meta_oodate(gn, oodate);
3372e2caf59SThomas Veerman }
3382e2caf59SThomas Veerman #endif
3392e2caf59SThomas Veerman
3402e2caf59SThomas Veerman /*
3412e2caf59SThomas Veerman * If the target isn't out-of-date, the parents need to know its
3422e2caf59SThomas Veerman * modification time. Note that targets that appear to be out-of-date
3432e2caf59SThomas Veerman * but aren't, because they have no commands and aren't of type OP_NOP,
3442e2caf59SThomas Veerman * have their mtime stay below their children's mtime to keep parents from
3452e2caf59SThomas Veerman * thinking they're out-of-date.
3462e2caf59SThomas Veerman */
3472e2caf59SThomas Veerman if (!oodate) {
3482e2caf59SThomas Veerman Lst_ForEach(gn->parents, MakeTimeStamp, gn);
3492e2caf59SThomas Veerman }
3502e2caf59SThomas Veerman
3512e2caf59SThomas Veerman return (oodate);
3522e2caf59SThomas Veerman }
3532e2caf59SThomas Veerman
3542e2caf59SThomas Veerman /*-
3552e2caf59SThomas Veerman *-----------------------------------------------------------------------
3562e2caf59SThomas Veerman * MakeAddChild --
3572e2caf59SThomas Veerman * Function used by Make_Run to add a child to the list l.
3582e2caf59SThomas Veerman * It will only add the child if its make field is FALSE.
3592e2caf59SThomas Veerman *
3602e2caf59SThomas Veerman * Input:
3612e2caf59SThomas Veerman * gnp the node to add
3622e2caf59SThomas Veerman * lp the list to which to add it
3632e2caf59SThomas Veerman *
3642e2caf59SThomas Veerman * Results:
3652e2caf59SThomas Veerman * Always returns 0
3662e2caf59SThomas Veerman *
3672e2caf59SThomas Veerman * Side Effects:
3682e2caf59SThomas Veerman * The given list is extended
3692e2caf59SThomas Veerman *-----------------------------------------------------------------------
3702e2caf59SThomas Veerman */
3712e2caf59SThomas Veerman static int
MakeAddChild(void * gnp,void * lp)3722e2caf59SThomas Veerman MakeAddChild(void *gnp, void *lp)
3732e2caf59SThomas Veerman {
3742e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
3752e2caf59SThomas Veerman Lst l = (Lst) lp;
3762e2caf59SThomas Veerman
3772e2caf59SThomas Veerman if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) {
3782e2caf59SThomas Veerman if (DEBUG(MAKE))
3792e2caf59SThomas Veerman fprintf(debug_file, "MakeAddChild: need to examine %s%s\n",
3802e2caf59SThomas Veerman gn->name, gn->cohort_num);
3812e2caf59SThomas Veerman (void)Lst_EnQueue(l, gn);
3822e2caf59SThomas Veerman }
3832e2caf59SThomas Veerman return (0);
3842e2caf59SThomas Veerman }
3852e2caf59SThomas Veerman
3862e2caf59SThomas Veerman /*-
3872e2caf59SThomas Veerman *-----------------------------------------------------------------------
3882e2caf59SThomas Veerman * MakeFindChild --
3892e2caf59SThomas Veerman * Function used by Make_Run to find the pathname of a child
3902e2caf59SThomas Veerman * that was already made.
3912e2caf59SThomas Veerman *
3922e2caf59SThomas Veerman * Input:
3932e2caf59SThomas Veerman * gnp the node to find
3942e2caf59SThomas Veerman *
3952e2caf59SThomas Veerman * Results:
3962e2caf59SThomas Veerman * Always returns 0
3972e2caf59SThomas Veerman *
3982e2caf59SThomas Veerman * Side Effects:
3992e2caf59SThomas Veerman * The path and mtime of the node and the cmgn of the parent are
4002e2caf59SThomas Veerman * updated; the unmade children count of the parent is decremented.
4012e2caf59SThomas Veerman *-----------------------------------------------------------------------
4022e2caf59SThomas Veerman */
4032e2caf59SThomas Veerman static int
MakeFindChild(void * gnp,void * pgnp)4042e2caf59SThomas Veerman MakeFindChild(void *gnp, void *pgnp)
4052e2caf59SThomas Veerman {
4062e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
4072e2caf59SThomas Veerman GNode *pgn = (GNode *)pgnp;
4082e2caf59SThomas Veerman
4092e2caf59SThomas Veerman (void)Dir_MTime(gn, 0);
4102e2caf59SThomas Veerman Make_TimeStamp(pgn, gn);
4112e2caf59SThomas Veerman pgn->unmade--;
4122e2caf59SThomas Veerman
4132e2caf59SThomas Veerman return (0);
4142e2caf59SThomas Veerman }
4152e2caf59SThomas Veerman
4162e2caf59SThomas Veerman /*-
4172e2caf59SThomas Veerman *-----------------------------------------------------------------------
4182e2caf59SThomas Veerman * Make_HandleUse --
4192e2caf59SThomas Veerman * Function called by Make_Run and SuffApplyTransform on the downward
4202e2caf59SThomas Veerman * pass to handle .USE and transformation nodes. It implements the
4212e2caf59SThomas Veerman * .USE and transformation functionality by copying the node's commands,
4222e2caf59SThomas Veerman * type flags and children to the parent node.
4232e2caf59SThomas Veerman *
4242e2caf59SThomas Veerman * A .USE node is much like an explicit transformation rule, except
4252e2caf59SThomas Veerman * its commands are always added to the target node, even if the
4262e2caf59SThomas Veerman * target already has commands.
4272e2caf59SThomas Veerman *
4282e2caf59SThomas Veerman * Input:
4292e2caf59SThomas Veerman * cgn The .USE node
4302e2caf59SThomas Veerman * pgn The target of the .USE node
4312e2caf59SThomas Veerman *
4322e2caf59SThomas Veerman * Results:
4332e2caf59SThomas Veerman * none
4342e2caf59SThomas Veerman *
4352e2caf59SThomas Veerman * Side Effects:
4362e2caf59SThomas Veerman * Children and commands may be added to the parent and the parent's
4372e2caf59SThomas Veerman * type may be changed.
4382e2caf59SThomas Veerman *
4392e2caf59SThomas Veerman *-----------------------------------------------------------------------
4402e2caf59SThomas Veerman */
4412e2caf59SThomas Veerman void
Make_HandleUse(GNode * cgn,GNode * pgn)4422e2caf59SThomas Veerman Make_HandleUse(GNode *cgn, GNode *pgn)
4432e2caf59SThomas Veerman {
4442e2caf59SThomas Veerman LstNode ln; /* An element in the children list */
4452e2caf59SThomas Veerman
4462e2caf59SThomas Veerman #ifdef DEBUG_SRC
4472e2caf59SThomas Veerman if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) {
4482e2caf59SThomas Veerman fprintf(debug_file, "Make_HandleUse: called for plain node %s\n", cgn->name);
4492e2caf59SThomas Veerman return;
4502e2caf59SThomas Veerman }
4512e2caf59SThomas Veerman #endif
4522e2caf59SThomas Veerman
4532e2caf59SThomas Veerman if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) {
4542e2caf59SThomas Veerman if (cgn->type & OP_USEBEFORE) {
4552e2caf59SThomas Veerman /*
4562e2caf59SThomas Veerman * .USEBEFORE --
4572e2caf59SThomas Veerman * prepend the child's commands to the parent.
4582e2caf59SThomas Veerman */
4592e2caf59SThomas Veerman Lst cmds = pgn->commands;
4602e2caf59SThomas Veerman pgn->commands = Lst_Duplicate(cgn->commands, NULL);
4612e2caf59SThomas Veerman (void)Lst_Concat(pgn->commands, cmds, LST_CONCNEW);
4622e2caf59SThomas Veerman Lst_Destroy(cmds, NULL);
4632e2caf59SThomas Veerman } else {
4642e2caf59SThomas Veerman /*
4652e2caf59SThomas Veerman * .USE or target has no commands --
4662e2caf59SThomas Veerman * append the child's commands to the parent.
4672e2caf59SThomas Veerman */
4682e2caf59SThomas Veerman (void)Lst_Concat(pgn->commands, cgn->commands, LST_CONCNEW);
4692e2caf59SThomas Veerman }
4702e2caf59SThomas Veerman }
4712e2caf59SThomas Veerman
4722e2caf59SThomas Veerman if (Lst_Open(cgn->children) == SUCCESS) {
4732e2caf59SThomas Veerman while ((ln = Lst_Next(cgn->children)) != NULL) {
4742e2caf59SThomas Veerman GNode *tgn, *gn = (GNode *)Lst_Datum(ln);
4752e2caf59SThomas Veerman
4762e2caf59SThomas Veerman /*
4772e2caf59SThomas Veerman * Expand variables in the .USE node's name
4782e2caf59SThomas Veerman * and save the unexpanded form.
4792e2caf59SThomas Veerman * We don't need to do this for commands.
4802e2caf59SThomas Veerman * They get expanded properly when we execute.
4812e2caf59SThomas Veerman */
4822e2caf59SThomas Veerman if (gn->uname == NULL) {
4832e2caf59SThomas Veerman gn->uname = gn->name;
4842e2caf59SThomas Veerman } else {
4852e2caf59SThomas Veerman if (gn->name)
4862e2caf59SThomas Veerman free(gn->name);
4872e2caf59SThomas Veerman }
4882e2caf59SThomas Veerman gn->name = Var_Subst(NULL, gn->uname, pgn, FALSE);
4892e2caf59SThomas Veerman if (gn->name && gn->uname && strcmp(gn->name, gn->uname) != 0) {
4902e2caf59SThomas Veerman /* See if we have a target for this node. */
4912e2caf59SThomas Veerman tgn = Targ_FindNode(gn->name, TARG_NOCREATE);
4922e2caf59SThomas Veerman if (tgn != NULL)
4932e2caf59SThomas Veerman gn = tgn;
4942e2caf59SThomas Veerman }
4952e2caf59SThomas Veerman
4962e2caf59SThomas Veerman (void)Lst_AtEnd(pgn->children, gn);
4972e2caf59SThomas Veerman (void)Lst_AtEnd(gn->parents, pgn);
4982e2caf59SThomas Veerman pgn->unmade += 1;
4992e2caf59SThomas Veerman }
5002e2caf59SThomas Veerman Lst_Close(cgn->children);
5012e2caf59SThomas Veerman }
5022e2caf59SThomas Veerman
5032e2caf59SThomas Veerman pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM);
5042e2caf59SThomas Veerman }
5052e2caf59SThomas Veerman
5062e2caf59SThomas Veerman /*-
5072e2caf59SThomas Veerman *-----------------------------------------------------------------------
5082e2caf59SThomas Veerman * MakeHandleUse --
5092e2caf59SThomas Veerman * Callback function for Lst_ForEach, used by Make_Run on the downward
5102e2caf59SThomas Veerman * pass to handle .USE nodes. Should be called before the children
5112e2caf59SThomas Veerman * are enqueued to be looked at by MakeAddChild.
5122e2caf59SThomas Veerman * This function calls Make_HandleUse to copy the .USE node's commands,
5132e2caf59SThomas Veerman * type flags and children to the parent node.
5142e2caf59SThomas Veerman *
5152e2caf59SThomas Veerman * Input:
5162e2caf59SThomas Veerman * cgnp the child we've just examined
5172e2caf59SThomas Veerman * pgnp the current parent
5182e2caf59SThomas Veerman *
5192e2caf59SThomas Veerman * Results:
5202e2caf59SThomas Veerman * returns 0.
5212e2caf59SThomas Veerman *
5222e2caf59SThomas Veerman * Side Effects:
5232e2caf59SThomas Veerman * After expansion, .USE child nodes are removed from the parent
5242e2caf59SThomas Veerman *
5252e2caf59SThomas Veerman *-----------------------------------------------------------------------
5262e2caf59SThomas Veerman */
5272e2caf59SThomas Veerman static int
MakeHandleUse(void * cgnp,void * pgnp)5282e2caf59SThomas Veerman MakeHandleUse(void *cgnp, void *pgnp)
5292e2caf59SThomas Veerman {
5302e2caf59SThomas Veerman GNode *cgn = (GNode *)cgnp;
5312e2caf59SThomas Veerman GNode *pgn = (GNode *)pgnp;
5322e2caf59SThomas Veerman LstNode ln; /* An element in the children list */
5332e2caf59SThomas Veerman int unmarked;
5342e2caf59SThomas Veerman
5352e2caf59SThomas Veerman unmarked = ((cgn->type & OP_MARK) == 0);
5362e2caf59SThomas Veerman cgn->type |= OP_MARK;
5372e2caf59SThomas Veerman
5382e2caf59SThomas Veerman if ((cgn->type & (OP_USE|OP_USEBEFORE)) == 0)
5392e2caf59SThomas Veerman return (0);
5402e2caf59SThomas Veerman
5412e2caf59SThomas Veerman if (unmarked)
5422e2caf59SThomas Veerman Make_HandleUse(cgn, pgn);
5432e2caf59SThomas Veerman
5442e2caf59SThomas Veerman /*
5452e2caf59SThomas Veerman * This child node is now "made", so we decrement the count of
5462e2caf59SThomas Veerman * unmade children in the parent... We also remove the child
5472e2caf59SThomas Veerman * from the parent's list to accurately reflect the number of decent
5482e2caf59SThomas Veerman * children the parent has. This is used by Make_Run to decide
5492e2caf59SThomas Veerman * whether to queue the parent or examine its children...
5502e2caf59SThomas Veerman */
5512e2caf59SThomas Veerman if ((ln = Lst_Member(pgn->children, cgn)) != NULL) {
5522e2caf59SThomas Veerman Lst_Remove(pgn->children, ln);
5532e2caf59SThomas Veerman pgn->unmade--;
5542e2caf59SThomas Veerman }
5552e2caf59SThomas Veerman return (0);
5562e2caf59SThomas Veerman }
5572e2caf59SThomas Veerman
5582e2caf59SThomas Veerman
5592e2caf59SThomas Veerman /*-
5602e2caf59SThomas Veerman *-----------------------------------------------------------------------
5612e2caf59SThomas Veerman * Make_Recheck --
5622e2caf59SThomas Veerman * Check the modification time of a gnode, and update it as described
5632e2caf59SThomas Veerman * in the comments below.
5642e2caf59SThomas Veerman *
5652e2caf59SThomas Veerman * Results:
566*0a6a1f1dSLionel Sambuc * returns 0 if the gnode does not exist, or its filesystem
5672e2caf59SThomas Veerman * time if it does.
5682e2caf59SThomas Veerman *
5692e2caf59SThomas Veerman * Side Effects:
5702e2caf59SThomas Veerman * the gnode's modification time and path name are affected.
5712e2caf59SThomas Veerman *
5722e2caf59SThomas Veerman *-----------------------------------------------------------------------
5732e2caf59SThomas Veerman */
5742e2caf59SThomas Veerman time_t
Make_Recheck(GNode * gn)5752e2caf59SThomas Veerman Make_Recheck(GNode *gn)
5762e2caf59SThomas Veerman {
5772e2caf59SThomas Veerman time_t mtime = Dir_MTime(gn, 1);
5782e2caf59SThomas Veerman
5792e2caf59SThomas Veerman #ifndef RECHECK
5802e2caf59SThomas Veerman /*
5812e2caf59SThomas Veerman * We can't re-stat the thing, but we can at least take care of rules
5822e2caf59SThomas Veerman * where a target depends on a source that actually creates the
5832e2caf59SThomas Veerman * target, but only if it has changed, e.g.
5842e2caf59SThomas Veerman *
5852e2caf59SThomas Veerman * parse.h : parse.o
5862e2caf59SThomas Veerman *
5872e2caf59SThomas Veerman * parse.o : parse.y
5882e2caf59SThomas Veerman * yacc -d parse.y
5892e2caf59SThomas Veerman * cc -c y.tab.c
5902e2caf59SThomas Veerman * mv y.tab.o parse.o
5912e2caf59SThomas Veerman * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
5922e2caf59SThomas Veerman *
5932e2caf59SThomas Veerman * In this case, if the definitions produced by yacc haven't changed
5942e2caf59SThomas Veerman * from before, parse.h won't have been updated and gn->mtime will
5952e2caf59SThomas Veerman * reflect the current modification time for parse.h. This is
5962e2caf59SThomas Veerman * something of a kludge, I admit, but it's a useful one..
5972e2caf59SThomas Veerman * XXX: People like to use a rule like
5982e2caf59SThomas Veerman *
5992e2caf59SThomas Veerman * FRC:
6002e2caf59SThomas Veerman *
6012e2caf59SThomas Veerman * To force things that depend on FRC to be made, so we have to
6022e2caf59SThomas Veerman * check for gn->children being empty as well...
6032e2caf59SThomas Veerman */
6042e2caf59SThomas Veerman if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {
6052e2caf59SThomas Veerman gn->mtime = now;
6062e2caf59SThomas Veerman }
6072e2caf59SThomas Veerman #else
6082e2caf59SThomas Veerman /*
6092e2caf59SThomas Veerman * This is what Make does and it's actually a good thing, as it
6102e2caf59SThomas Veerman * allows rules like
6112e2caf59SThomas Veerman *
6122e2caf59SThomas Veerman * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
6132e2caf59SThomas Veerman *
6142e2caf59SThomas Veerman * to function as intended. Unfortunately, thanks to the stateless
6152e2caf59SThomas Veerman * nature of NFS (by which I mean the loose coupling of two clients
6162e2caf59SThomas Veerman * using the same file from a common server), there are times
6172e2caf59SThomas Veerman * when the modification time of a file created on a remote
6182e2caf59SThomas Veerman * machine will not be modified before the local stat() implied by
6192e2caf59SThomas Veerman * the Dir_MTime occurs, thus leading us to believe that the file
6202e2caf59SThomas Veerman * is unchanged, wreaking havoc with files that depend on this one.
6212e2caf59SThomas Veerman *
6222e2caf59SThomas Veerman * I have decided it is better to make too much than to make too
6232e2caf59SThomas Veerman * little, so this stuff is commented out unless you're sure it's ok.
6242e2caf59SThomas Veerman * -- ardeb 1/12/88
6252e2caf59SThomas Veerman */
6262e2caf59SThomas Veerman /*
6272e2caf59SThomas Veerman * Christos, 4/9/92: If we are saving commands pretend that
6282e2caf59SThomas Veerman * the target is made now. Otherwise archives with ... rules
6292e2caf59SThomas Veerman * don't work!
6302e2caf59SThomas Veerman */
6312e2caf59SThomas Veerman if (NoExecute(gn) || (gn->type & OP_SAVE_CMDS) ||
6322e2caf59SThomas Veerman (mtime == 0 && !(gn->type & OP_WAIT))) {
6332e2caf59SThomas Veerman if (DEBUG(MAKE)) {
6342e2caf59SThomas Veerman fprintf(debug_file, " recheck(%s): update time from %s to now\n",
6352e2caf59SThomas Veerman gn->name, Targ_FmtTime(gn->mtime));
6362e2caf59SThomas Veerman }
6372e2caf59SThomas Veerman gn->mtime = now;
6382e2caf59SThomas Veerman }
6392e2caf59SThomas Veerman else {
6402e2caf59SThomas Veerman if (DEBUG(MAKE)) {
6412e2caf59SThomas Veerman fprintf(debug_file, " recheck(%s): current update time: %s\n",
6422e2caf59SThomas Veerman gn->name, Targ_FmtTime(gn->mtime));
6432e2caf59SThomas Veerman }
6442e2caf59SThomas Veerman }
6452e2caf59SThomas Veerman #endif
6462e2caf59SThomas Veerman return mtime;
6472e2caf59SThomas Veerman }
6482e2caf59SThomas Veerman
6492e2caf59SThomas Veerman /*-
6502e2caf59SThomas Veerman *-----------------------------------------------------------------------
6512e2caf59SThomas Veerman * Make_Update --
6522e2caf59SThomas Veerman * Perform update on the parents of a node. Used by JobFinish once
6532e2caf59SThomas Veerman * a node has been dealt with and by MakeStartJobs if it finds an
6542e2caf59SThomas Veerman * up-to-date node.
6552e2caf59SThomas Veerman *
6562e2caf59SThomas Veerman * Input:
6572e2caf59SThomas Veerman * cgn the child node
6582e2caf59SThomas Veerman *
6592e2caf59SThomas Veerman * Results:
6602e2caf59SThomas Veerman * Always returns 0
6612e2caf59SThomas Veerman *
6622e2caf59SThomas Veerman * Side Effects:
6632e2caf59SThomas Veerman * The unmade field of pgn is decremented and pgn may be placed on
6642e2caf59SThomas Veerman * the toBeMade queue if this field becomes 0.
6652e2caf59SThomas Veerman *
6662e2caf59SThomas Veerman * If the child was made, the parent's flag CHILDMADE field will be
6672e2caf59SThomas Veerman * set true.
6682e2caf59SThomas Veerman *
6692e2caf59SThomas Veerman * If the child is not up-to-date and still does not exist,
6702e2caf59SThomas Veerman * set the FORCE flag on the parents.
6712e2caf59SThomas Veerman *
6722e2caf59SThomas Veerman * If the child wasn't made, the cmgn field of the parent will be
6732e2caf59SThomas Veerman * altered if the child's mtime is big enough.
6742e2caf59SThomas Veerman *
6752e2caf59SThomas Veerman * Finally, if the child is the implied source for the parent, the
6762e2caf59SThomas Veerman * parent's IMPSRC variable is set appropriately.
6772e2caf59SThomas Veerman *
6782e2caf59SThomas Veerman *-----------------------------------------------------------------------
6792e2caf59SThomas Veerman */
6802e2caf59SThomas Veerman void
Make_Update(GNode * cgn)6812e2caf59SThomas Veerman Make_Update(GNode *cgn)
6822e2caf59SThomas Veerman {
6832e2caf59SThomas Veerman GNode *pgn; /* the parent node */
6842e2caf59SThomas Veerman char *cname; /* the child's name */
6852e2caf59SThomas Veerman LstNode ln; /* Element in parents and iParents lists */
6862e2caf59SThomas Veerman time_t mtime = -1;
6872e2caf59SThomas Veerman char *p1;
6882e2caf59SThomas Veerman Lst parents;
6892e2caf59SThomas Veerman GNode *centurion;
6902e2caf59SThomas Veerman
6912e2caf59SThomas Veerman /* It is save to re-examine any nodes again */
6922e2caf59SThomas Veerman checked++;
6932e2caf59SThomas Veerman
6942e2caf59SThomas Veerman cname = Var_Value(TARGET, cgn, &p1);
6952e2caf59SThomas Veerman if (p1)
6962e2caf59SThomas Veerman free(p1);
6972e2caf59SThomas Veerman
6982e2caf59SThomas Veerman if (DEBUG(MAKE))
6992e2caf59SThomas Veerman fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);
7002e2caf59SThomas Veerman
7012e2caf59SThomas Veerman /*
7022e2caf59SThomas Veerman * If the child was actually made, see what its modification time is
7032e2caf59SThomas Veerman * now -- some rules won't actually update the file. If the file still
7042e2caf59SThomas Veerman * doesn't exist, make its mtime now.
7052e2caf59SThomas Veerman */
7062e2caf59SThomas Veerman if (cgn->made != UPTODATE) {
7072e2caf59SThomas Veerman mtime = Make_Recheck(cgn);
7082e2caf59SThomas Veerman }
7092e2caf59SThomas Veerman
7102e2caf59SThomas Veerman /*
7112e2caf59SThomas Veerman * If this is a `::' node, we must consult its first instance
7122e2caf59SThomas Veerman * which is where all parents are linked.
7132e2caf59SThomas Veerman */
7142e2caf59SThomas Veerman if ((centurion = cgn->centurion) != NULL) {
7152e2caf59SThomas Veerman if (!Lst_IsEmpty(cgn->parents))
7162e2caf59SThomas Veerman Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num);
7172e2caf59SThomas Veerman centurion->unmade_cohorts -= 1;
7182e2caf59SThomas Veerman if (centurion->unmade_cohorts < 0)
7192e2caf59SThomas Veerman Error("Graph cycles through centurion %s", centurion->name);
7202e2caf59SThomas Veerman } else {
7212e2caf59SThomas Veerman centurion = cgn;
7222e2caf59SThomas Veerman }
7232e2caf59SThomas Veerman parents = centurion->parents;
7242e2caf59SThomas Veerman
7252e2caf59SThomas Veerman /* If this was a .ORDER node, schedule the RHS */
7262e2caf59SThomas Veerman Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade));
7272e2caf59SThomas Veerman
7282e2caf59SThomas Veerman /* Now mark all the parents as having one less unmade child */
7292e2caf59SThomas Veerman if (Lst_Open(parents) == SUCCESS) {
7302e2caf59SThomas Veerman while ((ln = Lst_Next(parents)) != NULL) {
7312e2caf59SThomas Veerman pgn = (GNode *)Lst_Datum(ln);
7322e2caf59SThomas Veerman if (DEBUG(MAKE))
7332e2caf59SThomas Veerman fprintf(debug_file, "inspect parent %s%s: flags %x, "
7342e2caf59SThomas Veerman "type %x, made %d, unmade %d ",
7352e2caf59SThomas Veerman pgn->name, pgn->cohort_num, pgn->flags,
7362e2caf59SThomas Veerman pgn->type, pgn->made, pgn->unmade-1);
7372e2caf59SThomas Veerman
7382e2caf59SThomas Veerman if (!(pgn->flags & REMAKE)) {
7392e2caf59SThomas Veerman /* This parent isn't needed */
7402e2caf59SThomas Veerman if (DEBUG(MAKE))
7412e2caf59SThomas Veerman fprintf(debug_file, "- not needed\n");
7422e2caf59SThomas Veerman continue;
7432e2caf59SThomas Veerman }
7442e2caf59SThomas Veerman if (mtime == 0 && !(cgn->type & OP_WAIT))
7452e2caf59SThomas Veerman pgn->flags |= FORCE;
7462e2caf59SThomas Veerman
7472e2caf59SThomas Veerman /*
7482e2caf59SThomas Veerman * If the parent has the .MADE attribute, its timestamp got
7492e2caf59SThomas Veerman * updated to that of its newest child, and its unmake
7502e2caf59SThomas Veerman * child count got set to zero in Make_ExpandUse().
7512e2caf59SThomas Veerman * However other things might cause us to build one of its
7522e2caf59SThomas Veerman * children - and so we mustn't do any processing here when
7532e2caf59SThomas Veerman * the child build finishes.
7542e2caf59SThomas Veerman */
7552e2caf59SThomas Veerman if (pgn->type & OP_MADE) {
7562e2caf59SThomas Veerman if (DEBUG(MAKE))
7572e2caf59SThomas Veerman fprintf(debug_file, "- .MADE\n");
7582e2caf59SThomas Veerman continue;
7592e2caf59SThomas Veerman }
7602e2caf59SThomas Veerman
7612e2caf59SThomas Veerman if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) {
7622e2caf59SThomas Veerman if (cgn->made == MADE)
7632e2caf59SThomas Veerman pgn->flags |= CHILDMADE;
7642e2caf59SThomas Veerman (void)Make_TimeStamp(pgn, cgn);
7652e2caf59SThomas Veerman }
7662e2caf59SThomas Veerman
7672e2caf59SThomas Veerman /*
7682e2caf59SThomas Veerman * A parent must wait for the completion of all instances
7692e2caf59SThomas Veerman * of a `::' dependency.
7702e2caf59SThomas Veerman */
7712e2caf59SThomas Veerman if (centurion->unmade_cohorts != 0 || centurion->made < MADE) {
7722e2caf59SThomas Veerman if (DEBUG(MAKE))
7732e2caf59SThomas Veerman fprintf(debug_file,
7742e2caf59SThomas Veerman "- centurion made %d, %d unmade cohorts\n",
7752e2caf59SThomas Veerman centurion->made, centurion->unmade_cohorts);
7762e2caf59SThomas Veerman continue;
7772e2caf59SThomas Veerman }
7782e2caf59SThomas Veerman
7792e2caf59SThomas Veerman /* One more child of this parent is now made */
7802e2caf59SThomas Veerman pgn->unmade -= 1;
7812e2caf59SThomas Veerman if (pgn->unmade < 0) {
7822e2caf59SThomas Veerman if (DEBUG(MAKE)) {
7832e2caf59SThomas Veerman fprintf(debug_file, "Graph cycles through %s%s\n",
7842e2caf59SThomas Veerman pgn->name, pgn->cohort_num);
7852e2caf59SThomas Veerman Targ_PrintGraph(2);
7862e2caf59SThomas Veerman }
7872e2caf59SThomas Veerman Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num);
7882e2caf59SThomas Veerman }
7892e2caf59SThomas Veerman
7902e2caf59SThomas Veerman /* We must always rescan the parents of .WAIT and .ORDER nodes. */
7912e2caf59SThomas Veerman if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
7922e2caf59SThomas Veerman && !(centurion->flags & DONE_ORDER)) {
7932e2caf59SThomas Veerman if (DEBUG(MAKE))
7942e2caf59SThomas Veerman fprintf(debug_file, "- unmade children\n");
7952e2caf59SThomas Veerman continue;
7962e2caf59SThomas Veerman }
7972e2caf59SThomas Veerman if (pgn->made != DEFERRED) {
7982e2caf59SThomas Veerman /*
7992e2caf59SThomas Veerman * Either this parent is on a different branch of the tree,
8002e2caf59SThomas Veerman * or it on the RHS of a .WAIT directive
8012e2caf59SThomas Veerman * or it is already on the toBeMade list.
8022e2caf59SThomas Veerman */
8032e2caf59SThomas Veerman if (DEBUG(MAKE))
8042e2caf59SThomas Veerman fprintf(debug_file, "- not deferred\n");
8052e2caf59SThomas Veerman continue;
8062e2caf59SThomas Veerman }
8072e2caf59SThomas Veerman if (pgn->order_pred
8082e2caf59SThomas Veerman && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) {
8092e2caf59SThomas Veerman /* A .ORDER rule stops us building this */
8102e2caf59SThomas Veerman continue;
8112e2caf59SThomas Veerman }
8122e2caf59SThomas Veerman if (DEBUG(MAKE)) {
8132e2caf59SThomas Veerman static int two = 2;
8142e2caf59SThomas Veerman fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n",
8152e2caf59SThomas Veerman cgn->name, cgn->cohort_num,
8162e2caf59SThomas Veerman pgn->name, pgn->cohort_num, pgn->made);
8172e2caf59SThomas Veerman Targ_PrintNode(pgn, &two);
8182e2caf59SThomas Veerman }
8192e2caf59SThomas Veerman /* Ok, we can schedule the parent again */
8202e2caf59SThomas Veerman pgn->made = REQUESTED;
8212e2caf59SThomas Veerman (void)Lst_EnQueue(toBeMade, pgn);
8222e2caf59SThomas Veerman }
8232e2caf59SThomas Veerman Lst_Close(parents);
8242e2caf59SThomas Veerman }
8252e2caf59SThomas Veerman
8262e2caf59SThomas Veerman /*
8272e2caf59SThomas Veerman * Set the .PREFIX and .IMPSRC variables for all the implied parents
8282e2caf59SThomas Veerman * of this node.
8292e2caf59SThomas Veerman */
8302e2caf59SThomas Veerman if (Lst_Open(cgn->iParents) == SUCCESS) {
8312e2caf59SThomas Veerman char *cpref = Var_Value(PREFIX, cgn, &p1);
8322e2caf59SThomas Veerman
8332e2caf59SThomas Veerman while ((ln = Lst_Next(cgn->iParents)) != NULL) {
8342e2caf59SThomas Veerman pgn = (GNode *)Lst_Datum(ln);
8352e2caf59SThomas Veerman if (pgn->flags & REMAKE) {
8362e2caf59SThomas Veerman Var_Set(IMPSRC, cname, pgn, 0);
8372e2caf59SThomas Veerman if (cpref != NULL)
8382e2caf59SThomas Veerman Var_Set(PREFIX, cpref, pgn, 0);
8392e2caf59SThomas Veerman }
8402e2caf59SThomas Veerman }
8412e2caf59SThomas Veerman if (p1)
8422e2caf59SThomas Veerman free(p1);
8432e2caf59SThomas Veerman Lst_Close(cgn->iParents);
8442e2caf59SThomas Veerman }
8452e2caf59SThomas Veerman }
8462e2caf59SThomas Veerman
8472e2caf59SThomas Veerman /*-
8482e2caf59SThomas Veerman *-----------------------------------------------------------------------
8492e2caf59SThomas Veerman * MakeAddAllSrc --
8502e2caf59SThomas Veerman * Add a child's name to the ALLSRC and OODATE variables of the given
8512e2caf59SThomas Veerman * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only
8522e2caf59SThomas Veerman * if it has not been given the .EXEC, .USE or .INVISIBLE attributes.
8532e2caf59SThomas Veerman * .EXEC and .USE children are very rarely going to be files, so...
8542e2caf59SThomas Veerman * If the child is a .JOIN node, its ALLSRC is propagated to the parent.
8552e2caf59SThomas Veerman *
8562e2caf59SThomas Veerman * A child is added to the OODATE variable if its modification time is
8572e2caf59SThomas Veerman * later than that of its parent, as defined by Make, except if the
8582e2caf59SThomas Veerman * parent is a .JOIN node. In that case, it is only added to the OODATE
8592e2caf59SThomas Veerman * variable if it was actually made (since .JOIN nodes don't have
8602e2caf59SThomas Veerman * modification times, the comparison is rather unfair...)..
8612e2caf59SThomas Veerman *
8622e2caf59SThomas Veerman * Results:
8632e2caf59SThomas Veerman * Always returns 0
8642e2caf59SThomas Veerman *
8652e2caf59SThomas Veerman * Side Effects:
8662e2caf59SThomas Veerman * The ALLSRC variable for the given node is extended.
8672e2caf59SThomas Veerman *-----------------------------------------------------------------------
8682e2caf59SThomas Veerman */
8692e2caf59SThomas Veerman static int
MakeUnmark(void * cgnp,void * pgnp MAKE_ATTR_UNUSED)8702bc7c627SLionel Sambuc MakeUnmark(void *cgnp, void *pgnp MAKE_ATTR_UNUSED)
8712e2caf59SThomas Veerman {
8722e2caf59SThomas Veerman GNode *cgn = (GNode *)cgnp;
8732e2caf59SThomas Veerman
8742e2caf59SThomas Veerman cgn->type &= ~OP_MARK;
8752e2caf59SThomas Veerman return (0);
8762e2caf59SThomas Veerman }
8772e2caf59SThomas Veerman
8782e2caf59SThomas Veerman /*
8792e2caf59SThomas Veerman * Input:
8802e2caf59SThomas Veerman * cgnp The child to add
8812e2caf59SThomas Veerman * pgnp The parent to whose ALLSRC variable it should
8822e2caf59SThomas Veerman * be added
8832e2caf59SThomas Veerman *
8842e2caf59SThomas Veerman */
8852e2caf59SThomas Veerman static int
MakeAddAllSrc(void * cgnp,void * pgnp)8862e2caf59SThomas Veerman MakeAddAllSrc(void *cgnp, void *pgnp)
8872e2caf59SThomas Veerman {
8882e2caf59SThomas Veerman GNode *cgn = (GNode *)cgnp;
8892e2caf59SThomas Veerman GNode *pgn = (GNode *)pgnp;
8902e2caf59SThomas Veerman
8912e2caf59SThomas Veerman if (cgn->type & OP_MARK)
8922e2caf59SThomas Veerman return (0);
8932e2caf59SThomas Veerman cgn->type |= OP_MARK;
8942e2caf59SThomas Veerman
8952e2caf59SThomas Veerman if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) {
8962e2caf59SThomas Veerman char *child, *allsrc;
8972e2caf59SThomas Veerman char *p1 = NULL, *p2 = NULL;
8982e2caf59SThomas Veerman
8992e2caf59SThomas Veerman if (cgn->type & OP_ARCHV)
9002e2caf59SThomas Veerman child = Var_Value(MEMBER, cgn, &p1);
9012e2caf59SThomas Veerman else
9022e2caf59SThomas Veerman child = cgn->path ? cgn->path : cgn->name;
9032e2caf59SThomas Veerman if (cgn->type & OP_JOIN) {
9042e2caf59SThomas Veerman allsrc = Var_Value(ALLSRC, cgn, &p2);
9052e2caf59SThomas Veerman } else {
9062e2caf59SThomas Veerman allsrc = child;
9072e2caf59SThomas Veerman }
9082e2caf59SThomas Veerman if (allsrc != NULL)
9092e2caf59SThomas Veerman Var_Append(ALLSRC, allsrc, pgn);
9102e2caf59SThomas Veerman if (p2)
9112e2caf59SThomas Veerman free(p2);
9122e2caf59SThomas Veerman if (pgn->type & OP_JOIN) {
9132e2caf59SThomas Veerman if (cgn->made == MADE) {
9142e2caf59SThomas Veerman Var_Append(OODATE, child, pgn);
9152e2caf59SThomas Veerman }
9162e2caf59SThomas Veerman } else if ((pgn->mtime < cgn->mtime) ||
9172e2caf59SThomas Veerman (cgn->mtime >= now && cgn->made == MADE))
9182e2caf59SThomas Veerman {
9192e2caf59SThomas Veerman /*
9202e2caf59SThomas Veerman * It goes in the OODATE variable if the parent is younger than the
9212e2caf59SThomas Veerman * child or if the child has been modified more recently than
9222e2caf59SThomas Veerman * the start of the make. This is to keep pmake from getting
9232e2caf59SThomas Veerman * confused if something else updates the parent after the
9242e2caf59SThomas Veerman * make starts (shouldn't happen, I know, but sometimes it
9252e2caf59SThomas Veerman * does). In such a case, if we've updated the kid, the parent
9262e2caf59SThomas Veerman * is likely to have a modification time later than that of
9272e2caf59SThomas Veerman * the kid and anything that relies on the OODATE variable will
9282e2caf59SThomas Veerman * be hosed.
9292e2caf59SThomas Veerman *
9302e2caf59SThomas Veerman * XXX: This will cause all made children to go in the OODATE
9312e2caf59SThomas Veerman * variable, even if they're not touched, if RECHECK isn't defined,
9322e2caf59SThomas Veerman * since cgn->mtime is set to now in Make_Update. According to
9332e2caf59SThomas Veerman * some people, this is good...
9342e2caf59SThomas Veerman */
9352e2caf59SThomas Veerman Var_Append(OODATE, child, pgn);
9362e2caf59SThomas Veerman }
9372e2caf59SThomas Veerman if (p1)
9382e2caf59SThomas Veerman free(p1);
9392e2caf59SThomas Veerman }
9402e2caf59SThomas Veerman return (0);
9412e2caf59SThomas Veerman }
9422e2caf59SThomas Veerman
9432e2caf59SThomas Veerman /*-
9442e2caf59SThomas Veerman *-----------------------------------------------------------------------
9452e2caf59SThomas Veerman * Make_DoAllVar --
9462e2caf59SThomas Veerman * Set up the ALLSRC and OODATE variables. Sad to say, it must be
9472e2caf59SThomas Veerman * done separately, rather than while traversing the graph. This is
9482e2caf59SThomas Veerman * because Make defined OODATE to contain all sources whose modification
9492e2caf59SThomas Veerman * times were later than that of the target, *not* those sources that
9502e2caf59SThomas Veerman * were out-of-date. Since in both compatibility and native modes,
9512e2caf59SThomas Veerman * the modification time of the parent isn't found until the child
9522e2caf59SThomas Veerman * has been dealt with, we have to wait until now to fill in the
9532e2caf59SThomas Veerman * variable. As for ALLSRC, the ordering is important and not
9542e2caf59SThomas Veerman * guaranteed when in native mode, so it must be set here, too.
9552e2caf59SThomas Veerman *
9562e2caf59SThomas Veerman * Results:
9572e2caf59SThomas Veerman * None
9582e2caf59SThomas Veerman *
9592e2caf59SThomas Veerman * Side Effects:
9602e2caf59SThomas Veerman * The ALLSRC and OODATE variables of the given node is filled in.
9612e2caf59SThomas Veerman * If the node is a .JOIN node, its TARGET variable will be set to
9622e2caf59SThomas Veerman * match its ALLSRC variable.
9632e2caf59SThomas Veerman *-----------------------------------------------------------------------
9642e2caf59SThomas Veerman */
9652e2caf59SThomas Veerman void
Make_DoAllVar(GNode * gn)9662e2caf59SThomas Veerman Make_DoAllVar(GNode *gn)
9672e2caf59SThomas Veerman {
9682e2caf59SThomas Veerman if (gn->flags & DONE_ALLSRC)
9692e2caf59SThomas Veerman return;
9702e2caf59SThomas Veerman
9712e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeUnmark, gn);
9722e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeAddAllSrc, gn);
9732e2caf59SThomas Veerman
9742e2caf59SThomas Veerman if (!Var_Exists (OODATE, gn)) {
9752e2caf59SThomas Veerman Var_Set(OODATE, "", gn, 0);
9762e2caf59SThomas Veerman }
9772e2caf59SThomas Veerman if (!Var_Exists (ALLSRC, gn)) {
9782e2caf59SThomas Veerman Var_Set(ALLSRC, "", gn, 0);
9792e2caf59SThomas Veerman }
9802e2caf59SThomas Veerman
9812e2caf59SThomas Veerman if (gn->type & OP_JOIN) {
9822e2caf59SThomas Veerman char *p1;
9832e2caf59SThomas Veerman Var_Set(TARGET, Var_Value(ALLSRC, gn, &p1), gn, 0);
9842e2caf59SThomas Veerman if (p1)
9852e2caf59SThomas Veerman free(p1);
9862e2caf59SThomas Veerman }
9872e2caf59SThomas Veerman gn->flags |= DONE_ALLSRC;
9882e2caf59SThomas Veerman }
9892e2caf59SThomas Veerman
9902e2caf59SThomas Veerman /*-
9912e2caf59SThomas Veerman *-----------------------------------------------------------------------
9922e2caf59SThomas Veerman * MakeStartJobs --
9932e2caf59SThomas Veerman * Start as many jobs as possible.
9942e2caf59SThomas Veerman *
9952e2caf59SThomas Veerman * Results:
9962e2caf59SThomas Veerman * If the query flag was given to pmake, no job will be started,
9972e2caf59SThomas Veerman * but as soon as an out-of-date target is found, this function
9982e2caf59SThomas Veerman * returns TRUE. At all other times, this function returns FALSE.
9992e2caf59SThomas Veerman *
10002e2caf59SThomas Veerman * Side Effects:
10012e2caf59SThomas Veerman * Nodes are removed from the toBeMade queue and job table slots
10022e2caf59SThomas Veerman * are filled.
10032e2caf59SThomas Veerman *
10042e2caf59SThomas Veerman *-----------------------------------------------------------------------
10052e2caf59SThomas Veerman */
10062e2caf59SThomas Veerman
10072e2caf59SThomas Veerman static int
MakeCheckOrder(void * v_bn,void * ignore MAKE_ATTR_UNUSED)10082bc7c627SLionel Sambuc MakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED)
10092e2caf59SThomas Veerman {
10102e2caf59SThomas Veerman GNode *bn = v_bn;
10112e2caf59SThomas Veerman
10122e2caf59SThomas Veerman if (bn->made >= MADE || !(bn->flags & REMAKE))
10132e2caf59SThomas Veerman return 0;
10142e2caf59SThomas Veerman if (DEBUG(MAKE))
10152e2caf59SThomas Veerman fprintf(debug_file, "MakeCheckOrder: Waiting for .ORDER node %s%s\n",
10162e2caf59SThomas Veerman bn->name, bn->cohort_num);
10172e2caf59SThomas Veerman return 1;
10182e2caf59SThomas Veerman }
10192e2caf59SThomas Veerman
10202e2caf59SThomas Veerman static int
MakeBuildChild(void * v_cn,void * toBeMade_next)10212e2caf59SThomas Veerman MakeBuildChild(void *v_cn, void *toBeMade_next)
10222e2caf59SThomas Veerman {
10232e2caf59SThomas Veerman GNode *cn = v_cn;
10242e2caf59SThomas Veerman
10252e2caf59SThomas Veerman if (DEBUG(MAKE))
10262e2caf59SThomas Veerman fprintf(debug_file, "MakeBuildChild: inspect %s%s, made %d, type %x\n",
10272e2caf59SThomas Veerman cn->name, cn->cohort_num, cn->made, cn->type);
10282e2caf59SThomas Veerman if (cn->made > DEFERRED)
10292e2caf59SThomas Veerman return 0;
10302e2caf59SThomas Veerman
10312e2caf59SThomas Veerman /* If this node is on the RHS of a .ORDER, check LHSs. */
10322e2caf59SThomas Veerman if (cn->order_pred && Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) {
10332e2caf59SThomas Veerman /* Can't build this (or anything else in this child list) yet */
10342e2caf59SThomas Veerman cn->made = DEFERRED;
103584d9c625SLionel Sambuc return 0; /* but keep looking */
10362e2caf59SThomas Veerman }
10372e2caf59SThomas Veerman
10382e2caf59SThomas Veerman if (DEBUG(MAKE))
10392e2caf59SThomas Veerman fprintf(debug_file, "MakeBuildChild: schedule %s%s\n",
10402e2caf59SThomas Veerman cn->name, cn->cohort_num);
10412e2caf59SThomas Veerman
10422e2caf59SThomas Veerman cn->made = REQUESTED;
10432e2caf59SThomas Veerman if (toBeMade_next == NULL)
10442e2caf59SThomas Veerman Lst_AtEnd(toBeMade, cn);
10452e2caf59SThomas Veerman else
10462e2caf59SThomas Veerman Lst_InsertBefore(toBeMade, toBeMade_next, cn);
10472e2caf59SThomas Veerman
10482e2caf59SThomas Veerman if (cn->unmade_cohorts != 0)
10492e2caf59SThomas Veerman Lst_ForEach(cn->cohorts, MakeBuildChild, toBeMade_next);
10502e2caf59SThomas Veerman
10512e2caf59SThomas Veerman /*
10522e2caf59SThomas Veerman * If this node is a .WAIT node with unmade chlidren
10532e2caf59SThomas Veerman * then don't add the next sibling.
10542e2caf59SThomas Veerman */
10552e2caf59SThomas Veerman return cn->type & OP_WAIT && cn->unmade > 0;
10562e2caf59SThomas Veerman }
10572e2caf59SThomas Veerman
105884d9c625SLionel Sambuc /* When a .ORDER LHS node completes we do this on each RHS */
10592e2caf59SThomas Veerman static int
MakeBuildParent(void * v_pn,void * toBeMade_next)10602e2caf59SThomas Veerman MakeBuildParent(void *v_pn, void *toBeMade_next)
10612e2caf59SThomas Veerman {
10622e2caf59SThomas Veerman GNode *pn = v_pn;
10632e2caf59SThomas Veerman
10642e2caf59SThomas Veerman if (pn->made != DEFERRED)
10652e2caf59SThomas Veerman return 0;
10662e2caf59SThomas Veerman
10672e2caf59SThomas Veerman if (MakeBuildChild(pn, toBeMade_next) == 0) {
10682e2caf59SThomas Veerman /* Mark so that when this node is built we reschedule its parents */
10692e2caf59SThomas Veerman pn->flags |= DONE_ORDER;
10702e2caf59SThomas Veerman }
10712e2caf59SThomas Veerman
10722e2caf59SThomas Veerman return 0;
10732e2caf59SThomas Veerman }
10742e2caf59SThomas Veerman
10752e2caf59SThomas Veerman static Boolean
MakeStartJobs(void)10762e2caf59SThomas Veerman MakeStartJobs(void)
10772e2caf59SThomas Veerman {
10782e2caf59SThomas Veerman GNode *gn;
10792e2caf59SThomas Veerman int have_token = 0;
10802e2caf59SThomas Veerman
10812e2caf59SThomas Veerman while (!Lst_IsEmpty (toBeMade)) {
10822e2caf59SThomas Veerman /* Get token now to avoid cycling job-list when we only have 1 token */
10832e2caf59SThomas Veerman if (!have_token && !Job_TokenWithdraw())
10842e2caf59SThomas Veerman break;
10852e2caf59SThomas Veerman have_token = 1;
10862e2caf59SThomas Veerman
10872e2caf59SThomas Veerman gn = (GNode *)Lst_DeQueue(toBeMade);
10882e2caf59SThomas Veerman if (DEBUG(MAKE))
10892e2caf59SThomas Veerman fprintf(debug_file, "Examining %s%s...\n",
10902e2caf59SThomas Veerman gn->name, gn->cohort_num);
10912e2caf59SThomas Veerman
10922e2caf59SThomas Veerman if (gn->made != REQUESTED) {
10932e2caf59SThomas Veerman if (DEBUG(MAKE))
10942e2caf59SThomas Veerman fprintf(debug_file, "state %d\n", gn->made);
10952e2caf59SThomas Veerman
10962e2caf59SThomas Veerman make_abort(gn, __LINE__);
10972e2caf59SThomas Veerman }
10982e2caf59SThomas Veerman
10992e2caf59SThomas Veerman if (gn->checked == checked) {
11002e2caf59SThomas Veerman /* We've already looked at this node since a job finished... */
11012e2caf59SThomas Veerman if (DEBUG(MAKE))
11022e2caf59SThomas Veerman fprintf(debug_file, "already checked %s%s\n",
11032e2caf59SThomas Veerman gn->name, gn->cohort_num);
11042e2caf59SThomas Veerman gn->made = DEFERRED;
11052e2caf59SThomas Veerman continue;
11062e2caf59SThomas Veerman }
11072e2caf59SThomas Veerman gn->checked = checked;
11082e2caf59SThomas Veerman
11092e2caf59SThomas Veerman if (gn->unmade != 0) {
11102e2caf59SThomas Veerman /*
11112e2caf59SThomas Veerman * We can't build this yet, add all unmade children to toBeMade,
11122e2caf59SThomas Veerman * just before the current first element.
11132e2caf59SThomas Veerman */
11142e2caf59SThomas Veerman gn->made = DEFERRED;
11152e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade));
11162e2caf59SThomas Veerman /* and drop this node on the floor */
11172e2caf59SThomas Veerman if (DEBUG(MAKE))
11182e2caf59SThomas Veerman fprintf(debug_file, "dropped %s%s\n", gn->name, gn->cohort_num);
11192e2caf59SThomas Veerman continue;
11202e2caf59SThomas Veerman }
11212e2caf59SThomas Veerman
11222e2caf59SThomas Veerman gn->made = BEINGMADE;
11232e2caf59SThomas Veerman if (Make_OODate(gn)) {
11242e2caf59SThomas Veerman if (DEBUG(MAKE)) {
11252e2caf59SThomas Veerman fprintf(debug_file, "out-of-date\n");
11262e2caf59SThomas Veerman }
11272e2caf59SThomas Veerman if (queryFlag) {
11282e2caf59SThomas Veerman return (TRUE);
11292e2caf59SThomas Veerman }
11302e2caf59SThomas Veerman Make_DoAllVar(gn);
11312e2caf59SThomas Veerman Job_Make(gn);
11322e2caf59SThomas Veerman have_token = 0;
11332e2caf59SThomas Veerman } else {
11342e2caf59SThomas Veerman if (DEBUG(MAKE)) {
11352e2caf59SThomas Veerman fprintf(debug_file, "up-to-date\n");
11362e2caf59SThomas Veerman }
11372e2caf59SThomas Veerman gn->made = UPTODATE;
11382e2caf59SThomas Veerman if (gn->type & OP_JOIN) {
11392e2caf59SThomas Veerman /*
11402e2caf59SThomas Veerman * Even for an up-to-date .JOIN node, we need it to have its
11412e2caf59SThomas Veerman * context variables so references to it get the correct
11422e2caf59SThomas Veerman * value for .TARGET when building up the context variables
11432e2caf59SThomas Veerman * of its parent(s)...
11442e2caf59SThomas Veerman */
11452e2caf59SThomas Veerman Make_DoAllVar(gn);
11462e2caf59SThomas Veerman }
11472e2caf59SThomas Veerman Make_Update(gn);
11482e2caf59SThomas Veerman }
11492e2caf59SThomas Veerman }
11502e2caf59SThomas Veerman
11512e2caf59SThomas Veerman if (have_token)
11522e2caf59SThomas Veerman Job_TokenReturn();
11532e2caf59SThomas Veerman
11542e2caf59SThomas Veerman return (FALSE);
11552e2caf59SThomas Veerman }
11562e2caf59SThomas Veerman
11572e2caf59SThomas Veerman /*-
11582e2caf59SThomas Veerman *-----------------------------------------------------------------------
11592e2caf59SThomas Veerman * MakePrintStatus --
11602e2caf59SThomas Veerman * Print the status of a top-level node, viz. it being up-to-date
11612e2caf59SThomas Veerman * already or not created due to an error in a lower level.
11622e2caf59SThomas Veerman * Callback function for Make_Run via Lst_ForEach.
11632e2caf59SThomas Veerman *
11642e2caf59SThomas Veerman * Input:
11652e2caf59SThomas Veerman * gnp Node to examine
11662e2caf59SThomas Veerman * cyclep True if gn->unmade being non-zero implies a
11672e2caf59SThomas Veerman * cycle in the graph, not an error in an
11682e2caf59SThomas Veerman * inferior.
11692e2caf59SThomas Veerman *
11702e2caf59SThomas Veerman * Results:
11712e2caf59SThomas Veerman * Always returns 0.
11722e2caf59SThomas Veerman *
11732e2caf59SThomas Veerman * Side Effects:
11742e2caf59SThomas Veerman * A message may be printed.
11752e2caf59SThomas Veerman *
11762e2caf59SThomas Veerman *-----------------------------------------------------------------------
11772e2caf59SThomas Veerman */
11782e2caf59SThomas Veerman static int
MakePrintStatusOrder(void * ognp,void * gnp)11792e2caf59SThomas Veerman MakePrintStatusOrder(void *ognp, void *gnp)
11802e2caf59SThomas Veerman {
11812e2caf59SThomas Veerman GNode *ogn = ognp;
11822e2caf59SThomas Veerman GNode *gn = gnp;
11832e2caf59SThomas Veerman
11842e2caf59SThomas Veerman if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED)
11852e2caf59SThomas Veerman /* not waiting for this one */
11862e2caf59SThomas Veerman return 0;
11872e2caf59SThomas Veerman
11882e2caf59SThomas Veerman printf(" `%s%s' has .ORDER dependency against %s%s "
11892e2caf59SThomas Veerman "(made %d, flags %x, type %x)\n",
11902e2caf59SThomas Veerman gn->name, gn->cohort_num,
11912e2caf59SThomas Veerman ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
11922e2caf59SThomas Veerman if (DEBUG(MAKE) && debug_file != stdout)
11932e2caf59SThomas Veerman fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s "
11942e2caf59SThomas Veerman "(made %d, flags %x, type %x)\n",
11952e2caf59SThomas Veerman gn->name, gn->cohort_num,
11962e2caf59SThomas Veerman ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type);
11972e2caf59SThomas Veerman return 0;
11982e2caf59SThomas Veerman }
11992e2caf59SThomas Veerman
12002e2caf59SThomas Veerman static int
MakePrintStatus(void * gnp,void * v_errors)12012e2caf59SThomas Veerman MakePrintStatus(void *gnp, void *v_errors)
12022e2caf59SThomas Veerman {
12032e2caf59SThomas Veerman GNode *gn = (GNode *)gnp;
12042e2caf59SThomas Veerman int *errors = v_errors;
12052e2caf59SThomas Veerman
12062e2caf59SThomas Veerman if (gn->flags & DONECYCLE)
12072e2caf59SThomas Veerman /* We've completely processed this node before, don't do it again. */
12082e2caf59SThomas Veerman return 0;
12092e2caf59SThomas Veerman
12102e2caf59SThomas Veerman if (gn->unmade == 0) {
12112e2caf59SThomas Veerman gn->flags |= DONECYCLE;
12122e2caf59SThomas Veerman switch (gn->made) {
12132e2caf59SThomas Veerman case UPTODATE:
12142e2caf59SThomas Veerman printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num);
12152e2caf59SThomas Veerman break;
12162e2caf59SThomas Veerman case MADE:
12172e2caf59SThomas Veerman break;
12182e2caf59SThomas Veerman case UNMADE:
12192e2caf59SThomas Veerman case DEFERRED:
12202e2caf59SThomas Veerman case REQUESTED:
12212e2caf59SThomas Veerman case BEINGMADE:
12222e2caf59SThomas Veerman (*errors)++;
12232e2caf59SThomas Veerman printf("`%s%s' was not built (made %d, flags %x, type %x)!\n",
12242e2caf59SThomas Veerman gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
12252e2caf59SThomas Veerman if (DEBUG(MAKE) && debug_file != stdout)
12262e2caf59SThomas Veerman fprintf(debug_file,
12272e2caf59SThomas Veerman "`%s%s' was not built (made %d, flags %x, type %x)!\n",
12282e2caf59SThomas Veerman gn->name, gn->cohort_num, gn->made, gn->flags, gn->type);
12292e2caf59SThomas Veerman /* Most likely problem is actually caused by .ORDER */
12302e2caf59SThomas Veerman Lst_ForEach(gn->order_pred, MakePrintStatusOrder, gn);
12312e2caf59SThomas Veerman break;
12322e2caf59SThomas Veerman default:
12332e2caf59SThomas Veerman /* Errors - already counted */
12342e2caf59SThomas Veerman printf("`%s%s' not remade because of errors.\n",
12352e2caf59SThomas Veerman gn->name, gn->cohort_num);
12362e2caf59SThomas Veerman if (DEBUG(MAKE) && debug_file != stdout)
12372e2caf59SThomas Veerman fprintf(debug_file, "`%s%s' not remade because of errors.\n",
12382e2caf59SThomas Veerman gn->name, gn->cohort_num);
12392e2caf59SThomas Veerman break;
12402e2caf59SThomas Veerman }
12412e2caf59SThomas Veerman return 0;
12422e2caf59SThomas Veerman }
12432e2caf59SThomas Veerman
12442e2caf59SThomas Veerman if (DEBUG(MAKE))
12452e2caf59SThomas Veerman fprintf(debug_file, "MakePrintStatus: %s%s has %d unmade children\n",
12462e2caf59SThomas Veerman gn->name, gn->cohort_num, gn->unmade);
12472e2caf59SThomas Veerman /*
12482e2caf59SThomas Veerman * If printing cycles and came to one that has unmade children,
12492e2caf59SThomas Veerman * print out the cycle by recursing on its children.
12502e2caf59SThomas Veerman */
12512e2caf59SThomas Veerman if (!(gn->flags & CYCLE)) {
12522e2caf59SThomas Veerman /* Fist time we've seen this node, check all children */
12532e2caf59SThomas Veerman gn->flags |= CYCLE;
12542e2caf59SThomas Veerman Lst_ForEach(gn->children, MakePrintStatus, errors);
12552e2caf59SThomas Veerman /* Mark that this node needn't be processed again */
12562e2caf59SThomas Veerman gn->flags |= DONECYCLE;
12572e2caf59SThomas Veerman return 0;
12582e2caf59SThomas Veerman }
12592e2caf59SThomas Veerman
12602e2caf59SThomas Veerman /* Only output the error once per node */
12612e2caf59SThomas Veerman gn->flags |= DONECYCLE;
12622e2caf59SThomas Veerman Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num);
12632e2caf59SThomas Veerman if ((*errors)++ > 100)
12642e2caf59SThomas Veerman /* Abandon the whole error report */
12652e2caf59SThomas Veerman return 1;
12662e2caf59SThomas Veerman
12672e2caf59SThomas Veerman /* Reporting for our children will give the rest of the loop */
12682e2caf59SThomas Veerman Lst_ForEach(gn->children, MakePrintStatus, errors);
12692e2caf59SThomas Veerman return 0;
12702e2caf59SThomas Veerman }
12712e2caf59SThomas Veerman
12722e2caf59SThomas Veerman
12732e2caf59SThomas Veerman /*-
12742e2caf59SThomas Veerman *-----------------------------------------------------------------------
12752e2caf59SThomas Veerman * Make_ExpandUse --
12762e2caf59SThomas Veerman * Expand .USE nodes and create a new targets list
12772e2caf59SThomas Veerman *
12782e2caf59SThomas Veerman * Input:
12792e2caf59SThomas Veerman * targs the initial list of targets
12802e2caf59SThomas Veerman *
12812e2caf59SThomas Veerman * Side Effects:
12822e2caf59SThomas Veerman *-----------------------------------------------------------------------
12832e2caf59SThomas Veerman */
12842e2caf59SThomas Veerman void
Make_ExpandUse(Lst targs)12852e2caf59SThomas Veerman Make_ExpandUse(Lst targs)
12862e2caf59SThomas Veerman {
12872e2caf59SThomas Veerman GNode *gn; /* a temporary pointer */
12882e2caf59SThomas Veerman Lst examine; /* List of targets to examine */
12892e2caf59SThomas Veerman
12902e2caf59SThomas Veerman examine = Lst_Duplicate(targs, NULL);
12912e2caf59SThomas Veerman
12922e2caf59SThomas Veerman /*
12932e2caf59SThomas Veerman * Make an initial downward pass over the graph, marking nodes to be made
12942e2caf59SThomas Veerman * as we go down. We call Suff_FindDeps to find where a node is and
12952e2caf59SThomas Veerman * to get some children for it if it has none and also has no commands.
12962e2caf59SThomas Veerman * If the node is a leaf, we stick it on the toBeMade queue to
12972e2caf59SThomas Veerman * be looked at in a minute, otherwise we add its children to our queue
12982e2caf59SThomas Veerman * and go on about our business.
12992e2caf59SThomas Veerman */
13002e2caf59SThomas Veerman while (!Lst_IsEmpty (examine)) {
13012e2caf59SThomas Veerman gn = (GNode *)Lst_DeQueue(examine);
13022e2caf59SThomas Veerman
13032e2caf59SThomas Veerman if (gn->flags & REMAKE)
13042e2caf59SThomas Veerman /* We've looked at this one already */
13052e2caf59SThomas Veerman continue;
13062e2caf59SThomas Veerman gn->flags |= REMAKE;
13072e2caf59SThomas Veerman if (DEBUG(MAKE))
13082e2caf59SThomas Veerman fprintf(debug_file, "Make_ExpandUse: examine %s%s\n",
13092e2caf59SThomas Veerman gn->name, gn->cohort_num);
13102e2caf59SThomas Veerman
13112e2caf59SThomas Veerman if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) {
13122e2caf59SThomas Veerman /* Append all the 'cohorts' to the list of things to examine */
13132e2caf59SThomas Veerman Lst new;
13142e2caf59SThomas Veerman new = Lst_Duplicate(gn->cohorts, NULL);
13152e2caf59SThomas Veerman Lst_Concat(new, examine, LST_CONCLINK);
13162e2caf59SThomas Veerman examine = new;
13172e2caf59SThomas Veerman }
13182e2caf59SThomas Veerman
13192e2caf59SThomas Veerman /*
13202e2caf59SThomas Veerman * Apply any .USE rules before looking for implicit dependencies
13212e2caf59SThomas Veerman * to make sure everything has commands that should...
13222e2caf59SThomas Veerman * Make sure that the TARGET is set, so that we can make
13232e2caf59SThomas Veerman * expansions.
13242e2caf59SThomas Veerman */
13252e2caf59SThomas Veerman if (gn->type & OP_ARCHV) {
13262e2caf59SThomas Veerman char *eoa, *eon;
13272e2caf59SThomas Veerman eoa = strchr(gn->name, '(');
13282e2caf59SThomas Veerman eon = strchr(gn->name, ')');
13292e2caf59SThomas Veerman if (eoa == NULL || eon == NULL)
13302e2caf59SThomas Veerman continue;
13312e2caf59SThomas Veerman *eoa = '\0';
13322e2caf59SThomas Veerman *eon = '\0';
13332e2caf59SThomas Veerman Var_Set(MEMBER, eoa + 1, gn, 0);
13342e2caf59SThomas Veerman Var_Set(ARCHIVE, gn->name, gn, 0);
13352e2caf59SThomas Veerman *eoa = '(';
13362e2caf59SThomas Veerman *eon = ')';
13372e2caf59SThomas Veerman }
13382e2caf59SThomas Veerman
13392e2caf59SThomas Veerman (void)Dir_MTime(gn, 0);
13402e2caf59SThomas Veerman Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0);
13412e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeUnmark, gn);
13422e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeHandleUse, gn);
13432e2caf59SThomas Veerman
13442e2caf59SThomas Veerman if ((gn->type & OP_MADE) == 0)
13452e2caf59SThomas Veerman Suff_FindDeps(gn);
13462e2caf59SThomas Veerman else {
13472e2caf59SThomas Veerman /* Pretend we made all this node's children */
13482e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeFindChild, gn);
13492e2caf59SThomas Veerman if (gn->unmade != 0)
13502e2caf59SThomas Veerman printf("Warning: %s%s still has %d unmade children\n",
13512e2caf59SThomas Veerman gn->name, gn->cohort_num, gn->unmade);
13522e2caf59SThomas Veerman }
13532e2caf59SThomas Veerman
13542e2caf59SThomas Veerman if (gn->unmade != 0)
13552e2caf59SThomas Veerman Lst_ForEach(gn->children, MakeAddChild, examine);
13562e2caf59SThomas Veerman }
13572e2caf59SThomas Veerman
13582e2caf59SThomas Veerman Lst_Destroy(examine, NULL);
13592e2caf59SThomas Veerman }
13602e2caf59SThomas Veerman
13612e2caf59SThomas Veerman /*-
13622e2caf59SThomas Veerman *-----------------------------------------------------------------------
13632e2caf59SThomas Veerman * Make_ProcessWait --
13642e2caf59SThomas Veerman * Convert .WAIT nodes into dependencies
13652e2caf59SThomas Veerman *
13662e2caf59SThomas Veerman * Input:
13672e2caf59SThomas Veerman * targs the initial list of targets
13682e2caf59SThomas Veerman *
13692e2caf59SThomas Veerman *-----------------------------------------------------------------------
13702e2caf59SThomas Veerman */
13712e2caf59SThomas Veerman
13722e2caf59SThomas Veerman static int
link_parent(void * cnp,void * pnp)13732e2caf59SThomas Veerman link_parent(void *cnp, void *pnp)
13742e2caf59SThomas Veerman {
13752e2caf59SThomas Veerman GNode *cn = cnp;
13762e2caf59SThomas Veerman GNode *pn = pnp;
13772e2caf59SThomas Veerman
13782e2caf59SThomas Veerman Lst_AtEnd(pn->children, cn);
13792e2caf59SThomas Veerman Lst_AtEnd(cn->parents, pn);
13802e2caf59SThomas Veerman pn->unmade++;
13812e2caf59SThomas Veerman return 0;
13822e2caf59SThomas Veerman }
13832e2caf59SThomas Veerman
13842e2caf59SThomas Veerman static int
add_wait_dep(void * v_cn,void * v_wn)13852e2caf59SThomas Veerman add_wait_dep(void *v_cn, void *v_wn)
13862e2caf59SThomas Veerman {
13872e2caf59SThomas Veerman GNode *cn = v_cn;
13882e2caf59SThomas Veerman GNode *wn = v_wn;
13892e2caf59SThomas Veerman
13902e2caf59SThomas Veerman if (cn == wn)
13912e2caf59SThomas Veerman return 1;
13922e2caf59SThomas Veerman
13932e2caf59SThomas Veerman if (cn == NULL || wn == NULL) {
13942e2caf59SThomas Veerman printf("bad wait dep %p %p\n", cn, wn);
13952e2caf59SThomas Veerman exit(4);
13962e2caf59SThomas Veerman }
13972e2caf59SThomas Veerman if (DEBUG(MAKE))
13982e2caf59SThomas Veerman fprintf(debug_file, ".WAIT: add dependency %s%s -> %s\n",
13992e2caf59SThomas Veerman cn->name, cn->cohort_num, wn->name);
14002e2caf59SThomas Veerman
14012e2caf59SThomas Veerman Lst_AtEnd(wn->children, cn);
14022e2caf59SThomas Veerman wn->unmade++;
14032e2caf59SThomas Veerman Lst_AtEnd(cn->parents, wn);
14042e2caf59SThomas Veerman return 0;
14052e2caf59SThomas Veerman }
14062e2caf59SThomas Veerman
14072e2caf59SThomas Veerman static void
Make_ProcessWait(Lst targs)14082e2caf59SThomas Veerman Make_ProcessWait(Lst targs)
14092e2caf59SThomas Veerman {
14102e2caf59SThomas Veerman GNode *pgn; /* 'parent' node we are examining */
14112e2caf59SThomas Veerman GNode *cgn; /* Each child in turn */
14122e2caf59SThomas Veerman LstNode owln; /* Previous .WAIT node */
14132e2caf59SThomas Veerman Lst examine; /* List of targets to examine */
14142e2caf59SThomas Veerman LstNode ln;
14152e2caf59SThomas Veerman
14162e2caf59SThomas Veerman /*
14172e2caf59SThomas Veerman * We need all the nodes to have a common parent in order for the
14182e2caf59SThomas Veerman * .WAIT and .ORDER scheduling to work.
14192e2caf59SThomas Veerman * Perhaps this should be done earlier...
14202e2caf59SThomas Veerman */
14212e2caf59SThomas Veerman
14222e2caf59SThomas Veerman pgn = Targ_NewGN(".MAIN");
14232e2caf59SThomas Veerman pgn->flags = REMAKE;
14242e2caf59SThomas Veerman pgn->type = OP_PHONY | OP_DEPENDS;
14252e2caf59SThomas Veerman /* Get it displayed in the diag dumps */
14262e2caf59SThomas Veerman Lst_AtFront(Targ_List(), pgn);
14272e2caf59SThomas Veerman
14282e2caf59SThomas Veerman Lst_ForEach(targs, link_parent, pgn);
14292e2caf59SThomas Veerman
14302e2caf59SThomas Veerman /* Start building with the 'dummy' .MAIN' node */
14312e2caf59SThomas Veerman MakeBuildChild(pgn, NULL);
14322e2caf59SThomas Veerman
14332e2caf59SThomas Veerman examine = Lst_Init(FALSE);
14342e2caf59SThomas Veerman Lst_AtEnd(examine, pgn);
14352e2caf59SThomas Veerman
14362e2caf59SThomas Veerman while (!Lst_IsEmpty (examine)) {
14372e2caf59SThomas Veerman pgn = Lst_DeQueue(examine);
14382e2caf59SThomas Veerman
14392e2caf59SThomas Veerman /* We only want to process each child-list once */
14402e2caf59SThomas Veerman if (pgn->flags & DONE_WAIT)
14412e2caf59SThomas Veerman continue;
14422e2caf59SThomas Veerman pgn->flags |= DONE_WAIT;
14432e2caf59SThomas Veerman if (DEBUG(MAKE))
14442e2caf59SThomas Veerman fprintf(debug_file, "Make_ProcessWait: examine %s\n", pgn->name);
14452e2caf59SThomas Veerman
14462e2caf59SThomas Veerman if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) {
14472e2caf59SThomas Veerman /* Append all the 'cohorts' to the list of things to examine */
14482e2caf59SThomas Veerman Lst new;
14492e2caf59SThomas Veerman new = Lst_Duplicate(pgn->cohorts, NULL);
14502e2caf59SThomas Veerman Lst_Concat(new, examine, LST_CONCLINK);
14512e2caf59SThomas Veerman examine = new;
14522e2caf59SThomas Veerman }
14532e2caf59SThomas Veerman
14542e2caf59SThomas Veerman owln = Lst_First(pgn->children);
14552e2caf59SThomas Veerman Lst_Open(pgn->children);
14562e2caf59SThomas Veerman for (; (ln = Lst_Next(pgn->children)) != NULL; ) {
14572e2caf59SThomas Veerman cgn = Lst_Datum(ln);
14582e2caf59SThomas Veerman if (cgn->type & OP_WAIT) {
14592e2caf59SThomas Veerman /* Make the .WAIT node depend on the previous children */
14602e2caf59SThomas Veerman Lst_ForEachFrom(pgn->children, owln, add_wait_dep, cgn);
14612e2caf59SThomas Veerman owln = ln;
14622e2caf59SThomas Veerman } else {
14632e2caf59SThomas Veerman Lst_AtEnd(examine, cgn);
14642e2caf59SThomas Veerman }
14652e2caf59SThomas Veerman }
14662e2caf59SThomas Veerman Lst_Close(pgn->children);
14672e2caf59SThomas Veerman }
14682e2caf59SThomas Veerman
14692e2caf59SThomas Veerman Lst_Destroy(examine, NULL);
14702e2caf59SThomas Veerman }
14712e2caf59SThomas Veerman
14722e2caf59SThomas Veerman /*-
14732e2caf59SThomas Veerman *-----------------------------------------------------------------------
14742e2caf59SThomas Veerman * Make_Run --
14752e2caf59SThomas Veerman * Initialize the nodes to remake and the list of nodes which are
14762e2caf59SThomas Veerman * ready to be made by doing a breadth-first traversal of the graph
14772e2caf59SThomas Veerman * starting from the nodes in the given list. Once this traversal
14782e2caf59SThomas Veerman * is finished, all the 'leaves' of the graph are in the toBeMade
14792e2caf59SThomas Veerman * queue.
14802e2caf59SThomas Veerman * Using this queue and the Job module, work back up the graph,
14812e2caf59SThomas Veerman * calling on MakeStartJobs to keep the job table as full as
14822e2caf59SThomas Veerman * possible.
14832e2caf59SThomas Veerman *
14842e2caf59SThomas Veerman * Input:
14852e2caf59SThomas Veerman * targs the initial list of targets
14862e2caf59SThomas Veerman *
14872e2caf59SThomas Veerman * Results:
14882e2caf59SThomas Veerman * TRUE if work was done. FALSE otherwise.
14892e2caf59SThomas Veerman *
14902e2caf59SThomas Veerman * Side Effects:
14912e2caf59SThomas Veerman * The make field of all nodes involved in the creation of the given
14922e2caf59SThomas Veerman * targets is set to 1. The toBeMade list is set to contain all the
14932e2caf59SThomas Veerman * 'leaves' of these subgraphs.
14942e2caf59SThomas Veerman *-----------------------------------------------------------------------
14952e2caf59SThomas Veerman */
14962e2caf59SThomas Veerman Boolean
Make_Run(Lst targs)14972e2caf59SThomas Veerman Make_Run(Lst targs)
14982e2caf59SThomas Veerman {
14992e2caf59SThomas Veerman int errors; /* Number of errors the Job module reports */
15002e2caf59SThomas Veerman
15012e2caf59SThomas Veerman /* Start trying to make the current targets... */
15022e2caf59SThomas Veerman toBeMade = Lst_Init(FALSE);
15032e2caf59SThomas Veerman
15042e2caf59SThomas Veerman Make_ExpandUse(targs);
15052e2caf59SThomas Veerman Make_ProcessWait(targs);
15062e2caf59SThomas Veerman
15072e2caf59SThomas Veerman if (DEBUG(MAKE)) {
15082e2caf59SThomas Veerman fprintf(debug_file, "#***# full graph\n");
15092e2caf59SThomas Veerman Targ_PrintGraph(1);
15102e2caf59SThomas Veerman }
15112e2caf59SThomas Veerman
15122e2caf59SThomas Veerman if (queryFlag) {
15132e2caf59SThomas Veerman /*
15142e2caf59SThomas Veerman * We wouldn't do any work unless we could start some jobs in the
15152e2caf59SThomas Veerman * next loop... (we won't actually start any, of course, this is just
15162e2caf59SThomas Veerman * to see if any of the targets was out of date)
15172e2caf59SThomas Veerman */
15182e2caf59SThomas Veerman return (MakeStartJobs());
15192e2caf59SThomas Veerman }
15202e2caf59SThomas Veerman /*
15212e2caf59SThomas Veerman * Initialization. At the moment, no jobs are running and until some
15222e2caf59SThomas Veerman * get started, nothing will happen since the remaining upward
15232e2caf59SThomas Veerman * traversal of the graph is performed by the routines in job.c upon
15242e2caf59SThomas Veerman * the finishing of a job. So we fill the Job table as much as we can
15252e2caf59SThomas Veerman * before going into our loop.
15262e2caf59SThomas Veerman */
15272e2caf59SThomas Veerman (void)MakeStartJobs();
15282e2caf59SThomas Veerman
15292e2caf59SThomas Veerman /*
15302e2caf59SThomas Veerman * Main Loop: The idea here is that the ending of jobs will take
15312e2caf59SThomas Veerman * care of the maintenance of data structures and the waiting for output
15322e2caf59SThomas Veerman * will cause us to be idle most of the time while our children run as
15332e2caf59SThomas Veerman * much as possible. Because the job table is kept as full as possible,
15342e2caf59SThomas Veerman * the only time when it will be empty is when all the jobs which need
15352e2caf59SThomas Veerman * running have been run, so that is the end condition of this loop.
15362e2caf59SThomas Veerman * Note that the Job module will exit if there were any errors unless the
15372e2caf59SThomas Veerman * keepgoing flag was given.
15382e2caf59SThomas Veerman */
15392e2caf59SThomas Veerman while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) {
15402e2caf59SThomas Veerman Job_CatchOutput();
15412e2caf59SThomas Veerman (void)MakeStartJobs();
15422e2caf59SThomas Veerman }
15432e2caf59SThomas Veerman
15442e2caf59SThomas Veerman errors = Job_Finish();
15452e2caf59SThomas Veerman
15462e2caf59SThomas Veerman /*
15472e2caf59SThomas Veerman * Print the final status of each target. E.g. if it wasn't made
15482e2caf59SThomas Veerman * because some inferior reported an error.
15492e2caf59SThomas Veerman */
15502e2caf59SThomas Veerman if (DEBUG(MAKE))
15512e2caf59SThomas Veerman fprintf(debug_file, "done: errors %d\n", errors);
15522e2caf59SThomas Veerman if (errors == 0) {
15532e2caf59SThomas Veerman Lst_ForEach(targs, MakePrintStatus, &errors);
15542e2caf59SThomas Veerman if (DEBUG(MAKE)) {
15552e2caf59SThomas Veerman fprintf(debug_file, "done: errors %d\n", errors);
15562e2caf59SThomas Veerman if (errors)
15572e2caf59SThomas Veerman Targ_PrintGraph(4);
15582e2caf59SThomas Veerman }
15592e2caf59SThomas Veerman }
15602e2caf59SThomas Veerman return errors != 0;
15612e2caf59SThomas Veerman }
1562