1 /* $NetBSD: targ.c,v 1.39 2006/01/08 17:43:31 dsl 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.39 2006/01/08 17:43:31 dsl 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.39 2006/01/08 17:43:31 dsl 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 * Debugging: 122 * Targ_PrintGraph Print out the entire graphm all variables 123 * and statistics for the directory cache. Should 124 * print something for suffixes, too, but... 125 */ 126 127 #include <stdio.h> 128 #include <time.h> 129 130 #include "make.h" 131 #include "hash.h" 132 #include "dir.h" 133 134 static Lst allTargets; /* the list of all targets found so far */ 135 #ifdef CLEANUP 136 static Lst allGNs; /* List of all the GNodes */ 137 #endif 138 static Hash_Table targets; /* a hash table of same */ 139 140 #define HTSIZE 191 /* initial size of hash table */ 141 142 static int TargPrintOnlySrc(ClientData, ClientData); 143 static int TargPrintName(ClientData, ClientData); 144 static int TargPrintNode(ClientData, ClientData); 145 #ifdef CLEANUP 146 static void TargFreeGN(ClientData); 147 #endif 148 static int TargPropagateCohort(ClientData, ClientData); 149 static int TargPropagateNode(ClientData, ClientData); 150 151 /*- 152 *----------------------------------------------------------------------- 153 * Targ_Init -- 154 * Initialize this module 155 * 156 * Results: 157 * None 158 * 159 * Side Effects: 160 * The allTargets list and the targets hash table are initialized 161 *----------------------------------------------------------------------- 162 */ 163 void 164 Targ_Init(void) 165 { 166 allTargets = Lst_Init(FALSE); 167 Hash_InitTable(&targets, HTSIZE); 168 } 169 170 /*- 171 *----------------------------------------------------------------------- 172 * Targ_End -- 173 * Finalize this module 174 * 175 * Results: 176 * None 177 * 178 * Side Effects: 179 * All lists and gnodes are cleared 180 *----------------------------------------------------------------------- 181 */ 182 void 183 Targ_End(void) 184 { 185 #ifdef CLEANUP 186 Lst_Destroy(allTargets, NOFREE); 187 if (allGNs) 188 Lst_Destroy(allGNs, TargFreeGN); 189 Hash_DeleteTable(&targets); 190 #endif 191 } 192 193 /*- 194 *----------------------------------------------------------------------- 195 * Targ_List -- 196 * Return the list of all targets 197 * 198 * Results: 199 * The list of all targets. 200 * 201 * Side Effects: 202 * None 203 *----------------------------------------------------------------------- 204 */ 205 Lst 206 Targ_List(void) 207 { 208 return allTargets; 209 } 210 211 /*- 212 *----------------------------------------------------------------------- 213 * Targ_NewGN -- 214 * Create and initialize a new graph node 215 * 216 * Input: 217 * name the name to stick in the new node 218 * 219 * Results: 220 * An initialized graph node with the name field filled with a copy 221 * of the passed name 222 * 223 * Side Effects: 224 * The gnode is added to the list of all gnodes. 225 *----------------------------------------------------------------------- 226 */ 227 GNode * 228 Targ_NewGN(const char *name) 229 { 230 GNode *gn; 231 232 gn = emalloc(sizeof(GNode)); 233 gn->name = estrdup(name); 234 gn->uname = NULL; 235 gn->path = NULL; 236 if (name[0] == '-' && name[1] == 'l') { 237 gn->type = OP_LIB; 238 } else { 239 gn->type = 0; 240 } 241 gn->unmade = 0; 242 gn->unmade_cohorts = 0; 243 gn->centurion = NULL; 244 gn->made = UNMADE; 245 gn->flags = 0; 246 gn->order = 0; 247 gn->mtime = gn->cmtime = 0; 248 gn->iParents = Lst_Init(FALSE); 249 gn->cohorts = Lst_Init(FALSE); 250 gn->parents = Lst_Init(FALSE); 251 gn->children = Lst_Init(FALSE); 252 gn->successors = Lst_Init(FALSE); 253 gn->preds = Lst_Init(FALSE); 254 Hash_InitTable(&gn->context, 0); 255 gn->commands = Lst_Init(FALSE); 256 gn->suffix = NULL; 257 gn->lineno = 0; 258 gn->fname = NULL; 259 260 #ifdef CLEANUP 261 if (allGNs == NULL) 262 allGNs = Lst_Init(FALSE); 263 Lst_AtEnd(allGNs, (ClientData) gn); 264 #endif 265 266 return (gn); 267 } 268 269 #ifdef CLEANUP 270 /*- 271 *----------------------------------------------------------------------- 272 * TargFreeGN -- 273 * Destroy a GNode 274 * 275 * Results: 276 * None. 277 * 278 * Side Effects: 279 * None. 280 *----------------------------------------------------------------------- 281 */ 282 static void 283 TargFreeGN(ClientData gnp) 284 { 285 GNode *gn = (GNode *)gnp; 286 287 288 free(gn->name); 289 if (gn->uname) 290 free(gn->uname); 291 if (gn->path) 292 free(gn->path); 293 if (gn->fname) 294 free(gn->fname); 295 296 Lst_Destroy(gn->iParents, NOFREE); 297 Lst_Destroy(gn->cohorts, NOFREE); 298 Lst_Destroy(gn->parents, NOFREE); 299 Lst_Destroy(gn->children, NOFREE); 300 Lst_Destroy(gn->successors, NOFREE); 301 Lst_Destroy(gn->preds, NOFREE); 302 Hash_DeleteTable(&gn->context); 303 Lst_Destroy(gn->commands, NOFREE); 304 free(gn); 305 } 306 #endif 307 308 309 /*- 310 *----------------------------------------------------------------------- 311 * Targ_FindNode -- 312 * Find a node in the list using the given name for matching 313 * 314 * Input: 315 * name the name to find 316 * flags flags governing events when target not 317 * found 318 * 319 * Results: 320 * The node in the list if it was. If it wasn't, return NILGNODE of 321 * flags was TARG_NOCREATE or the newly created and initialized node 322 * if it was TARG_CREATE 323 * 324 * Side Effects: 325 * Sometimes a node is created and added to the list 326 *----------------------------------------------------------------------- 327 */ 328 GNode * 329 Targ_FindNode(const char *name, int flags) 330 { 331 GNode *gn; /* node in that element */ 332 Hash_Entry *he; /* New or used hash entry for node */ 333 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 334 /* an entry for the node */ 335 336 337 if (flags & TARG_CREATE) { 338 he = Hash_CreateEntry(&targets, name, &isNew); 339 if (isNew) { 340 gn = Targ_NewGN(name); 341 Hash_SetValue(he, gn); 342 Var_Append(".ALLTARGETS", name, VAR_GLOBAL); 343 (void)Lst_AtEnd(allTargets, (ClientData)gn); 344 } 345 } else { 346 he = Hash_FindEntry(&targets, name); 347 } 348 349 if (he == NULL) { 350 return (NILGNODE); 351 } else { 352 return ((GNode *)Hash_GetValue(he)); 353 } 354 } 355 356 /*- 357 *----------------------------------------------------------------------- 358 * Targ_FindList -- 359 * Make a complete list of GNodes from the given list of names 360 * 361 * Input: 362 * name list of names to find 363 * flags flags used if no node is found for a given name 364 * 365 * Results: 366 * A complete list of graph nodes corresponding to all instances of all 367 * the names in names. 368 * 369 * Side Effects: 370 * If flags is TARG_CREATE, nodes will be created for all names in 371 * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 372 * an error message will be printed for each name which can't be found. 373 * ----------------------------------------------------------------------- 374 */ 375 Lst 376 Targ_FindList(Lst names, int flags) 377 { 378 Lst nodes; /* result list */ 379 LstNode ln; /* name list element */ 380 GNode *gn; /* node in tLn */ 381 char *name; 382 383 nodes = Lst_Init(FALSE); 384 385 if (Lst_Open(names) == FAILURE) { 386 return (nodes); 387 } 388 while ((ln = Lst_Next(names)) != NILLNODE) { 389 name = (char *)Lst_Datum(ln); 390 gn = Targ_FindNode(name, flags); 391 if (gn != NILGNODE) { 392 /* 393 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes 394 * are added to the list in the order in which they were 395 * encountered in the makefile. 396 */ 397 (void)Lst_AtEnd(nodes, (ClientData)gn); 398 } else if (flags == TARG_NOCREATE) { 399 Error("\"%s\" -- target unknown.", name); 400 } 401 } 402 Lst_Close(names); 403 return (nodes); 404 } 405 406 /*- 407 *----------------------------------------------------------------------- 408 * Targ_Ignore -- 409 * Return true if should ignore errors when creating gn 410 * 411 * Input: 412 * gn node to check for 413 * 414 * Results: 415 * TRUE if should ignore errors 416 * 417 * Side Effects: 418 * None 419 *----------------------------------------------------------------------- 420 */ 421 Boolean 422 Targ_Ignore(GNode *gn) 423 { 424 if (ignoreErrors || gn->type & OP_IGNORE) { 425 return (TRUE); 426 } else { 427 return (FALSE); 428 } 429 } 430 431 /*- 432 *----------------------------------------------------------------------- 433 * Targ_Silent -- 434 * Return true if be silent when creating gn 435 * 436 * Input: 437 * gn node to check for 438 * 439 * Results: 440 * TRUE if should be silent 441 * 442 * Side Effects: 443 * None 444 *----------------------------------------------------------------------- 445 */ 446 Boolean 447 Targ_Silent(GNode *gn) 448 { 449 if (beSilent || gn->type & OP_SILENT) { 450 return (TRUE); 451 } else { 452 return (FALSE); 453 } 454 } 455 456 /*- 457 *----------------------------------------------------------------------- 458 * Targ_Precious -- 459 * See if the given target is precious 460 * 461 * Input: 462 * gn the node to check 463 * 464 * Results: 465 * TRUE if it is precious. FALSE otherwise 466 * 467 * Side Effects: 468 * None 469 *----------------------------------------------------------------------- 470 */ 471 Boolean 472 Targ_Precious(GNode *gn) 473 { 474 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 475 return (TRUE); 476 } else { 477 return (FALSE); 478 } 479 } 480 481 /******************* DEBUG INFO PRINTING ****************/ 482 483 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 484 /*- 485 *----------------------------------------------------------------------- 486 * Targ_SetMain -- 487 * Set our idea of the main target we'll be creating. Used for 488 * debugging output. 489 * 490 * Input: 491 * gn The main target we'll create 492 * 493 * Results: 494 * None. 495 * 496 * Side Effects: 497 * "mainTarg" is set to the main target's node. 498 *----------------------------------------------------------------------- 499 */ 500 void 501 Targ_SetMain(GNode *gn) 502 { 503 mainTarg = gn; 504 } 505 506 #define PrintWait (ClientData)1 507 #define PrintPath (ClientData)2 508 509 static int 510 TargPrintName(ClientData gnp, ClientData pflags) 511 { 512 static int last_order; 513 GNode *gn = (GNode *)gnp; 514 515 if (pflags == PrintWait && gn->order > last_order) 516 printf(".WAIT "); 517 last_order = gn->order; 518 519 printf("%s ", gn->name); 520 521 #ifdef notdef 522 if (pflags == PrintPath) { 523 if (gn->path) { 524 printf("[%s] ", gn->path); 525 } 526 if (gn == mainTarg) { 527 printf("(MAIN NAME) "); 528 } 529 } 530 #endif /* notdef */ 531 532 return 0; 533 } 534 535 536 int 537 Targ_PrintCmd(ClientData cmd, ClientData dummy) 538 { 539 printf("\t%s\n", (char *)cmd); 540 return (dummy ? 0 : 0); 541 } 542 543 /*- 544 *----------------------------------------------------------------------- 545 * Targ_FmtTime -- 546 * Format a modification time in some reasonable way and return it. 547 * 548 * Results: 549 * The time reformatted. 550 * 551 * Side Effects: 552 * The time is placed in a static area, so it is overwritten 553 * with each call. 554 * 555 *----------------------------------------------------------------------- 556 */ 557 char * 558 Targ_FmtTime(time_t tm) 559 { 560 struct tm *parts; 561 static char buf[128]; 562 563 parts = localtime(&tm); 564 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 565 return(buf); 566 } 567 568 /*- 569 *----------------------------------------------------------------------- 570 * Targ_PrintType -- 571 * Print out a type field giving only those attributes the user can 572 * set. 573 * 574 * Results: 575 * 576 * Side Effects: 577 * 578 *----------------------------------------------------------------------- 579 */ 580 void 581 Targ_PrintType(int type) 582 { 583 int tbit; 584 585 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 586 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))printf("." #attr " "); break 587 588 type &= ~OP_OPMASK; 589 590 while (type) { 591 tbit = 1 << (ffs(type) - 1); 592 type &= ~tbit; 593 594 switch(tbit) { 595 PRINTBIT(OPTIONAL); 596 PRINTBIT(USE); 597 PRINTBIT(EXEC); 598 PRINTBIT(IGNORE); 599 PRINTBIT(PRECIOUS); 600 PRINTBIT(SILENT); 601 PRINTBIT(MAKE); 602 PRINTBIT(JOIN); 603 PRINTBIT(INVISIBLE); 604 PRINTBIT(NOTMAIN); 605 PRINTDBIT(LIB); 606 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 607 case OP_MEMBER: if (DEBUG(TARG))printf(".MEMBER "); break; 608 PRINTDBIT(ARCHV); 609 PRINTDBIT(MADE); 610 PRINTDBIT(PHONY); 611 } 612 } 613 } 614 615 /*- 616 *----------------------------------------------------------------------- 617 * TargPrintNode -- 618 * print the contents of a node 619 *----------------------------------------------------------------------- 620 */ 621 static int 622 TargPrintNode(ClientData gnp, ClientData passp) 623 { 624 GNode *gn = (GNode *)gnp; 625 int pass = *(int *)passp; 626 if (!OP_NOP(gn->type)) { 627 printf("#\n"); 628 if (gn == mainTarg) { 629 printf("# *** MAIN TARGET ***\n"); 630 } 631 if (pass == 2) { 632 if (gn->unmade) { 633 printf("# %d unmade children\n", gn->unmade); 634 } else { 635 printf("# No unmade children\n"); 636 } 637 if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) { 638 if (gn->mtime != 0) { 639 printf("# last modified %s: %s\n", 640 Targ_FmtTime(gn->mtime), 641 (gn->made == UNMADE ? "unmade" : 642 (gn->made == MADE ? "made" : 643 (gn->made == UPTODATE ? "up-to-date" : 644 "error when made")))); 645 } else if (gn->made != UNMADE) { 646 printf("# non-existent (maybe): %s\n", 647 (gn->made == MADE ? "made" : 648 (gn->made == UPTODATE ? "up-to-date" : 649 (gn->made == ERROR ? "error when made" : 650 "aborted")))); 651 } else { 652 printf("# unmade\n"); 653 } 654 } 655 if (!Lst_IsEmpty (gn->iParents)) { 656 printf("# implicit parents: "); 657 Lst_ForEach(gn->iParents, TargPrintName, (ClientData)0); 658 fputc('\n', stdout); 659 } 660 } 661 if (!Lst_IsEmpty (gn->parents)) { 662 printf("# parents: "); 663 Lst_ForEach(gn->parents, TargPrintName, (ClientData)0); 664 fputc('\n', stdout); 665 } 666 if (!Lst_IsEmpty (gn->preds)) { 667 printf("# preds: "); 668 Lst_ForEach(gn->preds, TargPrintName, (ClientData)0); 669 fputc('\n', stdout); 670 } 671 if (!Lst_IsEmpty (gn->successors)) { 672 printf("# successors: "); 673 Lst_ForEach(gn->successors, TargPrintName, (ClientData)0); 674 fputc('\n', stdout); 675 } 676 677 printf("%-16s", gn->name); 678 switch (gn->type & OP_OPMASK) { 679 case OP_DEPENDS: 680 printf(": "); break; 681 case OP_FORCE: 682 printf("! "); break; 683 case OP_DOUBLEDEP: 684 printf(":: "); break; 685 } 686 Targ_PrintType(gn->type); 687 Lst_ForEach(gn->children, TargPrintName, PrintWait); 688 fputc('\n', stdout); 689 Lst_ForEach(gn->commands, Targ_PrintCmd, (ClientData)0); 690 printf("\n\n"); 691 if (gn->type & OP_DOUBLEDEP) { 692 Lst_ForEach(gn->cohorts, TargPrintNode, (ClientData)&pass); 693 } 694 } 695 return (0); 696 } 697 698 /*- 699 *----------------------------------------------------------------------- 700 * TargPrintOnlySrc -- 701 * Print only those targets that are just a source. 702 * 703 * Results: 704 * 0. 705 * 706 * Side Effects: 707 * The name of each file is printed preceded by #\t 708 * 709 *----------------------------------------------------------------------- 710 */ 711 static int 712 TargPrintOnlySrc(ClientData gnp, ClientData dummy) 713 { 714 GNode *gn = (GNode *)gnp; 715 if (OP_NOP(gn->type)) 716 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 717 718 return (dummy ? 0 : 0); 719 } 720 721 /*- 722 *----------------------------------------------------------------------- 723 * Targ_PrintGraph -- 724 * print the entire graph. heh heh 725 * 726 * Input: 727 * pass Which pass this is. 1 => no processing 728 * 2 => processing done 729 * 730 * Results: 731 * none 732 * 733 * Side Effects: 734 * lots o' output 735 *----------------------------------------------------------------------- 736 */ 737 void 738 Targ_PrintGraph(int pass) 739 { 740 printf("#*** Input graph:\n"); 741 Lst_ForEach(allTargets, TargPrintNode, (ClientData)&pass); 742 printf("\n\n"); 743 printf("#\n# Files that are only sources:\n"); 744 Lst_ForEach(allTargets, TargPrintOnlySrc, (ClientData) 0); 745 printf("#*** Global Variables:\n"); 746 Var_Dump(VAR_GLOBAL); 747 printf("#*** Command-line Variables:\n"); 748 Var_Dump(VAR_CMD); 749 printf("\n"); 750 Dir_PrintDirectories(); 751 printf("\n"); 752 Suff_PrintAll(); 753 } 754 755 static int 756 TargPropagateCohort(ClientData cgnp, ClientData pgnp) 757 { 758 GNode *cgn = (GNode *)cgnp; 759 GNode *pgn = (GNode *)pgnp; 760 761 cgn->type |= pgn->type & ~OP_OPMASK; 762 return (0); 763 } 764 765 static int 766 TargPropagateNode(ClientData gnp, ClientData junk __unused) 767 { 768 GNode *gn = (GNode *)gnp; 769 if (gn->type & OP_DOUBLEDEP) 770 Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp); 771 return (0); 772 } 773 774 void 775 Targ_Propagate(void) 776 { 777 Lst_ForEach(allTargets, TargPropagateNode, (ClientData)0); 778 } 779