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