Annotation of src/usr.bin/make/make.c, Revision 1.1
1.1 ! cgd 1: /*
! 2: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
! 3: * Copyright (c) 1988, 1989 by Adam de Boor
! 4: * Copyright (c) 1989 by Berkeley Softworks
! 5: * All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to Berkeley by
! 8: * Adam de Boor.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the University of
! 21: * California, Berkeley and its contributors.
! 22: * 4. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: */
! 38:
! 39: #ifndef lint
! 40: static char sccsid[] = "@(#)make.c 5.3 (Berkeley) 6/1/90";
! 41: #endif /* not lint */
! 42:
! 43: /*-
! 44: * make.c --
! 45: * The functions which perform the examination of targets and
! 46: * their suitability for creation
! 47: *
! 48: * Interface:
! 49: * Make_Run Initialize things for the module and recreate
! 50: * whatever needs recreating. Returns TRUE if
! 51: * work was (or would have been) done and FALSE
! 52: * otherwise.
! 53: *
! 54: * Make_Update Update all parents of a given child. Performs
! 55: * various bookkeeping chores like the updating
! 56: * of the cmtime field of the parent, filling
! 57: * of the IMPSRC context variable, etc. It will
! 58: * place the parent on the toBeMade queue if it
! 59: * should be.
! 60: *
! 61: * Make_TimeStamp Function to set the parent's cmtime field
! 62: * based on a child's modification time.
! 63: *
! 64: * Make_DoAllVar Set up the various local variables for a
! 65: * target, including the .ALLSRC variable, making
! 66: * sure that any variable that needs to exist
! 67: * at the very least has the empty value.
! 68: *
! 69: * Make_OODate Determine if a target is out-of-date.
! 70: *
! 71: * Make_HandleUse See if a child is a .USE node for a parent
! 72: * and perform the .USE actions if so.
! 73: */
! 74:
! 75: #include "make.h"
! 76:
! 77: static Lst toBeMade; /* The current fringe of the graph. These
! 78: * are nodes which await examination by
! 79: * MakeOODate. It is added to by
! 80: * Make_Update and subtracted from by
! 81: * MakeStartJobs */
! 82: static int numNodes; /* Number of nodes to be processed. If this
! 83: * is non-zero when Job_Empty() returns
! 84: * TRUE, there's a cycle in the graph */
! 85:
! 86: /*-
! 87: *-----------------------------------------------------------------------
! 88: * Make_TimeStamp --
! 89: * Set the cmtime field of a parent node based on the mtime stamp in its
! 90: * child. Called from MakeOODate via Lst_ForEach.
! 91: *
! 92: * Results:
! 93: * Always returns 0.
! 94: *
! 95: * Side Effects:
! 96: * The cmtime of the parent node will be changed if the mtime
! 97: * field of the child is greater than it.
! 98: *-----------------------------------------------------------------------
! 99: */
! 100: int
! 101: Make_TimeStamp (pgn, cgn)
! 102: register GNode *pgn; /* the current parent */
! 103: register GNode *cgn; /* the child we've just examined */
! 104: {
! 105: if (cgn->mtime > pgn->cmtime) {
! 106: pgn->cmtime = cgn->mtime;
! 107: }
! 108: return (0);
! 109: }
! 110:
! 111: /*-
! 112: *-----------------------------------------------------------------------
! 113: * Make_OODate --
! 114: * See if a given node is out of date with respect to its sources.
! 115: * Used by Make_Run when deciding which nodes to place on the
! 116: * toBeMade queue initially and by Make_Update to screen out USE and
! 117: * EXEC nodes. In the latter case, however, any other sort of node
! 118: * must be considered out-of-date since at least one of its children
! 119: * will have been recreated.
! 120: *
! 121: * Results:
! 122: * TRUE if the node is out of date. FALSE otherwise.
! 123: *
! 124: * Side Effects:
! 125: * The mtime field of the node and the cmtime field of its parents
! 126: * will/may be changed.
! 127: *-----------------------------------------------------------------------
! 128: */
! 129: Boolean
! 130: Make_OODate (gn)
! 131: register GNode *gn; /* the node to check */
! 132: {
! 133: Boolean oodate;
! 134:
! 135: /*
! 136: * Certain types of targets needn't even be sought as their datedness
! 137: * doesn't depend on their modification time...
! 138: */
! 139: if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) {
! 140: (void) Dir_MTime (gn);
! 141: if (DEBUG(MAKE)) {
! 142: if (gn->mtime != 0) {
! 143: printf ("modified %s...", Targ_FmtTime(gn->mtime));
! 144: } else {
! 145: printf ("non-existent...");
! 146: }
! 147: }
! 148: }
! 149:
! 150: /*
! 151: * A target is remade in one of the following circumstances:
! 152: * its modification time is smaller than that of its youngest child
! 153: * and it would actually be run (has commands or type OP_NOP)
! 154: * it's the object of a force operator
! 155: * it has no children, was on the lhs of an operator and doesn't exist
! 156: * already.
! 157: *
! 158: * Libraries are only considered out-of-date if the archive module says
! 159: * they are.
! 160: *
! 161: * These weird rules are brought to you by Backward-Compatability and
! 162: * the strange people who wrote 'Make'.
! 163: */
! 164: if (gn->type & OP_USE) {
! 165: /*
! 166: * If the node is a USE node it is *never* out of date
! 167: * no matter *what*.
! 168: */
! 169: if (DEBUG(MAKE)) {
! 170: printf(".USE node...");
! 171: }
! 172: oodate = FALSE;
! 173: } else if (gn->type & OP_LIB) {
! 174: if (DEBUG(MAKE)) {
! 175: printf("library...");
! 176: }
! 177: oodate = Arch_LibOODate (gn);
! 178: } else if (gn->type & OP_JOIN) {
! 179: /*
! 180: * A target with the .JOIN attribute is only considered
! 181: * out-of-date if any of its children was out-of-date.
! 182: */
! 183: if (DEBUG(MAKE)) {
! 184: printf(".JOIN node...");
! 185: }
! 186: oodate = gn->childMade;
! 187: } else if (gn->type & (OP_FORCE|OP_EXEC)) {
! 188: /*
! 189: * A node which is the object of the force (!) operator or which has
! 190: * the .EXEC attribute is always considered out-of-date.
! 191: */
! 192: if (DEBUG(MAKE)) {
! 193: if (gn->type & OP_FORCE) {
! 194: printf("! operator...");
! 195: } else {
! 196: printf(".EXEC node...");
! 197: }
! 198: }
! 199: oodate = TRUE;
! 200: } else if ((gn->mtime < gn->cmtime) ||
! 201: ((gn->cmtime == 0) &&
! 202: ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP))))
! 203: {
! 204: /*
! 205: * A node whose modification time is less than that of its
! 206: * youngest child or that has no children (cmtime == 0) and
! 207: * either doesn't exist (mtime == 0) or was the object of a
! 208: * :: operator is out-of-date. Why? Because that's the way Make does
! 209: * it.
! 210: */
! 211: if (DEBUG(MAKE)) {
! 212: if (gn->mtime < gn->cmtime) {
! 213: printf("modified before source...");
! 214: } else if (gn->mtime == 0) {
! 215: printf("non-existent and no sources...");
! 216: } else {
! 217: printf(":: operator and no sources...");
! 218: }
! 219: }
! 220: oodate = TRUE;
! 221: } else {
! 222: #if 0
! 223: /* WHY? */
! 224: if (DEBUG(MAKE)) {
! 225: printf("source %smade...", gn->childMade ? "" : "not ");
! 226: }
! 227: oodate = gn->childMade;
! 228: #else
! 229: oodate = FALSE;
! 230: #endif /* 0 */
! 231: }
! 232:
! 233: /*
! 234: * If the target isn't out-of-date, the parents need to know its
! 235: * modification time. Note that targets that appear to be out-of-date
! 236: * but aren't, because they have no commands and aren't of type OP_NOP,
! 237: * have their mtime stay below their children's mtime to keep parents from
! 238: * thinking they're out-of-date.
! 239: */
! 240: if (!oodate) {
! 241: Lst_ForEach (gn->parents, Make_TimeStamp, (ClientData)gn);
! 242: }
! 243:
! 244: return (oodate);
! 245: }
! 246:
! 247: /*-
! 248: *-----------------------------------------------------------------------
! 249: * MakeAddChild --
! 250: * Function used by Make_Run to add a child to the list l.
! 251: * It will only add the child if its make field is FALSE.
! 252: *
! 253: * Results:
! 254: * Always returns 0
! 255: *
! 256: * Side Effects:
! 257: * The given list is extended
! 258: *-----------------------------------------------------------------------
! 259: */
! 260: static int
! 261: MakeAddChild (gn, l)
! 262: GNode *gn; /* the node to add */
! 263: Lst l; /* the list to which to add it */
! 264: {
! 265: if (!gn->make && !(gn->type & OP_USE)) {
! 266: (void)Lst_EnQueue (l, (ClientData)gn);
! 267: }
! 268: return (0);
! 269: }
! 270:
! 271: /*-
! 272: *-----------------------------------------------------------------------
! 273: * Make_HandleUse --
! 274: * Function called by Make_Run and SuffApplyTransform on the downward
! 275: * pass to handle .USE and transformation nodes. A callback function
! 276: * for Lst_ForEach, it implements the .USE and transformation
! 277: * functionality by copying the node's commands, type flags
! 278: * and children to the parent node. Should be called before the
! 279: * children are enqueued to be looked at by MakeAddChild.
! 280: *
! 281: * A .USE node is much like an explicit transformation rule, except
! 282: * its commands are always added to the target node, even if the
! 283: * target already has commands.
! 284: *
! 285: * Results:
! 286: * returns 0.
! 287: *
! 288: * Side Effects:
! 289: * Children and commands may be added to the parent and the parent's
! 290: * type may be changed.
! 291: *
! 292: *-----------------------------------------------------------------------
! 293: */
! 294: int
! 295: Make_HandleUse (cgn, pgn)
! 296: register GNode *cgn; /* The .USE node */
! 297: register GNode *pgn; /* The target of the .USE node */
! 298: {
! 299: register GNode *gn; /* A child of the .USE node */
! 300: register LstNode ln; /* An element in the children list */
! 301:
! 302: if (cgn->type & (OP_USE|OP_TRANSFORM)) {
! 303: if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) {
! 304: /*
! 305: * .USE or transformation and target has no commands -- append
! 306: * the child's commands to the parent.
! 307: */
! 308: (void) Lst_Concat (pgn->commands, cgn->commands, LST_CONCNEW);
! 309: }
! 310:
! 311: if (Lst_Open (cgn->children) == SUCCESS) {
! 312: while ((ln = Lst_Next (cgn->children)) != NILLNODE) {
! 313: gn = (GNode *)Lst_Datum (ln);
! 314:
! 315: if (Lst_Member (pgn->children, gn) == NILLNODE) {
! 316: (void) Lst_AtEnd (pgn->children, gn);
! 317: (void) Lst_AtEnd (gn->parents, pgn);
! 318: pgn->unmade += 1;
! 319: }
! 320: }
! 321: Lst_Close (cgn->children);
! 322: }
! 323:
! 324: pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);
! 325:
! 326: /*
! 327: * This child node is now "made", so we decrement the count of
! 328: * unmade children in the parent... We also remove the child
! 329: * from the parent's list to accurately reflect the number of decent
! 330: * children the parent has. This is used by Make_Run to decide
! 331: * whether to queue the parent or examine its children...
! 332: */
! 333: if (cgn->type & OP_USE) {
! 334: pgn->unmade -= 1;
! 335: }
! 336: }
! 337: return (0);
! 338: }
! 339:
! 340: /*-
! 341: *-----------------------------------------------------------------------
! 342: * Make_Update --
! 343: * Perform update on the parents of a node. Used by JobFinish once
! 344: * a node has been dealt with and by MakeStartJobs if it finds an
! 345: * up-to-date node.
! 346: *
! 347: * Results:
! 348: * Always returns 0
! 349: *
! 350: * Side Effects:
! 351: * The unmade field of pgn is decremented and pgn may be placed on
! 352: * the toBeMade queue if this field becomes 0.
! 353: *
! 354: * If the child was made, the parent's childMade field will be set true
! 355: * and its cmtime set to now.
! 356: *
! 357: * If the child wasn't made, the cmtime field of the parent will be
! 358: * altered if the child's mtime is big enough.
! 359: *
! 360: * Finally, if the child is the implied source for the parent, the
! 361: * parent's IMPSRC variable is set appropriately.
! 362: *
! 363: *-----------------------------------------------------------------------
! 364: */
! 365: void
! 366: Make_Update (cgn)
! 367: register GNode *cgn; /* the child node */
! 368: {
! 369: register GNode *pgn; /* the parent node */
! 370: register char *cname; /* the child's name */
! 371: register LstNode ln; /* Element in parents and iParents lists */
! 372:
! 373: cname = Var_Value (TARGET, cgn);
! 374:
! 375: /*
! 376: * If the child was actually made, see what its modification time is
! 377: * now -- some rules won't actually update the file. If the file still
! 378: * doesn't exist, make its mtime now.
! 379: */
! 380: if (cgn->made != UPTODATE) {
! 381: #ifndef RECHECK
! 382: /*
! 383: * We can't re-stat the thing, but we can at least take care of rules
! 384: * where a target depends on a source that actually creates the
! 385: * target, but only if it has changed, e.g.
! 386: *
! 387: * parse.h : parse.o
! 388: *
! 389: * parse.o : parse.y
! 390: * yacc -d parse.y
! 391: * cc -c y.tab.c
! 392: * mv y.tab.o parse.o
! 393: * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
! 394: *
! 395: * In this case, if the definitions produced by yacc haven't changed
! 396: * from before, parse.h won't have been updated and cgn->mtime will
! 397: * reflect the current modification time for parse.h. This is
! 398: * something of a kludge, I admit, but it's a useful one..
! 399: * XXX: People like to use a rule like
! 400: *
! 401: * FRC:
! 402: *
! 403: * To force things that depend on FRC to be made, so we have to
! 404: * check for gn->children being empty as well...
! 405: */
! 406: if (!Lst_IsEmpty(cgn->commands) || Lst_IsEmpty(cgn->children)) {
! 407: cgn->mtime = now;
! 408: }
! 409: #else
! 410: /*
! 411: * This is what Make does and it's actually a good thing, as it
! 412: * allows rules like
! 413: *
! 414: * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
! 415: *
! 416: * to function as intended. Unfortunately, thanks to the stateless
! 417: * nature of NFS (by which I mean the loose coupling of two clients
! 418: * using the same file from a common server), there are times
! 419: * when the modification time of a file created on a remote
! 420: * machine will not be modified before the local stat() implied by
! 421: * the Dir_MTime occurs, thus leading us to believe that the file
! 422: * is unchanged, wreaking havoc with files that depend on this one.
! 423: *
! 424: * I have decided it is better to make too much than to make too
! 425: * little, so this stuff is commented out unless you're sure it's ok.
! 426: * -- ardeb 1/12/88
! 427: */
! 428: if (noExecute || Dir_MTime(cgn) == 0) {
! 429: cgn->mtime = now;
! 430: }
! 431: if (DEBUG(MAKE)) {
! 432: printf("update time: %s\n", Targ_FmtTime(cgn->mtime));
! 433: }
! 434: #endif
! 435: }
! 436:
! 437: if (Lst_Open (cgn->parents) == SUCCESS) {
! 438: while ((ln = Lst_Next (cgn->parents)) != NILLNODE) {
! 439: pgn = (GNode *)Lst_Datum (ln);
! 440: if (pgn->make) {
! 441: pgn->unmade -= 1;
! 442:
! 443: if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
! 444: if (cgn->made == MADE) {
! 445: pgn->childMade = TRUE;
! 446: if (pgn->cmtime < cgn->mtime) {
! 447: pgn->cmtime = cgn->mtime;
! 448: }
! 449: } else {
! 450: (void)Make_TimeStamp (pgn, cgn);
! 451: }
! 452: }
! 453: if (pgn->unmade == 0) {
! 454: /*
! 455: * Queue the node up -- any unmade predecessors will
! 456: * be dealt with in MakeStartJobs.
! 457: */
! 458: (void)Lst_EnQueue (toBeMade, (ClientData)pgn);
! 459: } else if (pgn->unmade < 0) {
! 460: Error ("Graph cycles through %s", pgn->name);
! 461: }
! 462: }
! 463: }
! 464: Lst_Close (cgn->parents);
! 465: }
! 466: /*
! 467: * Deal with successor nodes. If any is marked for making and has an unmade
! 468: * count of 0, has not been made and isn't in the examination queue,
! 469: * it means we need to place it in the queue as it restrained itself
! 470: * before.
! 471: */
! 472: for (ln = Lst_First(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) {
! 473: GNode *succ = (GNode *)Lst_Datum(ln);
! 474:
! 475: if (succ->make && succ->unmade == 0 && succ->made == UNMADE &&
! 476: Lst_Member(toBeMade, (ClientData)succ) == NILLNODE)
! 477: {
! 478: (void)Lst_EnQueue(toBeMade, (ClientData)succ);
! 479: }
! 480: }
! 481:
! 482: /*
! 483: * Set the .PREFIX and .IMPSRC variables for all the implied parents
! 484: * of this node.
! 485: */
! 486: if (Lst_Open (cgn->iParents) == SUCCESS) {
! 487: char *cpref = Var_Value(PREFIX, cgn);
! 488:
! 489: while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) {
! 490: pgn = (GNode *)Lst_Datum (ln);
! 491: if (pgn->make) {
! 492: Var_Set (IMPSRC, cname, pgn);
! 493: Var_Set (PREFIX, cpref, pgn);
! 494: }
! 495: }
! 496: Lst_Close (cgn->iParents);
! 497: }
! 498: }
! 499:
! 500: /*-
! 501: *-----------------------------------------------------------------------
! 502: * MakeAddAllSrc --
! 503: * Add a child's name to the ALLSRC and OODATE variables of the given
! 504: * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only
! 505: * if it has not been given the .EXEC, .USE or .INVISIBLE attributes.
! 506: * .EXEC and .USE children are very rarely going to be files, so...
! 507: * A child is added to the OODATE variable if its modification time is
! 508: * later than that of its parent, as defined by Make, except if the
! 509: * parent is a .JOIN node. In that case, it is only added to the OODATE
! 510: * variable if it was actually made (since .JOIN nodes don't have
! 511: * modification times, the comparison is rather unfair...)..
! 512: *
! 513: * Results:
! 514: * Always returns 0
! 515: *
! 516: * Side Effects:
! 517: * The ALLSRC variable for the given node is extended.
! 518: *-----------------------------------------------------------------------
! 519: */
! 520: static int
! 521: MakeAddAllSrc (cgn, pgn)
! 522: GNode *cgn; /* The child to add */
! 523: GNode *pgn; /* The parent to whose ALLSRC variable it should be */
! 524: /* added */
! 525: {
! 526: if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) {
! 527: register char *child;
! 528:
! 529: child = Var_Value(TARGET, cgn);
! 530: Var_Append (ALLSRC, child, pgn);
! 531: if (pgn->type & OP_JOIN) {
! 532: if (cgn->made == MADE) {
! 533: Var_Append(OODATE, child, pgn);
! 534: }
! 535: } else if ((pgn->mtime < cgn->mtime) ||
! 536: (cgn->mtime >= now && cgn->made == MADE))
! 537: {
! 538: /*
! 539: * It goes in the OODATE variable if the parent is younger than the
! 540: * child or if the child has been modified more recently than
! 541: * the start of the make. This is to keep pmake from getting
! 542: * confused if something else updates the parent after the
! 543: * make starts (shouldn't happen, I know, but sometimes it
! 544: * does). In such a case, if we've updated the kid, the parent
! 545: * is likely to have a modification time later than that of
! 546: * the kid and anything that relies on the OODATE variable will
! 547: * be hosed.
! 548: *
! 549: * XXX: This will cause all made children to go in the OODATE
! 550: * variable, even if they're not touched, if RECHECK isn't defined,
! 551: * since cgn->mtime is set to now in Make_Update. According to
! 552: * some people, this is good...
! 553: */
! 554: Var_Append(OODATE, child, pgn);
! 555: }
! 556: }
! 557: return (0);
! 558: }
! 559:
! 560: /*-
! 561: *-----------------------------------------------------------------------
! 562: * Make_DoAllVar --
! 563: * Set up the ALLSRC and OODATE variables. Sad to say, it must be
! 564: * done separately, rather than while traversing the graph. This is
! 565: * because Make defined OODATE to contain all sources whose modification
! 566: * times were later than that of the target, *not* those sources that
! 567: * were out-of-date. Since in both compatibility and native modes,
! 568: * the modification time of the parent isn't found until the child
! 569: * has been dealt with, we have to wait until now to fill in the
! 570: * variable. As for ALLSRC, the ordering is important and not
! 571: * guaranteed when in native mode, so it must be set here, too.
! 572: *
! 573: * Results:
! 574: * None
! 575: *
! 576: * Side Effects:
! 577: * The ALLSRC and OODATE variables of the given node is filled in.
! 578: * If the node is a .JOIN node, its TARGET variable will be set to
! 579: * match its ALLSRC variable.
! 580: *-----------------------------------------------------------------------
! 581: */
! 582: void
! 583: Make_DoAllVar (gn)
! 584: GNode *gn;
! 585: {
! 586: Lst_ForEach (gn->children, MakeAddAllSrc, gn);
! 587:
! 588: if (!Var_Exists (OODATE, gn)) {
! 589: Var_Set (OODATE, "", gn);
! 590: }
! 591: if (!Var_Exists (ALLSRC, gn)) {
! 592: Var_Set (ALLSRC, "", gn);
! 593: }
! 594:
! 595: if (gn->type & OP_JOIN) {
! 596: Var_Set (TARGET, Var_Value (ALLSRC, gn), gn);
! 597: }
! 598: }
! 599:
! 600: /*-
! 601: *-----------------------------------------------------------------------
! 602: * MakeStartJobs --
! 603: * Start as many jobs as possible.
! 604: *
! 605: * Results:
! 606: * If the query flag was given to pmake, no job will be started,
! 607: * but as soon as an out-of-date target is found, this function
! 608: * returns TRUE. At all other times, this function returns FALSE.
! 609: *
! 610: * Side Effects:
! 611: * Nodes are removed from the toBeMade queue and job table slots
! 612: * are filled.
! 613: *
! 614: *-----------------------------------------------------------------------
! 615: */
! 616: static Boolean
! 617: MakeStartJobs ()
! 618: {
! 619: register GNode *gn;
! 620:
! 621: while (!Job_Full() && !Lst_IsEmpty (toBeMade)) {
! 622: gn = (GNode *) Lst_DeQueue (toBeMade);
! 623: if (DEBUG(MAKE)) {
! 624: printf ("Examining %s...", gn->name);
! 625: }
! 626: /*
! 627: * Make sure any and all predecessors that are going to be made,
! 628: * have been.
! 629: */
! 630: if (!Lst_IsEmpty(gn->preds)) {
! 631: LstNode ln;
! 632:
! 633: for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){
! 634: GNode *pgn = (GNode *)Lst_Datum(ln);
! 635:
! 636: if (pgn->make && pgn->made == UNMADE) {
! 637: if (DEBUG(MAKE)) {
! 638: printf("predecessor %s not made yet.\n", pgn->name);
! 639: }
! 640: break;
! 641: }
! 642: }
! 643: /*
! 644: * If ln isn't nil, there's a predecessor as yet unmade, so we
! 645: * just drop this node on the floor. When the node in question
! 646: * has been made, it will notice this node as being ready to
! 647: * make but as yet unmade and will place the node on the queue.
! 648: */
! 649: if (ln != NILLNODE) {
! 650: continue;
! 651: }
! 652: }
! 653:
! 654: numNodes--;
! 655: if (Make_OODate (gn)) {
! 656: if (DEBUG(MAKE)) {
! 657: printf ("out-of-date\n");
! 658: }
! 659: if (queryFlag) {
! 660: return (TRUE);
! 661: }
! 662: Make_DoAllVar (gn);
! 663: Job_Make (gn);
! 664: } else {
! 665: if (DEBUG(MAKE)) {
! 666: printf ("up-to-date\n");
! 667: }
! 668: gn->made = UPTODATE;
! 669: if (gn->type & OP_JOIN) {
! 670: /*
! 671: * Even for an up-to-date .JOIN node, we need it to have its
! 672: * context variables so references to it get the correct
! 673: * value for .TARGET when building up the context variables
! 674: * of its parent(s)...
! 675: */
! 676: Make_DoAllVar (gn);
! 677: }
! 678:
! 679: Make_Update (gn);
! 680: }
! 681: }
! 682: return (FALSE);
! 683: }
! 684:
! 685: /*-
! 686: *-----------------------------------------------------------------------
! 687: * MakePrintStatus --
! 688: * Print the status of a top-level node, viz. it being up-to-date
! 689: * already or not created due to an error in a lower level.
! 690: * Callback function for Make_Run via Lst_ForEach.
! 691: *
! 692: * Results:
! 693: * Always returns 0.
! 694: *
! 695: * Side Effects:
! 696: * A message may be printed.
! 697: *
! 698: *-----------------------------------------------------------------------
! 699: */
! 700: static int
! 701: MakePrintStatus(gn, cycle)
! 702: GNode *gn; /* Node to examine */
! 703: Boolean cycle; /* True if gn->unmade being non-zero implies
! 704: * a cycle in the graph, not an error in an
! 705: * inferior */
! 706: {
! 707: if (gn->made == UPTODATE) {
! 708: printf ("`%s' is up to date.\n", gn->name);
! 709: } else if (gn->unmade != 0) {
! 710: if (cycle) {
! 711: /*
! 712: * If printing cycles and came to one that has unmade children,
! 713: * print out the cycle by recursing on its children. Note a
! 714: * cycle like:
! 715: * a : b
! 716: * b : c
! 717: * c : b
! 718: * will cause this to erroneously complain about a being in
! 719: * the cycle, but this is a good approximation.
! 720: */
! 721: if (gn->made == CYCLE) {
! 722: Error("Graph cycles through `%s'", gn->name);
! 723: gn->made = ENDCYCLE;
! 724: Lst_ForEach(gn->children, MakePrintStatus, (ClientData)TRUE);
! 725: gn->made = UNMADE;
! 726: } else if (gn->made != ENDCYCLE) {
! 727: gn->made = CYCLE;
! 728: Lst_ForEach(gn->children, MakePrintStatus, (ClientData)TRUE);
! 729: }
! 730: } else {
! 731: printf ("`%s' not remade because of errors.\n", gn->name);
! 732: }
! 733: }
! 734: return (0);
! 735: }
! 736:
! 737: /*-
! 738: *-----------------------------------------------------------------------
! 739: * Make_Run --
! 740: * Initialize the nodes to remake and the list of nodes which are
! 741: * ready to be made by doing a breadth-first traversal of the graph
! 742: * starting from the nodes in the given list. Once this traversal
! 743: * is finished, all the 'leaves' of the graph are in the toBeMade
! 744: * queue.
! 745: * Using this queue and the Job module, work back up the graph,
! 746: * calling on MakeStartJobs to keep the job table as full as
! 747: * possible.
! 748: *
! 749: * Results:
! 750: * TRUE if work was done. FALSE otherwise.
! 751: *
! 752: * Side Effects:
! 753: * The make field of all nodes involved in the creation of the given
! 754: * targets is set to 1. The toBeMade list is set to contain all the
! 755: * 'leaves' of these subgraphs.
! 756: *-----------------------------------------------------------------------
! 757: */
! 758: Boolean
! 759: Make_Run (targs)
! 760: Lst targs; /* the initial list of targets */
! 761: {
! 762: register GNode *gn; /* a temporary pointer */
! 763: register Lst examine; /* List of targets to examine */
! 764: int errors; /* Number of errors the Job module reports */
! 765:
! 766: toBeMade = Lst_Init (FALSE);
! 767:
! 768: examine = Lst_Duplicate(targs, NOCOPY);
! 769: numNodes = 0;
! 770:
! 771: /*
! 772: * Make an initial downward pass over the graph, marking nodes to be made
! 773: * as we go down. We call Suff_FindDeps to find where a node is and
! 774: * to get some children for it if it has none and also has no commands.
! 775: * If the node is a leaf, we stick it on the toBeMade queue to
! 776: * be looked at in a minute, otherwise we add its children to our queue
! 777: * and go on about our business.
! 778: */
! 779: while (!Lst_IsEmpty (examine)) {
! 780: gn = (GNode *) Lst_DeQueue (examine);
! 781:
! 782: if (!gn->make) {
! 783: gn->make = TRUE;
! 784: numNodes++;
! 785:
! 786: /*
! 787: * Apply any .USE rules before looking for implicit dependencies
! 788: * to make sure everything has commands that should...
! 789: */
! 790: Lst_ForEach (gn->children, Make_HandleUse, (ClientData)gn);
! 791: Suff_FindDeps (gn);
! 792:
! 793: if (gn->unmade != 0) {
! 794: Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine);
! 795: } else {
! 796: (void)Lst_EnQueue (toBeMade, (ClientData)gn);
! 797: }
! 798: }
! 799: }
! 800:
! 801: Lst_Destroy (examine, NOFREE);
! 802:
! 803: if (queryFlag) {
! 804: /*
! 805: * We wouldn't do any work unless we could start some jobs in the
! 806: * next loop... (we won't actually start any, of course, this is just
! 807: * to see if any of the targets was out of date)
! 808: */
! 809: return (MakeStartJobs());
! 810: } else {
! 811: /*
! 812: * Initialization. At the moment, no jobs are running and until some
! 813: * get started, nothing will happen since the remaining upward
! 814: * traversal of the graph is performed by the routines in job.c upon
! 815: * the finishing of a job. So we fill the Job table as much as we can
! 816: * before going into our loop.
! 817: */
! 818: (void) MakeStartJobs();
! 819: }
! 820:
! 821: /*
! 822: * Main Loop: The idea here is that the ending of jobs will take
! 823: * care of the maintenance of data structures and the waiting for output
! 824: * will cause us to be idle most of the time while our children run as
! 825: * much as possible. Because the job table is kept as full as possible,
! 826: * the only time when it will be empty is when all the jobs which need
! 827: * running have been run, so that is the end condition of this loop.
! 828: * Note that the Job module will exit if there were any errors unless the
! 829: * keepgoing flag was given.
! 830: */
! 831: while (!Job_Empty ()) {
! 832: Job_CatchOutput ();
! 833: Job_CatchChildren (!usePipes);
! 834: (void)MakeStartJobs();
! 835: }
! 836:
! 837: errors = Job_End();
! 838:
! 839: /*
! 840: * Print the final status of each target. E.g. if it wasn't made
! 841: * because some inferior reported an error.
! 842: */
! 843: Lst_ForEach(targs, MakePrintStatus,
! 844: (ClientData)((errors == 0) && (numNodes != 0)));
! 845:
! 846: return (TRUE);
! 847: }
CVSweb <webmaster@jp.NetBSD.org>