1243115Ssjg/* $NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/* 36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 37236769Sobrien * All rights reserved. 38236769Sobrien * 39236769Sobrien * This code is derived from software contributed to Berkeley by 40236769Sobrien * Adam de Boor. 41236769Sobrien * 42236769Sobrien * Redistribution and use in source and binary forms, with or without 43236769Sobrien * modification, are permitted provided that the following conditions 44236769Sobrien * are met: 45236769Sobrien * 1. Redistributions of source code must retain the above copyright 46236769Sobrien * notice, this list of conditions and the following disclaimer. 47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 48236769Sobrien * notice, this list of conditions and the following disclaimer in the 49236769Sobrien * documentation and/or other materials provided with the distribution. 50236769Sobrien * 3. All advertising materials mentioning features or use of this software 51236769Sobrien * must display the following acknowledgement: 52236769Sobrien * This product includes software developed by the University of 53236769Sobrien * California, Berkeley and its contributors. 54236769Sobrien * 4. Neither the name of the University nor the names of its contributors 55236769Sobrien * may be used to endorse or promote products derived from this software 56236769Sobrien * without specific prior written permission. 57236769Sobrien * 58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68236769Sobrien * SUCH DAMAGE. 69236769Sobrien */ 70236769Sobrien 71236769Sobrien#ifndef MAKE_NATIVE 72243115Ssjgstatic char rcsid[] = "$NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $"; 73236769Sobrien#else 74236769Sobrien#include <sys/cdefs.h> 75236769Sobrien#ifndef lint 76236769Sobrien#if 0 77236769Sobrienstatic char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; 78236769Sobrien#else 79243115Ssjg__RCSID("$NetBSD: make.c,v 1.88 2012/11/09 18:53:05 sjg Exp $"); 80236769Sobrien#endif 81236769Sobrien#endif /* not lint */ 82236769Sobrien#endif 83236769Sobrien 84236769Sobrien/*- 85236769Sobrien * make.c -- 86236769Sobrien * The functions which perform the examination of targets and 87236769Sobrien * their suitability for creation 88236769Sobrien * 89236769Sobrien * Interface: 90236769Sobrien * Make_Run Initialize things for the module and recreate 91236769Sobrien * whatever needs recreating. Returns TRUE if 92236769Sobrien * work was (or would have been) done and FALSE 93236769Sobrien * otherwise. 94236769Sobrien * 95236769Sobrien * Make_Update Update all parents of a given child. Performs 96236769Sobrien * various bookkeeping chores like the updating 97236769Sobrien * of the cmgn field of the parent, filling 98236769Sobrien * of the IMPSRC context variable, etc. It will 99236769Sobrien * place the parent on the toBeMade queue if it 100236769Sobrien * should be. 101236769Sobrien * 102236769Sobrien * Make_TimeStamp Function to set the parent's cmgn field 103236769Sobrien * based on a child's modification time. 104236769Sobrien * 105236769Sobrien * Make_DoAllVar Set up the various local variables for a 106236769Sobrien * target, including the .ALLSRC variable, making 107236769Sobrien * sure that any variable that needs to exist 108236769Sobrien * at the very least has the empty value. 109236769Sobrien * 110236769Sobrien * Make_OODate Determine if a target is out-of-date. 111236769Sobrien * 112236769Sobrien * Make_HandleUse See if a child is a .USE node for a parent 113236769Sobrien * and perform the .USE actions if so. 114236769Sobrien * 115236769Sobrien * Make_ExpandUse Expand .USE nodes 116236769Sobrien */ 117236769Sobrien 118236769Sobrien#include "make.h" 119236769Sobrien#include "hash.h" 120236769Sobrien#include "dir.h" 121236769Sobrien#include "job.h" 122236769Sobrien 123236769Sobrienstatic unsigned int checked = 1;/* Sequence # to detect recursion */ 124236769Sobrienstatic Lst toBeMade; /* The current fringe of the graph. These 125236769Sobrien * are nodes which await examination by 126236769Sobrien * MakeOODate. It is added to by 127236769Sobrien * Make_Update and subtracted from by 128236769Sobrien * MakeStartJobs */ 129236769Sobrien 130236769Sobrienstatic int MakeAddChild(void *, void *); 131236769Sobrienstatic int MakeFindChild(void *, void *); 132236769Sobrienstatic int MakeUnmark(void *, void *); 133236769Sobrienstatic int MakeAddAllSrc(void *, void *); 134236769Sobrienstatic int MakeTimeStamp(void *, void *); 135236769Sobrienstatic int MakeHandleUse(void *, void *); 136236769Sobrienstatic Boolean MakeStartJobs(void); 137236769Sobrienstatic int MakePrintStatus(void *, void *); 138236769Sobrienstatic int MakeCheckOrder(void *, void *); 139236769Sobrienstatic int MakeBuildChild(void *, void *); 140236769Sobrienstatic int MakeBuildParent(void *, void *); 141236769Sobrien 142237578SobrienMAKE_ATTR_DEAD static void 143236769Sobrienmake_abort(GNode *gn, int line) 144236769Sobrien{ 145236769Sobrien static int two = 2; 146236769Sobrien 147236769Sobrien fprintf(debug_file, "make_abort from line %d\n", line); 148236769Sobrien Targ_PrintNode(gn, &two); 149236769Sobrien Lst_ForEach(toBeMade, Targ_PrintNode, &two); 150236769Sobrien Targ_PrintGraph(3); 151236769Sobrien abort(); 152236769Sobrien} 153236769Sobrien 154236769Sobrien/*- 155236769Sobrien *----------------------------------------------------------------------- 156236769Sobrien * Make_TimeStamp -- 157236769Sobrien * Set the cmgn field of a parent node based on the mtime stamp in its 158236769Sobrien * child. Called from MakeOODate via Lst_ForEach. 159236769Sobrien * 160236769Sobrien * Input: 161236769Sobrien * pgn the current parent 162236769Sobrien * cgn the child we've just examined 163236769Sobrien * 164236769Sobrien * Results: 165236769Sobrien * Always returns 0. 166236769Sobrien * 167236769Sobrien * Side Effects: 168236769Sobrien * The cmgn of the parent node will be changed if the mtime 169236769Sobrien * field of the child is greater than it. 170236769Sobrien *----------------------------------------------------------------------- 171236769Sobrien */ 172236769Sobrienint 173236769SobrienMake_TimeStamp(GNode *pgn, GNode *cgn) 174236769Sobrien{ 175236769Sobrien if (pgn->cmgn == NULL || cgn->mtime > pgn->cmgn->mtime) { 176236769Sobrien pgn->cmgn = cgn; 177236769Sobrien } 178236769Sobrien return (0); 179236769Sobrien} 180236769Sobrien 181236769Sobrien/* 182236769Sobrien * Input: 183236769Sobrien * pgn the current parent 184236769Sobrien * cgn the child we've just examined 185236769Sobrien * 186236769Sobrien */ 187236769Sobrienstatic int 188236769SobrienMakeTimeStamp(void *pgn, void *cgn) 189236769Sobrien{ 190236769Sobrien return Make_TimeStamp((GNode *)pgn, (GNode *)cgn); 191236769Sobrien} 192236769Sobrien 193236769Sobrien/*- 194236769Sobrien *----------------------------------------------------------------------- 195236769Sobrien * Make_OODate -- 196236769Sobrien * See if a given node is out of date with respect to its sources. 197236769Sobrien * Used by Make_Run when deciding which nodes to place on the 198236769Sobrien * toBeMade queue initially and by Make_Update to screen out USE and 199236769Sobrien * EXEC nodes. In the latter case, however, any other sort of node 200236769Sobrien * must be considered out-of-date since at least one of its children 201236769Sobrien * will have been recreated. 202236769Sobrien * 203236769Sobrien * Input: 204236769Sobrien * gn the node to check 205236769Sobrien * 206236769Sobrien * Results: 207236769Sobrien * TRUE if the node is out of date. FALSE otherwise. 208236769Sobrien * 209236769Sobrien * Side Effects: 210236769Sobrien * The mtime field of the node and the cmgn field of its parents 211236769Sobrien * will/may be changed. 212236769Sobrien *----------------------------------------------------------------------- 213236769Sobrien */ 214236769SobrienBoolean 215236769SobrienMake_OODate(GNode *gn) 216236769Sobrien{ 217236769Sobrien Boolean oodate; 218236769Sobrien 219236769Sobrien /* 220236769Sobrien * Certain types of targets needn't even be sought as their datedness 221236769Sobrien * doesn't depend on their modification time... 222236769Sobrien */ 223236769Sobrien if ((gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC)) == 0) { 224236769Sobrien (void)Dir_MTime(gn, 1); 225236769Sobrien if (DEBUG(MAKE)) { 226236769Sobrien if (gn->mtime != 0) { 227236769Sobrien fprintf(debug_file, "modified %s...", Targ_FmtTime(gn->mtime)); 228236769Sobrien } else { 229236769Sobrien fprintf(debug_file, "non-existent..."); 230236769Sobrien } 231236769Sobrien } 232236769Sobrien } 233236769Sobrien 234236769Sobrien /* 235236769Sobrien * A target is remade in one of the following circumstances: 236236769Sobrien * its modification time is smaller than that of its youngest child 237236769Sobrien * and it would actually be run (has commands or type OP_NOP) 238236769Sobrien * it's the object of a force operator 239236769Sobrien * it has no children, was on the lhs of an operator and doesn't exist 240236769Sobrien * already. 241236769Sobrien * 242236769Sobrien * Libraries are only considered out-of-date if the archive module says 243236769Sobrien * they are. 244236769Sobrien * 245236769Sobrien * These weird rules are brought to you by Backward-Compatibility and 246236769Sobrien * the strange people who wrote 'Make'. 247236769Sobrien */ 248236769Sobrien if (gn->type & (OP_USE|OP_USEBEFORE)) { 249236769Sobrien /* 250236769Sobrien * If the node is a USE node it is *never* out of date 251236769Sobrien * no matter *what*. 252236769Sobrien */ 253236769Sobrien if (DEBUG(MAKE)) { 254236769Sobrien fprintf(debug_file, ".USE node..."); 255236769Sobrien } 256236769Sobrien oodate = FALSE; 257236769Sobrien } else if ((gn->type & OP_LIB) && 258236769Sobrien ((gn->mtime==0) || Arch_IsLib(gn))) { 259236769Sobrien if (DEBUG(MAKE)) { 260236769Sobrien fprintf(debug_file, "library..."); 261236769Sobrien } 262236769Sobrien 263236769Sobrien /* 264236769Sobrien * always out of date if no children and :: target 265236769Sobrien * or non-existent. 266236769Sobrien */ 267236769Sobrien oodate = (gn->mtime == 0 || Arch_LibOODate(gn) || 268236769Sobrien (gn->cmgn == NULL && (gn->type & OP_DOUBLEDEP))); 269236769Sobrien } else if (gn->type & OP_JOIN) { 270236769Sobrien /* 271236769Sobrien * A target with the .JOIN attribute is only considered 272236769Sobrien * out-of-date if any of its children was out-of-date. 273236769Sobrien */ 274236769Sobrien if (DEBUG(MAKE)) { 275236769Sobrien fprintf(debug_file, ".JOIN node..."); 276236769Sobrien } 277236769Sobrien if (DEBUG(MAKE)) { 278236769Sobrien fprintf(debug_file, "source %smade...", gn->flags & CHILDMADE ? "" : "not "); 279236769Sobrien } 280236769Sobrien oodate = (gn->flags & CHILDMADE) ? TRUE : FALSE; 281236769Sobrien } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { 282236769Sobrien /* 283236769Sobrien * A node which is the object of the force (!) operator or which has 284236769Sobrien * the .EXEC attribute is always considered out-of-date. 285236769Sobrien */ 286236769Sobrien if (DEBUG(MAKE)) { 287236769Sobrien if (gn->type & OP_FORCE) { 288236769Sobrien fprintf(debug_file, "! operator..."); 289236769Sobrien } else if (gn->type & OP_PHONY) { 290236769Sobrien fprintf(debug_file, ".PHONY node..."); 291236769Sobrien } else { 292236769Sobrien fprintf(debug_file, ".EXEC node..."); 293236769Sobrien } 294236769Sobrien } 295236769Sobrien oodate = TRUE; 296236769Sobrien } else if ((gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) || 297236769Sobrien (gn->cmgn == NULL && 298236769Sobrien ((gn->mtime == 0 && !(gn->type & OP_OPTIONAL)) 299236769Sobrien || gn->type & OP_DOUBLEDEP))) 300236769Sobrien { 301236769Sobrien /* 302236769Sobrien * A node whose modification time is less than that of its 303236769Sobrien * youngest child or that has no children (cmgn == NULL) and 304236769Sobrien * either doesn't exist (mtime == 0) and it isn't optional 305236769Sobrien * or was the object of a * :: operator is out-of-date. 306236769Sobrien * Why? Because that's the way Make does it. 307236769Sobrien */ 308236769Sobrien if (DEBUG(MAKE)) { 309236769Sobrien if (gn->cmgn != NULL && gn->mtime < gn->cmgn->mtime) { 310236769Sobrien fprintf(debug_file, "modified before source %s...", 311236769Sobrien gn->cmgn->path); 312236769Sobrien } else if (gn->mtime == 0) { 313236769Sobrien fprintf(debug_file, "non-existent and no sources..."); 314236769Sobrien } else { 315236769Sobrien fprintf(debug_file, ":: operator and no sources..."); 316236769Sobrien } 317236769Sobrien } 318236769Sobrien oodate = TRUE; 319236769Sobrien } else { 320236769Sobrien /* 321236769Sobrien * When a non-existing child with no sources 322236769Sobrien * (such as a typically used FORCE source) has been made and 323236769Sobrien * the target of the child (usually a directory) has the same 324236769Sobrien * timestamp as the timestamp just given to the non-existing child 325236769Sobrien * after it was considered made. 326236769Sobrien */ 327236769Sobrien if (DEBUG(MAKE)) { 328236769Sobrien if (gn->flags & FORCE) 329236769Sobrien fprintf(debug_file, "non existing child..."); 330236769Sobrien } 331236769Sobrien oodate = (gn->flags & FORCE) ? TRUE : FALSE; 332236769Sobrien } 333236769Sobrien 334236769Sobrien#ifdef USE_META 335236769Sobrien if (useMeta) { 336236769Sobrien oodate = meta_oodate(gn, oodate); 337236769Sobrien } 338236769Sobrien#endif 339236769Sobrien 340236769Sobrien /* 341236769Sobrien * If the target isn't out-of-date, the parents need to know its 342236769Sobrien * modification time. Note that targets that appear to be out-of-date 343236769Sobrien * but aren't, because they have no commands and aren't of type OP_NOP, 344236769Sobrien * have their mtime stay below their children's mtime to keep parents from 345236769Sobrien * thinking they're out-of-date. 346236769Sobrien */ 347236769Sobrien if (!oodate) { 348236769Sobrien Lst_ForEach(gn->parents, MakeTimeStamp, gn); 349236769Sobrien } 350236769Sobrien 351236769Sobrien return (oodate); 352236769Sobrien} 353236769Sobrien 354236769Sobrien/*- 355236769Sobrien *----------------------------------------------------------------------- 356236769Sobrien * MakeAddChild -- 357236769Sobrien * Function used by Make_Run to add a child to the list l. 358236769Sobrien * It will only add the child if its make field is FALSE. 359236769Sobrien * 360236769Sobrien * Input: 361236769Sobrien * gnp the node to add 362236769Sobrien * lp the list to which to add it 363236769Sobrien * 364236769Sobrien * Results: 365236769Sobrien * Always returns 0 366236769Sobrien * 367236769Sobrien * Side Effects: 368236769Sobrien * The given list is extended 369236769Sobrien *----------------------------------------------------------------------- 370236769Sobrien */ 371236769Sobrienstatic int 372236769SobrienMakeAddChild(void *gnp, void *lp) 373236769Sobrien{ 374236769Sobrien GNode *gn = (GNode *)gnp; 375236769Sobrien Lst l = (Lst) lp; 376236769Sobrien 377236769Sobrien if ((gn->flags & REMAKE) == 0 && !(gn->type & (OP_USE|OP_USEBEFORE))) { 378236769Sobrien if (DEBUG(MAKE)) 379236769Sobrien fprintf(debug_file, "MakeAddChild: need to examine %s%s\n", 380236769Sobrien gn->name, gn->cohort_num); 381236769Sobrien (void)Lst_EnQueue(l, gn); 382236769Sobrien } 383236769Sobrien return (0); 384236769Sobrien} 385236769Sobrien 386236769Sobrien/*- 387236769Sobrien *----------------------------------------------------------------------- 388236769Sobrien * MakeFindChild -- 389236769Sobrien * Function used by Make_Run to find the pathname of a child 390236769Sobrien * that was already made. 391236769Sobrien * 392236769Sobrien * Input: 393236769Sobrien * gnp the node to find 394236769Sobrien * 395236769Sobrien * Results: 396236769Sobrien * Always returns 0 397236769Sobrien * 398236769Sobrien * Side Effects: 399236769Sobrien * The path and mtime of the node and the cmgn of the parent are 400236769Sobrien * updated; the unmade children count of the parent is decremented. 401236769Sobrien *----------------------------------------------------------------------- 402236769Sobrien */ 403236769Sobrienstatic int 404236769SobrienMakeFindChild(void *gnp, void *pgnp) 405236769Sobrien{ 406236769Sobrien GNode *gn = (GNode *)gnp; 407236769Sobrien GNode *pgn = (GNode *)pgnp; 408236769Sobrien 409236769Sobrien (void)Dir_MTime(gn, 0); 410236769Sobrien Make_TimeStamp(pgn, gn); 411236769Sobrien pgn->unmade--; 412236769Sobrien 413236769Sobrien return (0); 414236769Sobrien} 415236769Sobrien 416236769Sobrien/*- 417236769Sobrien *----------------------------------------------------------------------- 418236769Sobrien * Make_HandleUse -- 419236769Sobrien * Function called by Make_Run and SuffApplyTransform on the downward 420236769Sobrien * pass to handle .USE and transformation nodes. It implements the 421236769Sobrien * .USE and transformation functionality by copying the node's commands, 422236769Sobrien * type flags and children to the parent node. 423236769Sobrien * 424236769Sobrien * A .USE node is much like an explicit transformation rule, except 425236769Sobrien * its commands are always added to the target node, even if the 426236769Sobrien * target already has commands. 427236769Sobrien * 428236769Sobrien * Input: 429236769Sobrien * cgn The .USE node 430236769Sobrien * pgn The target of the .USE node 431236769Sobrien * 432236769Sobrien * Results: 433236769Sobrien * none 434236769Sobrien * 435236769Sobrien * Side Effects: 436236769Sobrien * Children and commands may be added to the parent and the parent's 437236769Sobrien * type may be changed. 438236769Sobrien * 439236769Sobrien *----------------------------------------------------------------------- 440236769Sobrien */ 441236769Sobrienvoid 442236769SobrienMake_HandleUse(GNode *cgn, GNode *pgn) 443236769Sobrien{ 444236769Sobrien LstNode ln; /* An element in the children list */ 445236769Sobrien 446236769Sobrien#ifdef DEBUG_SRC 447236769Sobrien if ((cgn->type & (OP_USE|OP_USEBEFORE|OP_TRANSFORM)) == 0) { 448236769Sobrien fprintf(debug_file, "Make_HandleUse: called for plain node %s\n", cgn->name); 449236769Sobrien return; 450236769Sobrien } 451236769Sobrien#endif 452236769Sobrien 453236769Sobrien if ((cgn->type & (OP_USE|OP_USEBEFORE)) || Lst_IsEmpty(pgn->commands)) { 454236769Sobrien if (cgn->type & OP_USEBEFORE) { 455236769Sobrien /* 456236769Sobrien * .USEBEFORE -- 457236769Sobrien * prepend the child's commands to the parent. 458236769Sobrien */ 459236769Sobrien Lst cmds = pgn->commands; 460236769Sobrien pgn->commands = Lst_Duplicate(cgn->commands, NULL); 461236769Sobrien (void)Lst_Concat(pgn->commands, cmds, LST_CONCNEW); 462236769Sobrien Lst_Destroy(cmds, NULL); 463236769Sobrien } else { 464236769Sobrien /* 465236769Sobrien * .USE or target has no commands -- 466236769Sobrien * append the child's commands to the parent. 467236769Sobrien */ 468236769Sobrien (void)Lst_Concat(pgn->commands, cgn->commands, LST_CONCNEW); 469236769Sobrien } 470236769Sobrien } 471236769Sobrien 472236769Sobrien if (Lst_Open(cgn->children) == SUCCESS) { 473236769Sobrien while ((ln = Lst_Next(cgn->children)) != NULL) { 474236769Sobrien GNode *tgn, *gn = (GNode *)Lst_Datum(ln); 475236769Sobrien 476236769Sobrien /* 477236769Sobrien * Expand variables in the .USE node's name 478236769Sobrien * and save the unexpanded form. 479236769Sobrien * We don't need to do this for commands. 480236769Sobrien * They get expanded properly when we execute. 481236769Sobrien */ 482236769Sobrien if (gn->uname == NULL) { 483236769Sobrien gn->uname = gn->name; 484236769Sobrien } else { 485236769Sobrien if (gn->name) 486236769Sobrien free(gn->name); 487236769Sobrien } 488236769Sobrien gn->name = Var_Subst(NULL, gn->uname, pgn, FALSE); 489236769Sobrien if (gn->name && gn->uname && strcmp(gn->name, gn->uname) != 0) { 490236769Sobrien /* See if we have a target for this node. */ 491236769Sobrien tgn = Targ_FindNode(gn->name, TARG_NOCREATE); 492236769Sobrien if (tgn != NULL) 493236769Sobrien gn = tgn; 494236769Sobrien } 495236769Sobrien 496236769Sobrien (void)Lst_AtEnd(pgn->children, gn); 497236769Sobrien (void)Lst_AtEnd(gn->parents, pgn); 498236769Sobrien pgn->unmade += 1; 499236769Sobrien } 500236769Sobrien Lst_Close(cgn->children); 501236769Sobrien } 502236769Sobrien 503236769Sobrien pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_USEBEFORE|OP_TRANSFORM); 504236769Sobrien} 505236769Sobrien 506236769Sobrien/*- 507236769Sobrien *----------------------------------------------------------------------- 508236769Sobrien * MakeHandleUse -- 509236769Sobrien * Callback function for Lst_ForEach, used by Make_Run on the downward 510236769Sobrien * pass to handle .USE nodes. Should be called before the children 511236769Sobrien * are enqueued to be looked at by MakeAddChild. 512236769Sobrien * This function calls Make_HandleUse to copy the .USE node's commands, 513236769Sobrien * type flags and children to the parent node. 514236769Sobrien * 515236769Sobrien * Input: 516236769Sobrien * cgnp the child we've just examined 517236769Sobrien * pgnp the current parent 518236769Sobrien * 519236769Sobrien * Results: 520236769Sobrien * returns 0. 521236769Sobrien * 522236769Sobrien * Side Effects: 523236769Sobrien * After expansion, .USE child nodes are removed from the parent 524236769Sobrien * 525236769Sobrien *----------------------------------------------------------------------- 526236769Sobrien */ 527236769Sobrienstatic int 528236769SobrienMakeHandleUse(void *cgnp, void *pgnp) 529236769Sobrien{ 530236769Sobrien GNode *cgn = (GNode *)cgnp; 531236769Sobrien GNode *pgn = (GNode *)pgnp; 532236769Sobrien LstNode ln; /* An element in the children list */ 533236769Sobrien int unmarked; 534236769Sobrien 535236769Sobrien unmarked = ((cgn->type & OP_MARK) == 0); 536236769Sobrien cgn->type |= OP_MARK; 537236769Sobrien 538236769Sobrien if ((cgn->type & (OP_USE|OP_USEBEFORE)) == 0) 539236769Sobrien return (0); 540236769Sobrien 541236769Sobrien if (unmarked) 542236769Sobrien Make_HandleUse(cgn, pgn); 543236769Sobrien 544236769Sobrien /* 545236769Sobrien * This child node is now "made", so we decrement the count of 546236769Sobrien * unmade children in the parent... We also remove the child 547236769Sobrien * from the parent's list to accurately reflect the number of decent 548236769Sobrien * children the parent has. This is used by Make_Run to decide 549236769Sobrien * whether to queue the parent or examine its children... 550236769Sobrien */ 551236769Sobrien if ((ln = Lst_Member(pgn->children, cgn)) != NULL) { 552236769Sobrien Lst_Remove(pgn->children, ln); 553236769Sobrien pgn->unmade--; 554236769Sobrien } 555236769Sobrien return (0); 556236769Sobrien} 557236769Sobrien 558236769Sobrien 559236769Sobrien/*- 560236769Sobrien *----------------------------------------------------------------------- 561236769Sobrien * Make_Recheck -- 562236769Sobrien * Check the modification time of a gnode, and update it as described 563236769Sobrien * in the comments below. 564236769Sobrien * 565236769Sobrien * Results: 566236769Sobrien * returns 0 if the gnode does not exist, or it's filesystem 567236769Sobrien * time if it does. 568236769Sobrien * 569236769Sobrien * Side Effects: 570236769Sobrien * the gnode's modification time and path name are affected. 571236769Sobrien * 572236769Sobrien *----------------------------------------------------------------------- 573236769Sobrien */ 574236769Sobrientime_t 575236769SobrienMake_Recheck(GNode *gn) 576236769Sobrien{ 577236769Sobrien time_t mtime = Dir_MTime(gn, 1); 578236769Sobrien 579236769Sobrien#ifndef RECHECK 580236769Sobrien /* 581236769Sobrien * We can't re-stat the thing, but we can at least take care of rules 582236769Sobrien * where a target depends on a source that actually creates the 583236769Sobrien * target, but only if it has changed, e.g. 584236769Sobrien * 585236769Sobrien * parse.h : parse.o 586236769Sobrien * 587236769Sobrien * parse.o : parse.y 588236769Sobrien * yacc -d parse.y 589236769Sobrien * cc -c y.tab.c 590236769Sobrien * mv y.tab.o parse.o 591236769Sobrien * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 592236769Sobrien * 593236769Sobrien * In this case, if the definitions produced by yacc haven't changed 594236769Sobrien * from before, parse.h won't have been updated and gn->mtime will 595236769Sobrien * reflect the current modification time for parse.h. This is 596236769Sobrien * something of a kludge, I admit, but it's a useful one.. 597236769Sobrien * XXX: People like to use a rule like 598236769Sobrien * 599236769Sobrien * FRC: 600236769Sobrien * 601236769Sobrien * To force things that depend on FRC to be made, so we have to 602236769Sobrien * check for gn->children being empty as well... 603236769Sobrien */ 604236769Sobrien if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { 605236769Sobrien gn->mtime = now; 606236769Sobrien } 607236769Sobrien#else 608236769Sobrien /* 609236769Sobrien * This is what Make does and it's actually a good thing, as it 610236769Sobrien * allows rules like 611236769Sobrien * 612236769Sobrien * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 613236769Sobrien * 614236769Sobrien * to function as intended. Unfortunately, thanks to the stateless 615236769Sobrien * nature of NFS (by which I mean the loose coupling of two clients 616236769Sobrien * using the same file from a common server), there are times 617236769Sobrien * when the modification time of a file created on a remote 618236769Sobrien * machine will not be modified before the local stat() implied by 619236769Sobrien * the Dir_MTime occurs, thus leading us to believe that the file 620236769Sobrien * is unchanged, wreaking havoc with files that depend on this one. 621236769Sobrien * 622236769Sobrien * I have decided it is better to make too much than to make too 623236769Sobrien * little, so this stuff is commented out unless you're sure it's ok. 624236769Sobrien * -- ardeb 1/12/88 625236769Sobrien */ 626236769Sobrien /* 627236769Sobrien * Christos, 4/9/92: If we are saving commands pretend that 628236769Sobrien * the target is made now. Otherwise archives with ... rules 629236769Sobrien * don't work! 630236769Sobrien */ 631236769Sobrien if (NoExecute(gn) || (gn->type & OP_SAVE_CMDS) || 632236769Sobrien (mtime == 0 && !(gn->type & OP_WAIT))) { 633236769Sobrien if (DEBUG(MAKE)) { 634236769Sobrien fprintf(debug_file, " recheck(%s): update time from %s to now\n", 635236769Sobrien gn->name, Targ_FmtTime(gn->mtime)); 636236769Sobrien } 637236769Sobrien gn->mtime = now; 638236769Sobrien } 639236769Sobrien else { 640236769Sobrien if (DEBUG(MAKE)) { 641236769Sobrien fprintf(debug_file, " recheck(%s): current update time: %s\n", 642236769Sobrien gn->name, Targ_FmtTime(gn->mtime)); 643236769Sobrien } 644236769Sobrien } 645236769Sobrien#endif 646236769Sobrien return mtime; 647236769Sobrien} 648236769Sobrien 649236769Sobrien/*- 650236769Sobrien *----------------------------------------------------------------------- 651236769Sobrien * Make_Update -- 652236769Sobrien * Perform update on the parents of a node. Used by JobFinish once 653236769Sobrien * a node has been dealt with and by MakeStartJobs if it finds an 654236769Sobrien * up-to-date node. 655236769Sobrien * 656236769Sobrien * Input: 657236769Sobrien * cgn the child node 658236769Sobrien * 659236769Sobrien * Results: 660236769Sobrien * Always returns 0 661236769Sobrien * 662236769Sobrien * Side Effects: 663236769Sobrien * The unmade field of pgn is decremented and pgn may be placed on 664236769Sobrien * the toBeMade queue if this field becomes 0. 665236769Sobrien * 666236769Sobrien * If the child was made, the parent's flag CHILDMADE field will be 667236769Sobrien * set true. 668236769Sobrien * 669236769Sobrien * If the child is not up-to-date and still does not exist, 670236769Sobrien * set the FORCE flag on the parents. 671236769Sobrien * 672236769Sobrien * If the child wasn't made, the cmgn field of the parent will be 673236769Sobrien * altered if the child's mtime is big enough. 674236769Sobrien * 675236769Sobrien * Finally, if the child is the implied source for the parent, the 676236769Sobrien * parent's IMPSRC variable is set appropriately. 677236769Sobrien * 678236769Sobrien *----------------------------------------------------------------------- 679236769Sobrien */ 680236769Sobrienvoid 681236769SobrienMake_Update(GNode *cgn) 682236769Sobrien{ 683236769Sobrien GNode *pgn; /* the parent node */ 684236769Sobrien char *cname; /* the child's name */ 685236769Sobrien LstNode ln; /* Element in parents and iParents lists */ 686236769Sobrien time_t mtime = -1; 687236769Sobrien char *p1; 688236769Sobrien Lst parents; 689236769Sobrien GNode *centurion; 690236769Sobrien 691236769Sobrien /* It is save to re-examine any nodes again */ 692236769Sobrien checked++; 693236769Sobrien 694236769Sobrien cname = Var_Value(TARGET, cgn, &p1); 695236769Sobrien if (p1) 696236769Sobrien free(p1); 697236769Sobrien 698236769Sobrien if (DEBUG(MAKE)) 699236769Sobrien fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num); 700236769Sobrien 701236769Sobrien /* 702236769Sobrien * If the child was actually made, see what its modification time is 703236769Sobrien * now -- some rules won't actually update the file. If the file still 704236769Sobrien * doesn't exist, make its mtime now. 705236769Sobrien */ 706236769Sobrien if (cgn->made != UPTODATE) { 707236769Sobrien mtime = Make_Recheck(cgn); 708236769Sobrien } 709236769Sobrien 710236769Sobrien /* 711236769Sobrien * If this is a `::' node, we must consult its first instance 712236769Sobrien * which is where all parents are linked. 713236769Sobrien */ 714236769Sobrien if ((centurion = cgn->centurion) != NULL) { 715236769Sobrien if (!Lst_IsEmpty(cgn->parents)) 716236769Sobrien Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num); 717236769Sobrien centurion->unmade_cohorts -= 1; 718236769Sobrien if (centurion->unmade_cohorts < 0) 719236769Sobrien Error("Graph cycles through centurion %s", centurion->name); 720236769Sobrien } else { 721236769Sobrien centurion = cgn; 722236769Sobrien } 723236769Sobrien parents = centurion->parents; 724236769Sobrien 725236769Sobrien /* If this was a .ORDER node, schedule the RHS */ 726236769Sobrien Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade)); 727236769Sobrien 728236769Sobrien /* Now mark all the parents as having one less unmade child */ 729236769Sobrien if (Lst_Open(parents) == SUCCESS) { 730236769Sobrien while ((ln = Lst_Next(parents)) != NULL) { 731236769Sobrien pgn = (GNode *)Lst_Datum(ln); 732236769Sobrien if (DEBUG(MAKE)) 733236769Sobrien fprintf(debug_file, "inspect parent %s%s: flags %x, " 734236769Sobrien "type %x, made %d, unmade %d ", 735236769Sobrien pgn->name, pgn->cohort_num, pgn->flags, 736236769Sobrien pgn->type, pgn->made, pgn->unmade-1); 737236769Sobrien 738236769Sobrien if (!(pgn->flags & REMAKE)) { 739236769Sobrien /* This parent isn't needed */ 740236769Sobrien if (DEBUG(MAKE)) 741236769Sobrien fprintf(debug_file, "- not needed\n"); 742236769Sobrien continue; 743236769Sobrien } 744236769Sobrien if (mtime == 0 && !(cgn->type & OP_WAIT)) 745236769Sobrien pgn->flags |= FORCE; 746236769Sobrien 747236769Sobrien /* 748236769Sobrien * If the parent has the .MADE attribute, its timestamp got 749236769Sobrien * updated to that of its newest child, and its unmake 750236769Sobrien * child count got set to zero in Make_ExpandUse(). 751236769Sobrien * However other things might cause us to build one of its 752236769Sobrien * children - and so we mustn't do any processing here when 753236769Sobrien * the child build finishes. 754236769Sobrien */ 755236769Sobrien if (pgn->type & OP_MADE) { 756236769Sobrien if (DEBUG(MAKE)) 757236769Sobrien fprintf(debug_file, "- .MADE\n"); 758236769Sobrien continue; 759236769Sobrien } 760236769Sobrien 761236769Sobrien if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) { 762236769Sobrien if (cgn->made == MADE) 763236769Sobrien pgn->flags |= CHILDMADE; 764236769Sobrien (void)Make_TimeStamp(pgn, cgn); 765236769Sobrien } 766236769Sobrien 767236769Sobrien /* 768236769Sobrien * A parent must wait for the completion of all instances 769236769Sobrien * of a `::' dependency. 770236769Sobrien */ 771236769Sobrien if (centurion->unmade_cohorts != 0 || centurion->made < MADE) { 772236769Sobrien if (DEBUG(MAKE)) 773236769Sobrien fprintf(debug_file, 774236769Sobrien "- centurion made %d, %d unmade cohorts\n", 775236769Sobrien centurion->made, centurion->unmade_cohorts); 776236769Sobrien continue; 777236769Sobrien } 778236769Sobrien 779236769Sobrien /* One more child of this parent is now made */ 780236769Sobrien pgn->unmade -= 1; 781236769Sobrien if (pgn->unmade < 0) { 782236769Sobrien if (DEBUG(MAKE)) { 783236769Sobrien fprintf(debug_file, "Graph cycles through %s%s\n", 784236769Sobrien pgn->name, pgn->cohort_num); 785236769Sobrien Targ_PrintGraph(2); 786236769Sobrien } 787236769Sobrien Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num); 788236769Sobrien } 789236769Sobrien 790236769Sobrien /* We must always rescan the parents of .WAIT and .ORDER nodes. */ 791236769Sobrien if (pgn->unmade != 0 && !(centurion->type & OP_WAIT) 792236769Sobrien && !(centurion->flags & DONE_ORDER)) { 793236769Sobrien if (DEBUG(MAKE)) 794236769Sobrien fprintf(debug_file, "- unmade children\n"); 795236769Sobrien continue; 796236769Sobrien } 797236769Sobrien if (pgn->made != DEFERRED) { 798236769Sobrien /* 799236769Sobrien * Either this parent is on a different branch of the tree, 800236769Sobrien * or it on the RHS of a .WAIT directive 801236769Sobrien * or it is already on the toBeMade list. 802236769Sobrien */ 803236769Sobrien if (DEBUG(MAKE)) 804236769Sobrien fprintf(debug_file, "- not deferred\n"); 805236769Sobrien continue; 806236769Sobrien } 807236769Sobrien if (pgn->order_pred 808236769Sobrien && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) { 809236769Sobrien /* A .ORDER rule stops us building this */ 810236769Sobrien continue; 811236769Sobrien } 812236769Sobrien if (DEBUG(MAKE)) { 813236769Sobrien static int two = 2; 814236769Sobrien fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n", 815236769Sobrien cgn->name, cgn->cohort_num, 816236769Sobrien pgn->name, pgn->cohort_num, pgn->made); 817236769Sobrien Targ_PrintNode(pgn, &two); 818236769Sobrien } 819236769Sobrien /* Ok, we can schedule the parent again */ 820236769Sobrien pgn->made = REQUESTED; 821236769Sobrien (void)Lst_EnQueue(toBeMade, pgn); 822236769Sobrien } 823236769Sobrien Lst_Close(parents); 824236769Sobrien } 825236769Sobrien 826236769Sobrien /* 827236769Sobrien * Set the .PREFIX and .IMPSRC variables for all the implied parents 828236769Sobrien * of this node. 829236769Sobrien */ 830236769Sobrien if (Lst_Open(cgn->iParents) == SUCCESS) { 831236769Sobrien char *cpref = Var_Value(PREFIX, cgn, &p1); 832236769Sobrien 833236769Sobrien while ((ln = Lst_Next(cgn->iParents)) != NULL) { 834236769Sobrien pgn = (GNode *)Lst_Datum(ln); 835236769Sobrien if (pgn->flags & REMAKE) { 836236769Sobrien Var_Set(IMPSRC, cname, pgn, 0); 837236769Sobrien if (cpref != NULL) 838236769Sobrien Var_Set(PREFIX, cpref, pgn, 0); 839236769Sobrien } 840236769Sobrien } 841236769Sobrien if (p1) 842236769Sobrien free(p1); 843236769Sobrien Lst_Close(cgn->iParents); 844236769Sobrien } 845236769Sobrien} 846236769Sobrien 847236769Sobrien/*- 848236769Sobrien *----------------------------------------------------------------------- 849236769Sobrien * MakeAddAllSrc -- 850236769Sobrien * Add a child's name to the ALLSRC and OODATE variables of the given 851236769Sobrien * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only 852236769Sobrien * if it has not been given the .EXEC, .USE or .INVISIBLE attributes. 853236769Sobrien * .EXEC and .USE children are very rarely going to be files, so... 854236769Sobrien * If the child is a .JOIN node, its ALLSRC is propagated to the parent. 855236769Sobrien * 856236769Sobrien * A child is added to the OODATE variable if its modification time is 857236769Sobrien * later than that of its parent, as defined by Make, except if the 858236769Sobrien * parent is a .JOIN node. In that case, it is only added to the OODATE 859236769Sobrien * variable if it was actually made (since .JOIN nodes don't have 860236769Sobrien * modification times, the comparison is rather unfair...).. 861236769Sobrien * 862236769Sobrien * Results: 863236769Sobrien * Always returns 0 864236769Sobrien * 865236769Sobrien * Side Effects: 866236769Sobrien * The ALLSRC variable for the given node is extended. 867236769Sobrien *----------------------------------------------------------------------- 868236769Sobrien */ 869236769Sobrienstatic int 870237578SobrienMakeUnmark(void *cgnp, void *pgnp MAKE_ATTR_UNUSED) 871236769Sobrien{ 872236769Sobrien GNode *cgn = (GNode *)cgnp; 873236769Sobrien 874236769Sobrien cgn->type &= ~OP_MARK; 875236769Sobrien return (0); 876236769Sobrien} 877236769Sobrien 878236769Sobrien/* 879236769Sobrien * Input: 880236769Sobrien * cgnp The child to add 881236769Sobrien * pgnp The parent to whose ALLSRC variable it should 882236769Sobrien * be added 883236769Sobrien * 884236769Sobrien */ 885236769Sobrienstatic int 886236769SobrienMakeAddAllSrc(void *cgnp, void *pgnp) 887236769Sobrien{ 888236769Sobrien GNode *cgn = (GNode *)cgnp; 889236769Sobrien GNode *pgn = (GNode *)pgnp; 890236769Sobrien 891236769Sobrien if (cgn->type & OP_MARK) 892236769Sobrien return (0); 893236769Sobrien cgn->type |= OP_MARK; 894236769Sobrien 895236769Sobrien if ((cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE|OP_INVISIBLE)) == 0) { 896236769Sobrien char *child, *allsrc; 897236769Sobrien char *p1 = NULL, *p2 = NULL; 898236769Sobrien 899236769Sobrien if (cgn->type & OP_ARCHV) 900236769Sobrien child = Var_Value(MEMBER, cgn, &p1); 901236769Sobrien else 902236769Sobrien child = cgn->path ? cgn->path : cgn->name; 903236769Sobrien if (cgn->type & OP_JOIN) { 904236769Sobrien allsrc = Var_Value(ALLSRC, cgn, &p2); 905236769Sobrien } else { 906236769Sobrien allsrc = child; 907236769Sobrien } 908236769Sobrien if (allsrc != NULL) 909236769Sobrien Var_Append(ALLSRC, allsrc, pgn); 910236769Sobrien if (p2) 911236769Sobrien free(p2); 912236769Sobrien if (pgn->type & OP_JOIN) { 913236769Sobrien if (cgn->made == MADE) { 914236769Sobrien Var_Append(OODATE, child, pgn); 915236769Sobrien } 916236769Sobrien } else if ((pgn->mtime < cgn->mtime) || 917236769Sobrien (cgn->mtime >= now && cgn->made == MADE)) 918236769Sobrien { 919236769Sobrien /* 920236769Sobrien * It goes in the OODATE variable if the parent is younger than the 921236769Sobrien * child or if the child has been modified more recently than 922236769Sobrien * the start of the make. This is to keep pmake from getting 923236769Sobrien * confused if something else updates the parent after the 924236769Sobrien * make starts (shouldn't happen, I know, but sometimes it 925236769Sobrien * does). In such a case, if we've updated the kid, the parent 926236769Sobrien * is likely to have a modification time later than that of 927236769Sobrien * the kid and anything that relies on the OODATE variable will 928236769Sobrien * be hosed. 929236769Sobrien * 930236769Sobrien * XXX: This will cause all made children to go in the OODATE 931236769Sobrien * variable, even if they're not touched, if RECHECK isn't defined, 932236769Sobrien * since cgn->mtime is set to now in Make_Update. According to 933236769Sobrien * some people, this is good... 934236769Sobrien */ 935236769Sobrien Var_Append(OODATE, child, pgn); 936236769Sobrien } 937236769Sobrien if (p1) 938236769Sobrien free(p1); 939236769Sobrien } 940236769Sobrien return (0); 941236769Sobrien} 942236769Sobrien 943236769Sobrien/*- 944236769Sobrien *----------------------------------------------------------------------- 945236769Sobrien * Make_DoAllVar -- 946236769Sobrien * Set up the ALLSRC and OODATE variables. Sad to say, it must be 947236769Sobrien * done separately, rather than while traversing the graph. This is 948236769Sobrien * because Make defined OODATE to contain all sources whose modification 949236769Sobrien * times were later than that of the target, *not* those sources that 950236769Sobrien * were out-of-date. Since in both compatibility and native modes, 951236769Sobrien * the modification time of the parent isn't found until the child 952236769Sobrien * has been dealt with, we have to wait until now to fill in the 953236769Sobrien * variable. As for ALLSRC, the ordering is important and not 954236769Sobrien * guaranteed when in native mode, so it must be set here, too. 955236769Sobrien * 956236769Sobrien * Results: 957236769Sobrien * None 958236769Sobrien * 959236769Sobrien * Side Effects: 960236769Sobrien * The ALLSRC and OODATE variables of the given node is filled in. 961236769Sobrien * If the node is a .JOIN node, its TARGET variable will be set to 962236769Sobrien * match its ALLSRC variable. 963236769Sobrien *----------------------------------------------------------------------- 964236769Sobrien */ 965236769Sobrienvoid 966236769SobrienMake_DoAllVar(GNode *gn) 967236769Sobrien{ 968236769Sobrien if (gn->flags & DONE_ALLSRC) 969236769Sobrien return; 970236769Sobrien 971236769Sobrien Lst_ForEach(gn->children, MakeUnmark, gn); 972236769Sobrien Lst_ForEach(gn->children, MakeAddAllSrc, gn); 973236769Sobrien 974236769Sobrien if (!Var_Exists (OODATE, gn)) { 975236769Sobrien Var_Set(OODATE, "", gn, 0); 976236769Sobrien } 977236769Sobrien if (!Var_Exists (ALLSRC, gn)) { 978236769Sobrien Var_Set(ALLSRC, "", gn, 0); 979236769Sobrien } 980236769Sobrien 981236769Sobrien if (gn->type & OP_JOIN) { 982236769Sobrien char *p1; 983236769Sobrien Var_Set(TARGET, Var_Value(ALLSRC, gn, &p1), gn, 0); 984236769Sobrien if (p1) 985236769Sobrien free(p1); 986236769Sobrien } 987236769Sobrien gn->flags |= DONE_ALLSRC; 988236769Sobrien} 989236769Sobrien 990236769Sobrien/*- 991236769Sobrien *----------------------------------------------------------------------- 992236769Sobrien * MakeStartJobs -- 993236769Sobrien * Start as many jobs as possible. 994236769Sobrien * 995236769Sobrien * Results: 996236769Sobrien * If the query flag was given to pmake, no job will be started, 997236769Sobrien * but as soon as an out-of-date target is found, this function 998236769Sobrien * returns TRUE. At all other times, this function returns FALSE. 999236769Sobrien * 1000236769Sobrien * Side Effects: 1001236769Sobrien * Nodes are removed from the toBeMade queue and job table slots 1002236769Sobrien * are filled. 1003236769Sobrien * 1004236769Sobrien *----------------------------------------------------------------------- 1005236769Sobrien */ 1006236769Sobrien 1007236769Sobrienstatic int 1008237578SobrienMakeCheckOrder(void *v_bn, void *ignore MAKE_ATTR_UNUSED) 1009236769Sobrien{ 1010236769Sobrien GNode *bn = v_bn; 1011236769Sobrien 1012236769Sobrien if (bn->made >= MADE || !(bn->flags & REMAKE)) 1013236769Sobrien return 0; 1014236769Sobrien if (DEBUG(MAKE)) 1015236769Sobrien fprintf(debug_file, "MakeCheckOrder: Waiting for .ORDER node %s%s\n", 1016236769Sobrien bn->name, bn->cohort_num); 1017236769Sobrien return 1; 1018236769Sobrien} 1019236769Sobrien 1020236769Sobrienstatic int 1021236769SobrienMakeBuildChild(void *v_cn, void *toBeMade_next) 1022236769Sobrien{ 1023236769Sobrien GNode *cn = v_cn; 1024236769Sobrien 1025236769Sobrien if (DEBUG(MAKE)) 1026236769Sobrien fprintf(debug_file, "MakeBuildChild: inspect %s%s, made %d, type %x\n", 1027236769Sobrien cn->name, cn->cohort_num, cn->made, cn->type); 1028236769Sobrien if (cn->made > DEFERRED) 1029236769Sobrien return 0; 1030236769Sobrien 1031236769Sobrien /* If this node is on the RHS of a .ORDER, check LHSs. */ 1032236769Sobrien if (cn->order_pred && Lst_ForEach(cn->order_pred, MakeCheckOrder, 0)) { 1033236769Sobrien /* Can't build this (or anything else in this child list) yet */ 1034236769Sobrien cn->made = DEFERRED; 1035243115Ssjg return 0; /* but keep looking */ 1036236769Sobrien } 1037236769Sobrien 1038236769Sobrien if (DEBUG(MAKE)) 1039236769Sobrien fprintf(debug_file, "MakeBuildChild: schedule %s%s\n", 1040236769Sobrien cn->name, cn->cohort_num); 1041236769Sobrien 1042236769Sobrien cn->made = REQUESTED; 1043236769Sobrien if (toBeMade_next == NULL) 1044236769Sobrien Lst_AtEnd(toBeMade, cn); 1045236769Sobrien else 1046236769Sobrien Lst_InsertBefore(toBeMade, toBeMade_next, cn); 1047236769Sobrien 1048236769Sobrien if (cn->unmade_cohorts != 0) 1049236769Sobrien Lst_ForEach(cn->cohorts, MakeBuildChild, toBeMade_next); 1050236769Sobrien 1051236769Sobrien /* 1052236769Sobrien * If this node is a .WAIT node with unmade chlidren 1053236769Sobrien * then don't add the next sibling. 1054236769Sobrien */ 1055236769Sobrien return cn->type & OP_WAIT && cn->unmade > 0; 1056236769Sobrien} 1057236769Sobrien 1058243115Ssjg/* When a .ORDER LHS node completes we do this on each RHS */ 1059236769Sobrienstatic int 1060236769SobrienMakeBuildParent(void *v_pn, void *toBeMade_next) 1061236769Sobrien{ 1062236769Sobrien GNode *pn = v_pn; 1063236769Sobrien 1064236769Sobrien if (pn->made != DEFERRED) 1065236769Sobrien return 0; 1066236769Sobrien 1067236769Sobrien if (MakeBuildChild(pn, toBeMade_next) == 0) { 1068236769Sobrien /* Mark so that when this node is built we reschedule its parents */ 1069236769Sobrien pn->flags |= DONE_ORDER; 1070236769Sobrien } 1071236769Sobrien 1072236769Sobrien return 0; 1073236769Sobrien} 1074236769Sobrien 1075236769Sobrienstatic Boolean 1076236769SobrienMakeStartJobs(void) 1077236769Sobrien{ 1078236769Sobrien GNode *gn; 1079236769Sobrien int have_token = 0; 1080236769Sobrien 1081236769Sobrien while (!Lst_IsEmpty (toBeMade)) { 1082236769Sobrien /* Get token now to avoid cycling job-list when we only have 1 token */ 1083236769Sobrien if (!have_token && !Job_TokenWithdraw()) 1084236769Sobrien break; 1085236769Sobrien have_token = 1; 1086236769Sobrien 1087236769Sobrien gn = (GNode *)Lst_DeQueue(toBeMade); 1088236769Sobrien if (DEBUG(MAKE)) 1089236769Sobrien fprintf(debug_file, "Examining %s%s...\n", 1090236769Sobrien gn->name, gn->cohort_num); 1091236769Sobrien 1092236769Sobrien if (gn->made != REQUESTED) { 1093236769Sobrien if (DEBUG(MAKE)) 1094236769Sobrien fprintf(debug_file, "state %d\n", gn->made); 1095236769Sobrien 1096236769Sobrien make_abort(gn, __LINE__); 1097236769Sobrien } 1098236769Sobrien 1099236769Sobrien if (gn->checked == checked) { 1100236769Sobrien /* We've already looked at this node since a job finished... */ 1101236769Sobrien if (DEBUG(MAKE)) 1102236769Sobrien fprintf(debug_file, "already checked %s%s\n", 1103236769Sobrien gn->name, gn->cohort_num); 1104236769Sobrien gn->made = DEFERRED; 1105236769Sobrien continue; 1106236769Sobrien } 1107236769Sobrien gn->checked = checked; 1108236769Sobrien 1109236769Sobrien if (gn->unmade != 0) { 1110236769Sobrien /* 1111236769Sobrien * We can't build this yet, add all unmade children to toBeMade, 1112236769Sobrien * just before the current first element. 1113236769Sobrien */ 1114236769Sobrien gn->made = DEFERRED; 1115236769Sobrien Lst_ForEach(gn->children, MakeBuildChild, Lst_First(toBeMade)); 1116236769Sobrien /* and drop this node on the floor */ 1117236769Sobrien if (DEBUG(MAKE)) 1118236769Sobrien fprintf(debug_file, "dropped %s%s\n", gn->name, gn->cohort_num); 1119236769Sobrien continue; 1120236769Sobrien } 1121236769Sobrien 1122236769Sobrien gn->made = BEINGMADE; 1123236769Sobrien if (Make_OODate(gn)) { 1124236769Sobrien if (DEBUG(MAKE)) { 1125236769Sobrien fprintf(debug_file, "out-of-date\n"); 1126236769Sobrien } 1127236769Sobrien if (queryFlag) { 1128236769Sobrien return (TRUE); 1129236769Sobrien } 1130236769Sobrien Make_DoAllVar(gn); 1131236769Sobrien Job_Make(gn); 1132236769Sobrien have_token = 0; 1133236769Sobrien } else { 1134236769Sobrien if (DEBUG(MAKE)) { 1135236769Sobrien fprintf(debug_file, "up-to-date\n"); 1136236769Sobrien } 1137236769Sobrien gn->made = UPTODATE; 1138236769Sobrien if (gn->type & OP_JOIN) { 1139236769Sobrien /* 1140236769Sobrien * Even for an up-to-date .JOIN node, we need it to have its 1141236769Sobrien * context variables so references to it get the correct 1142236769Sobrien * value for .TARGET when building up the context variables 1143236769Sobrien * of its parent(s)... 1144236769Sobrien */ 1145236769Sobrien Make_DoAllVar(gn); 1146236769Sobrien } 1147236769Sobrien Make_Update(gn); 1148236769Sobrien } 1149236769Sobrien } 1150236769Sobrien 1151236769Sobrien if (have_token) 1152236769Sobrien Job_TokenReturn(); 1153236769Sobrien 1154236769Sobrien return (FALSE); 1155236769Sobrien} 1156236769Sobrien 1157236769Sobrien/*- 1158236769Sobrien *----------------------------------------------------------------------- 1159236769Sobrien * MakePrintStatus -- 1160236769Sobrien * Print the status of a top-level node, viz. it being up-to-date 1161236769Sobrien * already or not created due to an error in a lower level. 1162236769Sobrien * Callback function for Make_Run via Lst_ForEach. 1163236769Sobrien * 1164236769Sobrien * Input: 1165236769Sobrien * gnp Node to examine 1166236769Sobrien * cyclep True if gn->unmade being non-zero implies a 1167236769Sobrien * cycle in the graph, not an error in an 1168236769Sobrien * inferior. 1169236769Sobrien * 1170236769Sobrien * Results: 1171236769Sobrien * Always returns 0. 1172236769Sobrien * 1173236769Sobrien * Side Effects: 1174236769Sobrien * A message may be printed. 1175236769Sobrien * 1176236769Sobrien *----------------------------------------------------------------------- 1177236769Sobrien */ 1178236769Sobrienstatic int 1179236769SobrienMakePrintStatusOrder(void *ognp, void *gnp) 1180236769Sobrien{ 1181236769Sobrien GNode *ogn = ognp; 1182236769Sobrien GNode *gn = gnp; 1183236769Sobrien 1184236769Sobrien if (!(ogn->flags & REMAKE) || ogn->made > REQUESTED) 1185236769Sobrien /* not waiting for this one */ 1186236769Sobrien return 0; 1187236769Sobrien 1188236769Sobrien printf(" `%s%s' has .ORDER dependency against %s%s " 1189236769Sobrien "(made %d, flags %x, type %x)\n", 1190236769Sobrien gn->name, gn->cohort_num, 1191236769Sobrien ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type); 1192236769Sobrien if (DEBUG(MAKE) && debug_file != stdout) 1193236769Sobrien fprintf(debug_file, " `%s%s' has .ORDER dependency against %s%s " 1194236769Sobrien "(made %d, flags %x, type %x)\n", 1195236769Sobrien gn->name, gn->cohort_num, 1196236769Sobrien ogn->name, ogn->cohort_num, ogn->made, ogn->flags, ogn->type); 1197236769Sobrien return 0; 1198236769Sobrien} 1199236769Sobrien 1200236769Sobrienstatic int 1201236769SobrienMakePrintStatus(void *gnp, void *v_errors) 1202236769Sobrien{ 1203236769Sobrien GNode *gn = (GNode *)gnp; 1204236769Sobrien int *errors = v_errors; 1205236769Sobrien 1206236769Sobrien if (gn->flags & DONECYCLE) 1207236769Sobrien /* We've completely processed this node before, don't do it again. */ 1208236769Sobrien return 0; 1209236769Sobrien 1210236769Sobrien if (gn->unmade == 0) { 1211236769Sobrien gn->flags |= DONECYCLE; 1212236769Sobrien switch (gn->made) { 1213236769Sobrien case UPTODATE: 1214236769Sobrien printf("`%s%s' is up to date.\n", gn->name, gn->cohort_num); 1215236769Sobrien break; 1216236769Sobrien case MADE: 1217236769Sobrien break; 1218236769Sobrien case UNMADE: 1219236769Sobrien case DEFERRED: 1220236769Sobrien case REQUESTED: 1221236769Sobrien case BEINGMADE: 1222236769Sobrien (*errors)++; 1223236769Sobrien printf("`%s%s' was not built (made %d, flags %x, type %x)!\n", 1224236769Sobrien gn->name, gn->cohort_num, gn->made, gn->flags, gn->type); 1225236769Sobrien if (DEBUG(MAKE) && debug_file != stdout) 1226236769Sobrien fprintf(debug_file, 1227236769Sobrien "`%s%s' was not built (made %d, flags %x, type %x)!\n", 1228236769Sobrien gn->name, gn->cohort_num, gn->made, gn->flags, gn->type); 1229236769Sobrien /* Most likely problem is actually caused by .ORDER */ 1230236769Sobrien Lst_ForEach(gn->order_pred, MakePrintStatusOrder, gn); 1231236769Sobrien break; 1232236769Sobrien default: 1233236769Sobrien /* Errors - already counted */ 1234236769Sobrien printf("`%s%s' not remade because of errors.\n", 1235236769Sobrien gn->name, gn->cohort_num); 1236236769Sobrien if (DEBUG(MAKE) && debug_file != stdout) 1237236769Sobrien fprintf(debug_file, "`%s%s' not remade because of errors.\n", 1238236769Sobrien gn->name, gn->cohort_num); 1239236769Sobrien break; 1240236769Sobrien } 1241236769Sobrien return 0; 1242236769Sobrien } 1243236769Sobrien 1244236769Sobrien if (DEBUG(MAKE)) 1245236769Sobrien fprintf(debug_file, "MakePrintStatus: %s%s has %d unmade children\n", 1246236769Sobrien gn->name, gn->cohort_num, gn->unmade); 1247236769Sobrien /* 1248236769Sobrien * If printing cycles and came to one that has unmade children, 1249236769Sobrien * print out the cycle by recursing on its children. 1250236769Sobrien */ 1251236769Sobrien if (!(gn->flags & CYCLE)) { 1252236769Sobrien /* Fist time we've seen this node, check all children */ 1253236769Sobrien gn->flags |= CYCLE; 1254236769Sobrien Lst_ForEach(gn->children, MakePrintStatus, errors); 1255236769Sobrien /* Mark that this node needn't be processed again */ 1256236769Sobrien gn->flags |= DONECYCLE; 1257236769Sobrien return 0; 1258236769Sobrien } 1259236769Sobrien 1260236769Sobrien /* Only output the error once per node */ 1261236769Sobrien gn->flags |= DONECYCLE; 1262236769Sobrien Error("Graph cycles through `%s%s'", gn->name, gn->cohort_num); 1263236769Sobrien if ((*errors)++ > 100) 1264236769Sobrien /* Abandon the whole error report */ 1265236769Sobrien return 1; 1266236769Sobrien 1267236769Sobrien /* Reporting for our children will give the rest of the loop */ 1268236769Sobrien Lst_ForEach(gn->children, MakePrintStatus, errors); 1269236769Sobrien return 0; 1270236769Sobrien} 1271236769Sobrien 1272236769Sobrien 1273236769Sobrien/*- 1274236769Sobrien *----------------------------------------------------------------------- 1275236769Sobrien * Make_ExpandUse -- 1276236769Sobrien * Expand .USE nodes and create a new targets list 1277236769Sobrien * 1278236769Sobrien * Input: 1279236769Sobrien * targs the initial list of targets 1280236769Sobrien * 1281236769Sobrien * Side Effects: 1282236769Sobrien *----------------------------------------------------------------------- 1283236769Sobrien */ 1284236769Sobrienvoid 1285236769SobrienMake_ExpandUse(Lst targs) 1286236769Sobrien{ 1287236769Sobrien GNode *gn; /* a temporary pointer */ 1288236769Sobrien Lst examine; /* List of targets to examine */ 1289236769Sobrien 1290236769Sobrien examine = Lst_Duplicate(targs, NULL); 1291236769Sobrien 1292236769Sobrien /* 1293236769Sobrien * Make an initial downward pass over the graph, marking nodes to be made 1294236769Sobrien * as we go down. We call Suff_FindDeps to find where a node is and 1295236769Sobrien * to get some children for it if it has none and also has no commands. 1296236769Sobrien * If the node is a leaf, we stick it on the toBeMade queue to 1297236769Sobrien * be looked at in a minute, otherwise we add its children to our queue 1298236769Sobrien * and go on about our business. 1299236769Sobrien */ 1300236769Sobrien while (!Lst_IsEmpty (examine)) { 1301236769Sobrien gn = (GNode *)Lst_DeQueue(examine); 1302236769Sobrien 1303236769Sobrien if (gn->flags & REMAKE) 1304236769Sobrien /* We've looked at this one already */ 1305236769Sobrien continue; 1306236769Sobrien gn->flags |= REMAKE; 1307236769Sobrien if (DEBUG(MAKE)) 1308236769Sobrien fprintf(debug_file, "Make_ExpandUse: examine %s%s\n", 1309236769Sobrien gn->name, gn->cohort_num); 1310236769Sobrien 1311236769Sobrien if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts)) { 1312236769Sobrien /* Append all the 'cohorts' to the list of things to examine */ 1313236769Sobrien Lst new; 1314236769Sobrien new = Lst_Duplicate(gn->cohorts, NULL); 1315236769Sobrien Lst_Concat(new, examine, LST_CONCLINK); 1316236769Sobrien examine = new; 1317236769Sobrien } 1318236769Sobrien 1319236769Sobrien /* 1320236769Sobrien * Apply any .USE rules before looking for implicit dependencies 1321236769Sobrien * to make sure everything has commands that should... 1322236769Sobrien * Make sure that the TARGET is set, so that we can make 1323236769Sobrien * expansions. 1324236769Sobrien */ 1325236769Sobrien if (gn->type & OP_ARCHV) { 1326236769Sobrien char *eoa, *eon; 1327236769Sobrien eoa = strchr(gn->name, '('); 1328236769Sobrien eon = strchr(gn->name, ')'); 1329236769Sobrien if (eoa == NULL || eon == NULL) 1330236769Sobrien continue; 1331236769Sobrien *eoa = '\0'; 1332236769Sobrien *eon = '\0'; 1333236769Sobrien Var_Set(MEMBER, eoa + 1, gn, 0); 1334236769Sobrien Var_Set(ARCHIVE, gn->name, gn, 0); 1335236769Sobrien *eoa = '('; 1336236769Sobrien *eon = ')'; 1337236769Sobrien } 1338236769Sobrien 1339236769Sobrien (void)Dir_MTime(gn, 0); 1340236769Sobrien Var_Set(TARGET, gn->path ? gn->path : gn->name, gn, 0); 1341236769Sobrien Lst_ForEach(gn->children, MakeUnmark, gn); 1342236769Sobrien Lst_ForEach(gn->children, MakeHandleUse, gn); 1343236769Sobrien 1344236769Sobrien if ((gn->type & OP_MADE) == 0) 1345236769Sobrien Suff_FindDeps(gn); 1346236769Sobrien else { 1347236769Sobrien /* Pretend we made all this node's children */ 1348236769Sobrien Lst_ForEach(gn->children, MakeFindChild, gn); 1349236769Sobrien if (gn->unmade != 0) 1350236769Sobrien printf("Warning: %s%s still has %d unmade children\n", 1351236769Sobrien gn->name, gn->cohort_num, gn->unmade); 1352236769Sobrien } 1353236769Sobrien 1354236769Sobrien if (gn->unmade != 0) 1355236769Sobrien Lst_ForEach(gn->children, MakeAddChild, examine); 1356236769Sobrien } 1357236769Sobrien 1358236769Sobrien Lst_Destroy(examine, NULL); 1359236769Sobrien} 1360236769Sobrien 1361236769Sobrien/*- 1362236769Sobrien *----------------------------------------------------------------------- 1363236769Sobrien * Make_ProcessWait -- 1364236769Sobrien * Convert .WAIT nodes into dependencies 1365236769Sobrien * 1366236769Sobrien * Input: 1367236769Sobrien * targs the initial list of targets 1368236769Sobrien * 1369236769Sobrien *----------------------------------------------------------------------- 1370236769Sobrien */ 1371236769Sobrien 1372236769Sobrienstatic int 1373236769Sobrienlink_parent(void *cnp, void *pnp) 1374236769Sobrien{ 1375236769Sobrien GNode *cn = cnp; 1376236769Sobrien GNode *pn = pnp; 1377236769Sobrien 1378236769Sobrien Lst_AtEnd(pn->children, cn); 1379236769Sobrien Lst_AtEnd(cn->parents, pn); 1380236769Sobrien pn->unmade++; 1381236769Sobrien return 0; 1382236769Sobrien} 1383236769Sobrien 1384236769Sobrienstatic int 1385236769Sobrienadd_wait_dep(void *v_cn, void *v_wn) 1386236769Sobrien{ 1387236769Sobrien GNode *cn = v_cn; 1388236769Sobrien GNode *wn = v_wn; 1389236769Sobrien 1390236769Sobrien if (cn == wn) 1391236769Sobrien return 1; 1392236769Sobrien 1393236769Sobrien if (cn == NULL || wn == NULL) { 1394236769Sobrien printf("bad wait dep %p %p\n", cn, wn); 1395236769Sobrien exit(4); 1396236769Sobrien } 1397236769Sobrien if (DEBUG(MAKE)) 1398236769Sobrien fprintf(debug_file, ".WAIT: add dependency %s%s -> %s\n", 1399236769Sobrien cn->name, cn->cohort_num, wn->name); 1400236769Sobrien 1401236769Sobrien Lst_AtEnd(wn->children, cn); 1402236769Sobrien wn->unmade++; 1403236769Sobrien Lst_AtEnd(cn->parents, wn); 1404236769Sobrien return 0; 1405236769Sobrien} 1406236769Sobrien 1407236769Sobrienstatic void 1408236769SobrienMake_ProcessWait(Lst targs) 1409236769Sobrien{ 1410236769Sobrien GNode *pgn; /* 'parent' node we are examining */ 1411236769Sobrien GNode *cgn; /* Each child in turn */ 1412236769Sobrien LstNode owln; /* Previous .WAIT node */ 1413236769Sobrien Lst examine; /* List of targets to examine */ 1414236769Sobrien LstNode ln; 1415236769Sobrien 1416236769Sobrien /* 1417236769Sobrien * We need all the nodes to have a common parent in order for the 1418236769Sobrien * .WAIT and .ORDER scheduling to work. 1419236769Sobrien * Perhaps this should be done earlier... 1420236769Sobrien */ 1421236769Sobrien 1422236769Sobrien pgn = Targ_NewGN(".MAIN"); 1423236769Sobrien pgn->flags = REMAKE; 1424236769Sobrien pgn->type = OP_PHONY | OP_DEPENDS; 1425236769Sobrien /* Get it displayed in the diag dumps */ 1426236769Sobrien Lst_AtFront(Targ_List(), pgn); 1427236769Sobrien 1428236769Sobrien Lst_ForEach(targs, link_parent, pgn); 1429236769Sobrien 1430236769Sobrien /* Start building with the 'dummy' .MAIN' node */ 1431236769Sobrien MakeBuildChild(pgn, NULL); 1432236769Sobrien 1433236769Sobrien examine = Lst_Init(FALSE); 1434236769Sobrien Lst_AtEnd(examine, pgn); 1435236769Sobrien 1436236769Sobrien while (!Lst_IsEmpty (examine)) { 1437236769Sobrien pgn = Lst_DeQueue(examine); 1438236769Sobrien 1439236769Sobrien /* We only want to process each child-list once */ 1440236769Sobrien if (pgn->flags & DONE_WAIT) 1441236769Sobrien continue; 1442236769Sobrien pgn->flags |= DONE_WAIT; 1443236769Sobrien if (DEBUG(MAKE)) 1444236769Sobrien fprintf(debug_file, "Make_ProcessWait: examine %s\n", pgn->name); 1445236769Sobrien 1446236769Sobrien if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts)) { 1447236769Sobrien /* Append all the 'cohorts' to the list of things to examine */ 1448236769Sobrien Lst new; 1449236769Sobrien new = Lst_Duplicate(pgn->cohorts, NULL); 1450236769Sobrien Lst_Concat(new, examine, LST_CONCLINK); 1451236769Sobrien examine = new; 1452236769Sobrien } 1453236769Sobrien 1454236769Sobrien owln = Lst_First(pgn->children); 1455236769Sobrien Lst_Open(pgn->children); 1456236769Sobrien for (; (ln = Lst_Next(pgn->children)) != NULL; ) { 1457236769Sobrien cgn = Lst_Datum(ln); 1458236769Sobrien if (cgn->type & OP_WAIT) { 1459236769Sobrien /* Make the .WAIT node depend on the previous children */ 1460236769Sobrien Lst_ForEachFrom(pgn->children, owln, add_wait_dep, cgn); 1461236769Sobrien owln = ln; 1462236769Sobrien } else { 1463236769Sobrien Lst_AtEnd(examine, cgn); 1464236769Sobrien } 1465236769Sobrien } 1466236769Sobrien Lst_Close(pgn->children); 1467236769Sobrien } 1468236769Sobrien 1469236769Sobrien Lst_Destroy(examine, NULL); 1470236769Sobrien} 1471236769Sobrien 1472236769Sobrien/*- 1473236769Sobrien *----------------------------------------------------------------------- 1474236769Sobrien * Make_Run -- 1475236769Sobrien * Initialize the nodes to remake and the list of nodes which are 1476236769Sobrien * ready to be made by doing a breadth-first traversal of the graph 1477236769Sobrien * starting from the nodes in the given list. Once this traversal 1478236769Sobrien * is finished, all the 'leaves' of the graph are in the toBeMade 1479236769Sobrien * queue. 1480236769Sobrien * Using this queue and the Job module, work back up the graph, 1481236769Sobrien * calling on MakeStartJobs to keep the job table as full as 1482236769Sobrien * possible. 1483236769Sobrien * 1484236769Sobrien * Input: 1485236769Sobrien * targs the initial list of targets 1486236769Sobrien * 1487236769Sobrien * Results: 1488236769Sobrien * TRUE if work was done. FALSE otherwise. 1489236769Sobrien * 1490236769Sobrien * Side Effects: 1491236769Sobrien * The make field of all nodes involved in the creation of the given 1492236769Sobrien * targets is set to 1. The toBeMade list is set to contain all the 1493236769Sobrien * 'leaves' of these subgraphs. 1494236769Sobrien *----------------------------------------------------------------------- 1495236769Sobrien */ 1496236769SobrienBoolean 1497236769SobrienMake_Run(Lst targs) 1498236769Sobrien{ 1499236769Sobrien int errors; /* Number of errors the Job module reports */ 1500236769Sobrien 1501236769Sobrien /* Start trying to make the current targets... */ 1502236769Sobrien toBeMade = Lst_Init(FALSE); 1503236769Sobrien 1504236769Sobrien Make_ExpandUse(targs); 1505236769Sobrien Make_ProcessWait(targs); 1506236769Sobrien 1507236769Sobrien if (DEBUG(MAKE)) { 1508236769Sobrien fprintf(debug_file, "#***# full graph\n"); 1509236769Sobrien Targ_PrintGraph(1); 1510236769Sobrien } 1511236769Sobrien 1512236769Sobrien if (queryFlag) { 1513236769Sobrien /* 1514236769Sobrien * We wouldn't do any work unless we could start some jobs in the 1515236769Sobrien * next loop... (we won't actually start any, of course, this is just 1516236769Sobrien * to see if any of the targets was out of date) 1517236769Sobrien */ 1518236769Sobrien return (MakeStartJobs()); 1519236769Sobrien } 1520236769Sobrien /* 1521236769Sobrien * Initialization. At the moment, no jobs are running and until some 1522236769Sobrien * get started, nothing will happen since the remaining upward 1523236769Sobrien * traversal of the graph is performed by the routines in job.c upon 1524236769Sobrien * the finishing of a job. So we fill the Job table as much as we can 1525236769Sobrien * before going into our loop. 1526236769Sobrien */ 1527236769Sobrien (void)MakeStartJobs(); 1528236769Sobrien 1529236769Sobrien /* 1530236769Sobrien * Main Loop: The idea here is that the ending of jobs will take 1531236769Sobrien * care of the maintenance of data structures and the waiting for output 1532236769Sobrien * will cause us to be idle most of the time while our children run as 1533236769Sobrien * much as possible. Because the job table is kept as full as possible, 1534236769Sobrien * the only time when it will be empty is when all the jobs which need 1535236769Sobrien * running have been run, so that is the end condition of this loop. 1536236769Sobrien * Note that the Job module will exit if there were any errors unless the 1537236769Sobrien * keepgoing flag was given. 1538236769Sobrien */ 1539236769Sobrien while (!Lst_IsEmpty(toBeMade) || jobTokensRunning > 0) { 1540236769Sobrien Job_CatchOutput(); 1541236769Sobrien (void)MakeStartJobs(); 1542236769Sobrien } 1543236769Sobrien 1544236769Sobrien errors = Job_Finish(); 1545236769Sobrien 1546236769Sobrien /* 1547236769Sobrien * Print the final status of each target. E.g. if it wasn't made 1548236769Sobrien * because some inferior reported an error. 1549236769Sobrien */ 1550236769Sobrien if (DEBUG(MAKE)) 1551236769Sobrien fprintf(debug_file, "done: errors %d\n", errors); 1552236769Sobrien if (errors == 0) { 1553236769Sobrien Lst_ForEach(targs, MakePrintStatus, &errors); 1554236769Sobrien if (DEBUG(MAKE)) { 1555236769Sobrien fprintf(debug_file, "done: errors %d\n", errors); 1556236769Sobrien if (errors) 1557236769Sobrien Targ_PrintGraph(4); 1558236769Sobrien } 1559236769Sobrien } 1560236769Sobrien return errors != 0; 1561236769Sobrien} 1562