1 /* $NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 #ifndef MAKE_NATIVE 72 static char rcsid[] = "$NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $"; 73 #else 74 #include <sys/cdefs.h> 75 #ifndef lint 76 #if 0 77 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94"; 78 #else 79 __RCSID("$NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $"); 80 #endif 81 #endif /* not lint */ 82 #endif 83 84 /*- 85 * targ.c -- 86 * Functions for maintaining the Lst allTargets. Target nodes are 87 * kept in two structures: a Lst, maintained by the list library, and a 88 * hash table, maintained by the hash library. 89 * 90 * Interface: 91 * Targ_Init Initialization procedure. 92 * 93 * Targ_End Cleanup the module 94 * 95 * Targ_List Return the list of all targets so far. 96 * 97 * Targ_NewGN Create a new GNode for the passed target 98 * (string). The node is *not* placed in the 99 * hash table, though all its fields are 100 * initialized. 101 * 102 * Targ_FindNode Find the node for a given target, creating 103 * and storing it if it doesn't exist and the 104 * flags are right (TARG_CREATE) 105 * 106 * Targ_FindList Given a list of names, find nodes for all 107 * of them. If a name doesn't exist and the 108 * TARG_NOCREATE flag was given, an error message 109 * is printed. Else, if a name doesn't exist, 110 * its node is created. 111 * 112 * Targ_Ignore Return TRUE if errors should be ignored when 113 * creating the given target. 114 * 115 * Targ_Silent Return TRUE if we should be silent when 116 * creating the given target. 117 * 118 * Targ_Precious Return TRUE if the target is precious and 119 * should not be removed if we are interrupted. 120 * 121 * Targ_Propagate Propagate information between related 122 * nodes. Should be called after the 123 * makefiles are parsed but before any 124 * action is taken. 125 * 126 * Debugging: 127 * Targ_PrintGraph Print out the entire graphm all variables 128 * and statistics for the directory cache. Should 129 * print something for suffixes, too, but... 130 */ 131 132 #include <stdio.h> 133 #include <time.h> 134 135 #include "make.h" 136 #include "hash.h" 137 #include "dir.h" 138 139 static Lst allTargets; /* the list of all targets found so far */ 140 #ifdef CLEANUP 141 static Lst allGNs; /* List of all the GNodes */ 142 #endif 143 static Hash_Table targets; /* a hash table of same */ 144 145 #define HTSIZE 191 /* initial size of hash table */ 146 147 static int TargPrintOnlySrc(ClientData, ClientData); 148 static int TargPrintName(ClientData, ClientData); 149 #ifdef CLEANUP 150 static void TargFreeGN(ClientData); 151 #endif 152 static int TargPropagateCohort(ClientData, ClientData); 153 static int TargPropagateNode(ClientData, ClientData); 154 155 /*- 156 *----------------------------------------------------------------------- 157 * Targ_Init -- 158 * Initialize this module 159 * 160 * Results: 161 * None 162 * 163 * Side Effects: 164 * The allTargets list and the targets hash table are initialized 165 *----------------------------------------------------------------------- 166 */ 167 void 168 Targ_Init(void) 169 { 170 allTargets = Lst_Init(FALSE); 171 Hash_InitTable(&targets, HTSIZE); 172 } 173 174 /*- 175 *----------------------------------------------------------------------- 176 * Targ_End -- 177 * Finalize this module 178 * 179 * Results: 180 * None 181 * 182 * Side Effects: 183 * All lists and gnodes are cleared 184 *----------------------------------------------------------------------- 185 */ 186 void 187 Targ_End(void) 188 { 189 #ifdef CLEANUP 190 Lst_Destroy(allTargets, NOFREE); 191 if (allGNs) 192 Lst_Destroy(allGNs, TargFreeGN); 193 Hash_DeleteTable(&targets); 194 #endif 195 } 196 197 /*- 198 *----------------------------------------------------------------------- 199 * Targ_List -- 200 * Return the list of all targets 201 * 202 * Results: 203 * The list of all targets. 204 * 205 * Side Effects: 206 * None 207 *----------------------------------------------------------------------- 208 */ 209 Lst 210 Targ_List(void) 211 { 212 return allTargets; 213 } 214 215 /*- 216 *----------------------------------------------------------------------- 217 * Targ_NewGN -- 218 * Create and initialize a new graph node 219 * 220 * Input: 221 * name the name to stick in the new node 222 * 223 * Results: 224 * An initialized graph node with the name field filled with a copy 225 * of the passed name 226 * 227 * Side Effects: 228 * The gnode is added to the list of all gnodes. 229 *----------------------------------------------------------------------- 230 */ 231 GNode * 232 Targ_NewGN(const char *name) 233 { 234 GNode *gn; 235 236 gn = emalloc(sizeof(GNode)); 237 gn->name = estrdup(name); 238 gn->uname = NULL; 239 gn->path = NULL; 240 if (name[0] == '-' && name[1] == 'l') { 241 gn->type = OP_LIB; 242 } else { 243 gn->type = 0; 244 } 245 gn->unmade = 0; 246 gn->unmade_cohorts = 0; 247 gn->centurion = NULL; 248 gn->made = UNMADE; 249 gn->flags = 0; 250 gn->order = 0; 251 gn->mtime = gn->cmtime = 0; 252 gn->iParents = Lst_Init(FALSE); 253 gn->cohorts = Lst_Init(FALSE); 254 gn->parents = Lst_Init(FALSE); 255 gn->ancestors = Lst_Init(FALSE); 256 gn->children = Lst_Init(FALSE); 257 gn->successors = Lst_Init(FALSE); 258 gn->preds = Lst_Init(FALSE); 259 gn->recpreds = Lst_Init(FALSE); 260 Hash_InitTable(&gn->context, 0); 261 gn->commands = Lst_Init(FALSE); 262 gn->suffix = NULL; 263 gn->lineno = 0; 264 gn->fname = NULL; 265 266 #ifdef CLEANUP 267 if (allGNs == NULL) 268 allGNs = Lst_Init(FALSE); 269 Lst_AtEnd(allGNs, (ClientData) gn); 270 #endif 271 272 return (gn); 273 } 274 275 #ifdef CLEANUP 276 /*- 277 *----------------------------------------------------------------------- 278 * TargFreeGN -- 279 * Destroy a GNode 280 * 281 * Results: 282 * None. 283 * 284 * Side Effects: 285 * None. 286 *----------------------------------------------------------------------- 287 */ 288 static void 289 TargFreeGN(ClientData gnp) 290 { 291 GNode *gn = (GNode *)gnp; 292 293 294 free(gn->name); 295 if (gn->uname) 296 free(gn->uname); 297 if (gn->path) 298 free(gn->path); 299 if (gn->fname) 300 free(gn->fname); 301 302 Lst_Destroy(gn->iParents, NOFREE); 303 Lst_Destroy(gn->cohorts, NOFREE); 304 Lst_Destroy(gn->parents, NOFREE); 305 Lst_Destroy(gn->ancestors, NOFREE); 306 Lst_Destroy(gn->children, NOFREE); 307 Lst_Destroy(gn->successors, NOFREE); 308 Lst_Destroy(gn->preds, NOFREE); 309 Lst_Destroy(gn->recpreds, NOFREE); 310 Hash_DeleteTable(&gn->context); 311 Lst_Destroy(gn->commands, NOFREE); 312 free(gn); 313 } 314 #endif 315 316 317 /*- 318 *----------------------------------------------------------------------- 319 * Targ_FindNode -- 320 * Find a node in the list using the given name for matching 321 * 322 * Input: 323 * name the name to find 324 * flags flags governing events when target not 325 * found 326 * 327 * Results: 328 * The node in the list if it was. If it wasn't, return NILGNODE of 329 * flags was TARG_NOCREATE or the newly created and initialized node 330 * if it was TARG_CREATE 331 * 332 * Side Effects: 333 * Sometimes a node is created and added to the list 334 *----------------------------------------------------------------------- 335 */ 336 GNode * 337 Targ_FindNode(const char *name, int flags) 338 { 339 GNode *gn; /* node in that element */ 340 Hash_Entry *he; /* New or used hash entry for node */ 341 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 342 /* an entry for the node */ 343 344 345 if (flags & TARG_CREATE) { 346 he = Hash_CreateEntry(&targets, name, &isNew); 347 if (isNew) { 348 gn = Targ_NewGN(name); 349 Hash_SetValue(he, gn); 350 Var_Append(".ALLTARGETS", name, VAR_GLOBAL); 351 (void)Lst_AtEnd(allTargets, (ClientData)gn); 352 } 353 } else { 354 he = Hash_FindEntry(&targets, name); 355 } 356 357 if (he == NULL) { 358 return (NILGNODE); 359 } else { 360 return ((GNode *)Hash_GetValue(he)); 361 } 362 } 363 364 /*- 365 *----------------------------------------------------------------------- 366 * Targ_FindList -- 367 * Make a complete list of GNodes from the given list of names 368 * 369 * Input: 370 * name list of names to find 371 * flags flags used if no node is found for a given name 372 * 373 * Results: 374 * A complete list of graph nodes corresponding to all instances of all 375 * the names in names. 376 * 377 * Side Effects: 378 * If flags is TARG_CREATE, nodes will be created for all names in 379 * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 380 * an error message will be printed for each name which can't be found. 381 * ----------------------------------------------------------------------- 382 */ 383 Lst 384 Targ_FindList(Lst names, int flags) 385 { 386 Lst nodes; /* result list */ 387 LstNode ln; /* name list element */ 388 GNode *gn; /* node in tLn */ 389 char *name; 390 391 nodes = Lst_Init(FALSE); 392 393 if (Lst_Open(names) == FAILURE) { 394 return (nodes); 395 } 396 while ((ln = Lst_Next(names)) != NILLNODE) { 397 name = (char *)Lst_Datum(ln); 398 gn = Targ_FindNode(name, flags); 399 if (gn != NILGNODE) { 400 /* 401 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes 402 * are added to the list in the order in which they were 403 * encountered in the makefile. 404 */ 405 (void)Lst_AtEnd(nodes, (ClientData)gn); 406 } else if (flags == TARG_NOCREATE) { 407 Error("\"%s\" -- target unknown.", name); 408 } 409 } 410 Lst_Close(names); 411 return (nodes); 412 } 413 414 /*- 415 *----------------------------------------------------------------------- 416 * Targ_Ignore -- 417 * Return true if should ignore errors when creating gn 418 * 419 * Input: 420 * gn node to check for 421 * 422 * Results: 423 * TRUE if should ignore errors 424 * 425 * Side Effects: 426 * None 427 *----------------------------------------------------------------------- 428 */ 429 Boolean 430 Targ_Ignore(GNode *gn) 431 { 432 if (ignoreErrors || gn->type & OP_IGNORE) { 433 return (TRUE); 434 } else { 435 return (FALSE); 436 } 437 } 438 439 /*- 440 *----------------------------------------------------------------------- 441 * Targ_Silent -- 442 * Return true if be silent when creating gn 443 * 444 * Input: 445 * gn node to check for 446 * 447 * Results: 448 * TRUE if should be silent 449 * 450 * Side Effects: 451 * None 452 *----------------------------------------------------------------------- 453 */ 454 Boolean 455 Targ_Silent(GNode *gn) 456 { 457 if (beSilent || gn->type & OP_SILENT) { 458 return (TRUE); 459 } else { 460 return (FALSE); 461 } 462 } 463 464 /*- 465 *----------------------------------------------------------------------- 466 * Targ_Precious -- 467 * See if the given target is precious 468 * 469 * Input: 470 * gn the node to check 471 * 472 * Results: 473 * TRUE if it is precious. FALSE otherwise 474 * 475 * Side Effects: 476 * None 477 *----------------------------------------------------------------------- 478 */ 479 Boolean 480 Targ_Precious(GNode *gn) 481 { 482 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 483 return (TRUE); 484 } else { 485 return (FALSE); 486 } 487 } 488 489 /******************* DEBUG INFO PRINTING ****************/ 490 491 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 492 /*- 493 *----------------------------------------------------------------------- 494 * Targ_SetMain -- 495 * Set our idea of the main target we'll be creating. Used for 496 * debugging output. 497 * 498 * Input: 499 * gn The main target we'll create 500 * 501 * Results: 502 * None. 503 * 504 * Side Effects: 505 * "mainTarg" is set to the main target's node. 506 *----------------------------------------------------------------------- 507 */ 508 void 509 Targ_SetMain(GNode *gn) 510 { 511 mainTarg = gn; 512 } 513 514 #define PrintWait (ClientData)1 515 #define PrintPath (ClientData)2 516 517 static int 518 TargPrintName(ClientData gnp, ClientData pflags) 519 { 520 static int last_order; 521 GNode *gn = (GNode *)gnp; 522 523 if (pflags == PrintWait && gn->order > last_order) 524 printf(".WAIT "); 525 last_order = gn->order; 526 527 printf("%s ", gn->name); 528 529 #ifdef notdef 530 if (pflags == PrintPath) { 531 if (gn->path) { 532 printf("[%s] ", gn->path); 533 } 534 if (gn == mainTarg) { 535 printf("(MAIN NAME) "); 536 } 537 } 538 #endif /* notdef */ 539 540 return 0; 541 } 542 543 544 int 545 Targ_PrintCmd(ClientData cmd, ClientData dummy) 546 { 547 printf("\t%s\n", (char *)cmd); 548 return (dummy ? 0 : 0); 549 } 550 551 /*- 552 *----------------------------------------------------------------------- 553 * Targ_FmtTime -- 554 * Format a modification time in some reasonable way and return it. 555 * 556 * Results: 557 * The time reformatted. 558 * 559 * Side Effects: 560 * The time is placed in a static area, so it is overwritten 561 * with each call. 562 * 563 *----------------------------------------------------------------------- 564 */ 565 char * 566 Targ_FmtTime(time_t tm) 567 { 568 struct tm *parts; 569 static char buf[128]; 570 571 parts = localtime(&tm); 572 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 573 return(buf); 574 } 575 576 /*- 577 *----------------------------------------------------------------------- 578 * Targ_PrintType -- 579 * Print out a type field giving only those attributes the user can 580 * set. 581 * 582 * Results: 583 * 584 * Side Effects: 585 * 586 *----------------------------------------------------------------------- 587 */ 588 void 589 Targ_PrintType(int type) 590 { 591 int tbit; 592 593 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 594 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))printf("." #attr " "); break 595 596 type &= ~OP_OPMASK; 597 598 while (type) { 599 tbit = 1 << (ffs(type) - 1); 600 type &= ~tbit; 601 602 switch(tbit) { 603 PRINTBIT(OPTIONAL); 604 PRINTBIT(USE); 605 PRINTBIT(EXEC); 606 PRINTBIT(IGNORE); 607 PRINTBIT(PRECIOUS); 608 PRINTBIT(SILENT); 609 PRINTBIT(MAKE); 610 PRINTBIT(JOIN); 611 PRINTBIT(INVISIBLE); 612 PRINTBIT(NOTMAIN); 613 PRINTDBIT(LIB); 614 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 615 case OP_MEMBER: if (DEBUG(TARG))printf(".MEMBER "); break; 616 PRINTDBIT(ARCHV); 617 PRINTDBIT(MADE); 618 PRINTDBIT(PHONY); 619 } 620 } 621 } 622 623 /*- 624 *----------------------------------------------------------------------- 625 * TargPrintNode -- 626 * print the contents of a node 627 *----------------------------------------------------------------------- 628 */ 629 int 630 Targ_PrintNode(ClientData gnp, ClientData passp) 631 { 632 GNode *gn = (GNode *)gnp; 633 int pass = passp ? *(int *)passp : 0; 634 if (!OP_NOP(gn->type)) { 635 printf("#\n"); 636 if (gn == mainTarg) { 637 printf("# *** MAIN TARGET ***\n"); 638 } 639 if (pass == 2) { 640 if (gn->unmade) { 641 printf("# %d unmade children\n", gn->unmade); 642 } else { 643 printf("# No unmade children\n"); 644 } 645 if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) { 646 if (gn->mtime != 0) { 647 printf("# last modified %s: %s\n", 648 Targ_FmtTime(gn->mtime), 649 (gn->made == UNMADE ? "unmade" : 650 (gn->made == MADE ? "made" : 651 (gn->made == UPTODATE ? "up-to-date" : 652 "error when made")))); 653 } else if (gn->made != UNMADE) { 654 printf("# non-existent (maybe): %s\n", 655 (gn->made == MADE ? "made" : 656 (gn->made == UPTODATE ? "up-to-date" : 657 (gn->made == ERROR ? "error when made" : 658 "aborted")))); 659 } else { 660 printf("# unmade\n"); 661 } 662 } 663 if (!Lst_IsEmpty (gn->iParents)) { 664 printf("# implicit parents: "); 665 Lst_ForEach(gn->iParents, TargPrintName, (ClientData)0); 666 fputc('\n', stdout); 667 } 668 } else { 669 if (gn->unmade) 670 printf("# %d unmade children\n", gn->unmade); 671 } 672 if (!Lst_IsEmpty (gn->parents)) { 673 printf("# parents: "); 674 Lst_ForEach(gn->parents, TargPrintName, (ClientData)0); 675 fputc('\n', stdout); 676 } 677 if (!Lst_IsEmpty (gn->children)) { 678 printf("# children: "); 679 Lst_ForEach(gn->children, TargPrintName, (ClientData)0); 680 fputc('\n', stdout); 681 } 682 if (!Lst_IsEmpty (gn->preds)) { 683 printf("# preds: "); 684 Lst_ForEach(gn->preds, TargPrintName, (ClientData)0); 685 fputc('\n', stdout); 686 } 687 if (!Lst_IsEmpty (gn->recpreds)) { 688 printf("# recpreds: "); 689 Lst_ForEach(gn->recpreds, TargPrintName, (ClientData)0); 690 fputc('\n', stdout); 691 } 692 if (!Lst_IsEmpty (gn->successors)) { 693 printf("# successors: "); 694 Lst_ForEach(gn->successors, TargPrintName, (ClientData)0); 695 fputc('\n', stdout); 696 } 697 698 printf("%-16s", gn->name); 699 switch (gn->type & OP_OPMASK) { 700 case OP_DEPENDS: 701 printf(": "); break; 702 case OP_FORCE: 703 printf("! "); break; 704 case OP_DOUBLEDEP: 705 printf(":: "); break; 706 } 707 Targ_PrintType(gn->type); 708 Lst_ForEach(gn->children, TargPrintName, PrintWait); 709 fputc('\n', stdout); 710 Lst_ForEach(gn->commands, Targ_PrintCmd, (ClientData)0); 711 printf("\n\n"); 712 if (gn->type & OP_DOUBLEDEP) { 713 Lst_ForEach(gn->cohorts, Targ_PrintNode, (ClientData)&pass); 714 } 715 } 716 return (0); 717 } 718 719 /*- 720 *----------------------------------------------------------------------- 721 * TargPrintOnlySrc -- 722 * Print only those targets that are just a source. 723 * 724 * Results: 725 * 0. 726 * 727 * Side Effects: 728 * The name of each file is printed preceded by #\t 729 * 730 *----------------------------------------------------------------------- 731 */ 732 static int 733 TargPrintOnlySrc(ClientData gnp, ClientData dummy) 734 { 735 GNode *gn = (GNode *)gnp; 736 if (OP_NOP(gn->type)) 737 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 738 739 return (dummy ? 0 : 0); 740 } 741 742 /*- 743 *----------------------------------------------------------------------- 744 * Targ_PrintGraph -- 745 * print the entire graph. heh heh 746 * 747 * Input: 748 * pass Which pass this is. 1 => no processing 749 * 2 => processing done 750 * 751 * Results: 752 * none 753 * 754 * Side Effects: 755 * lots o' output 756 *----------------------------------------------------------------------- 757 */ 758 void 759 Targ_PrintGraph(int pass) 760 { 761 printf("#*** Input graph:\n"); 762 Lst_ForEach(allTargets, Targ_PrintNode, (ClientData)&pass); 763 printf("\n\n"); 764 printf("#\n# Files that are only sources:\n"); 765 Lst_ForEach(allTargets, TargPrintOnlySrc, (ClientData) 0); 766 printf("#*** Global Variables:\n"); 767 Var_Dump(VAR_GLOBAL); 768 printf("#*** Command-line Variables:\n"); 769 Var_Dump(VAR_CMD); 770 printf("\n"); 771 Dir_PrintDirectories(); 772 printf("\n"); 773 Suff_PrintAll(); 774 } 775 776 /*- 777 *----------------------------------------------------------------------- 778 * TargAppendAncestor - 779 * Appends a single ancestor to a node's list of ancestors, 780 * ignoring duplicates. 781 * 782 * Input: 783 * ancestorgnp An ancestor to be added to a list. 784 * thisgnp The node whose ancestor list will be changed. 785 * 786 * Results: 787 * Always returns 0, for the benefit of Lst_ForEach(). 788 * 789 * Side Effects: 790 * May modify the ancestors list of the node we are 791 * examining. 792 *----------------------------------------------------------------------- 793 */ 794 static int 795 TargAppendAncestor(ClientData ancestorgnp, ClientData thisgnp) 796 { 797 GNode *ancestorgn = (GNode *)ancestorgnp; 798 GNode *thisgn = (GNode *)thisgnp; 799 800 if (Lst_Member(thisgn->ancestors, ancestorgn) == NILLNODE) { 801 (void)Lst_AtEnd(thisgn->ancestors, (ClientData)ancestorgn); 802 } 803 return (0); 804 } 805 806 /*- 807 *----------------------------------------------------------------------- 808 * TargAppendParentAncestors - 809 * Appends all ancestors of a parent node to the ancestor list of a 810 * given node, ignoring duplicates. 811 * 812 * Input: 813 * parentgnp A parent node whose ancestor list will be 814 * propagated to another node. 815 * thisgnp The node whose ancestor list will be changed. 816 * 817 * Results: 818 * Always returns 0, for the benefit of Lst_ForEach(). 819 * 820 * Side Effects: 821 * May modify the ancestors list of the node we are 822 * examining. 823 *----------------------------------------------------------------------- 824 */ 825 static int 826 TargAppendParentAncestors(ClientData parentgnp, ClientData thisgnp) 827 { 828 GNode *parentgn = (GNode *)parentgnp; 829 GNode *thisgn = (GNode *)thisgnp; 830 831 Lst_ForEach(parentgn->ancestors, TargAppendAncestor, thisgn); 832 return (0); 833 } 834 835 /*- 836 *----------------------------------------------------------------------- 837 * TargInitAncestors - 838 * Initialises the ancestor list of a node and all the 839 * node's ancestors. 840 * 841 * Input: 842 * thisgnp The node that we are examining. 843 * 844 * Results: 845 * Always returns 0, for the benefit of Lst_ForEach(). 846 * 847 * Side Effects: 848 * May initialise the ancestors list of the node we are 849 * examining and all its ancestors. Does nothing if the 850 * list has already been initialised. 851 *----------------------------------------------------------------------- 852 */ 853 static int 854 TargInitAncestors(ClientData thisgnp, ClientData junk __unused) 855 { 856 GNode *thisgn = (GNode *)thisgnp; 857 858 if (Lst_IsEmpty (thisgn->ancestors)) { 859 /* 860 * Add our parents to our ancestor list before recursing, to 861 * ensure that loops in the dependency graph will not result in 862 * infinite recursion. 863 */ 864 Lst_ForEach(thisgn->parents, TargAppendAncestor, thisgn); 865 Lst_ForEach(thisgn->iParents, TargAppendAncestor, thisgn); 866 /* Recursively initialise our parents' ancestor lists */ 867 Lst_ForEach(thisgn->parents, TargInitAncestors, (ClientData)0); 868 Lst_ForEach(thisgn->iParents, TargInitAncestors, (ClientData)0); 869 /* Our parents' ancestors are also our ancestors */ 870 Lst_ForEach(thisgn->parents, TargAppendParentAncestors, thisgn); 871 Lst_ForEach(thisgn->iParents, TargAppendParentAncestors, thisgn); 872 } 873 return (0); 874 } 875 876 /*- 877 *----------------------------------------------------------------------- 878 * TargHasAncestor - 879 * Checks whether one node is an ancestor of another node. 880 * 881 * If called with both arguments pointing to the 882 * same node, checks whether the node is part of a cycle 883 * in the graph. 884 * 885 * Input: 886 * thisgnp The node whose ancestor list we are examining. 887 * seekgnp The node that we are seeking in the 888 * ancestor list. 889 * 890 * Results: 891 * TRUE if seekgn is an ancestor of thisgn; FALSE if not. 892 * 893 * Side Effects: 894 * Initialises the ancestors list in thisgnp and all its ancestors. 895 *----------------------------------------------------------------------- 896 */ 897 static Boolean 898 TargHasAncestor(ClientData thisgnp, ClientData seekgnp) 899 { 900 GNode *thisgn = (GNode *)thisgnp; 901 GNode *seekgn = (GNode *)seekgnp; 902 903 TargInitAncestors(thisgn, (ClientData)0); 904 if (Lst_Member(thisgn->ancestors, seekgn) != NILLNODE) { 905 return (TRUE); 906 } 907 return (FALSE); 908 } 909 910 /*- 911 *----------------------------------------------------------------------- 912 * TargPropagateRecpredChild -- 913 * Create a new predecessor/successor relationship between a pair 914 * of nodes, and recursively propagate the relationship to all 915 * children of the successor node. 916 * 917 * If there is already a predecessor/successor relationship 918 * in the opposite direction, or if there is already an 919 * ancestor/descendent relationship in the oposite direction, then 920 * we avoid adding the new relationship, because that would cause a 921 * cycle in the graph. 922 * 923 * Input: 924 * succgnp Successor node. 925 * predgnp Predecessor node. 926 * 927 * Results: 928 * Always returns 0, for the benefit of Lst_ForEach(). 929 * 930 * Side Effects: 931 * preds/successors information is modified for predgnp, succgnp, 932 * and recursively for all children of succgnp. 933 *----------------------------------------------------------------------- 934 */ 935 static int 936 TargPropagateRecpredChild(ClientData succgnp, ClientData predgnp) 937 { 938 GNode *succgn = (GNode *)succgnp; 939 GNode *predgn = (GNode *)predgnp; 940 Boolean debugmore = FALSE; /* how much debugging? */ 941 942 /* Ignore if succgn == predgn */ 943 if (succgn == predgn) { 944 if (DEBUG(TARG) && debugmore) { 945 printf("# TargPropagateRecpredChild: not propagating %s - %s (identical)\n", 946 predgn->name, succgn->name); 947 } 948 return (0); 949 } 950 /* Pre-existing pred/successor relationship 951 * in the opposite direction takes precedence. */ 952 if (Lst_Member(succgn->successors, predgn) != NILLNODE) { 953 if (DEBUG(TARG) && debugmore) { 954 printf("# TargPropagateRecpredChild: not propagating %s - %s (opposite)\n", 955 predgn->name, succgn->name); 956 } 957 return (0); 958 } 959 /* Pre-existing descendent/ancestor relationship in the opposite 960 * direction takes precedence. */ 961 if (TargHasAncestor(succgn, predgn)) { 962 if (DEBUG(TARG) && debugmore) { 963 printf("# TargPropagateRecpredChild: not propagating %s - %s (ancestor)\n", 964 predgn->name, succgn->name); 965 } 966 return (0); 967 } 968 /* Note the new pred/successor relationship. */ 969 if (DEBUG(TARG)) { 970 printf("# TargPropagateRecpredChild: propagating %s - %s\n", 971 predgn->name, succgn->name); 972 } 973 if (Lst_Member(succgn->preds, predgn) == NILLNODE) { 974 (void)Lst_AtEnd(succgn->preds, (ClientData)predgn); 975 (void)Lst_AtEnd(predgn->successors, (ClientData)succgn); 976 } 977 /* Recurse, provided there's not a cycle. */ 978 if (! TargHasAncestor(succgn, succgn)) { 979 Lst_ForEach(succgn->children, TargPropagateRecpredChild, predgn); 980 } 981 return (0); 982 } 983 984 /*- 985 *----------------------------------------------------------------------- 986 * TargPropagateRecpred -- 987 * Recursively propagate information about a single predecessor 988 * node, from a single successor node to all children of the 989 * successor node. 990 * 991 * Input: 992 * predgnp Predecessor node. 993 * succgnp Successor node. 994 * 995 * Results: 996 * Always returns 0, for the benefit of Lst_ForEach(). 997 * 998 * Side Effects: 999 * preds/successors information is modified for predgnp, succgnp, 1000 * and recursively for all children of succgnp. 1001 * 1002 * The real work is done by TargPropagateRecpredChild(), which 1003 * will be called for each child of the successor node. 1004 *----------------------------------------------------------------------- 1005 */ 1006 static int 1007 TargPropagateRecpred(ClientData predgnp, ClientData succgnp) 1008 { 1009 GNode *predgn = (GNode *)predgnp; 1010 GNode *succgn = (GNode *)succgnp; 1011 1012 Lst_ForEach(succgn->children, TargPropagateRecpredChild, predgn); 1013 return (0); 1014 } 1015 1016 /*- 1017 *----------------------------------------------------------------------- 1018 * TargPropagateNode -- 1019 * Propagate information from a single node to related nodes if 1020 * appropriate. 1021 * 1022 * Input: 1023 * gnp The node that we are processing. 1024 * 1025 * Results: 1026 * Always returns 0, for the benefit of Lst_ForEach(). 1027 * 1028 * Side Effects: 1029 * Information is propagated from this node to cohort or child 1030 * nodes. 1031 * 1032 * If the node was defined with "::", then TargPropagateCohort() 1033 * will be called for each cohort node. 1034 * 1035 * If the node has recursive predecessors, then 1036 * TargPropagateRecpred() will be called for each recursive 1037 * predecessor. 1038 *----------------------------------------------------------------------- 1039 */ 1040 static int 1041 TargPropagateNode(ClientData gnp, ClientData junk __unused) 1042 { 1043 GNode *gn = (GNode *)gnp; 1044 if (gn->type & OP_DOUBLEDEP) 1045 Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp); 1046 Lst_ForEach(gn->recpreds, TargPropagateRecpred, gnp); 1047 return (0); 1048 } 1049 1050 /*- 1051 *----------------------------------------------------------------------- 1052 * TargPropagateCohort -- 1053 * Propagate some bits in the type mask from a node to 1054 * a related cohort node. 1055 * 1056 * Input: 1057 * cnp The node that we are processing. 1058 * gnp Another node that has cnp as a cohort. 1059 * 1060 * Results: 1061 * Always returns 0, for the benefit of Lst_ForEach(). 1062 * 1063 * Side Effects: 1064 * cnp's type bitmask is modified to incorporate some of the 1065 * bits from gnp's type bitmask. (XXX need a better explanation.) 1066 *----------------------------------------------------------------------- 1067 */ 1068 static int 1069 TargPropagateCohort(ClientData cgnp, ClientData pgnp) 1070 { 1071 GNode *cgn = (GNode *)cgnp; 1072 GNode *pgn = (GNode *)pgnp; 1073 1074 cgn->type |= pgn->type & ~OP_OPMASK; 1075 return (0); 1076 } 1077 1078 /*- 1079 *----------------------------------------------------------------------- 1080 * Targ_Propagate -- 1081 * Propagate information between related nodes. Should be called 1082 * after the makefiles are parsed but before any action is taken. 1083 * 1084 * Results: 1085 * none 1086 * 1087 * Side Effects: 1088 * Information is propagated between related nodes throughout the 1089 * graph. 1090 *----------------------------------------------------------------------- 1091 */ 1092 void 1093 Targ_Propagate(void) 1094 { 1095 Lst_ForEach(allTargets, TargPropagateNode, (ClientData)0); 1096 } 1097