1 /* $NetBSD: targ.c,v 1.28 2002/06/15 18:24:58 wiz Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1989 by Berkeley Softworks 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Adam de Boor. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #ifdef MAKE_BOOTSTRAP 42 static char rcsid[] = "$NetBSD: targ.c,v 1.28 2002/06/15 18:24:58 wiz Exp $"; 43 #else 44 #include <sys/cdefs.h> 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94"; 48 #else 49 __RCSID("$NetBSD: targ.c,v 1.28 2002/06/15 18:24:58 wiz Exp $"); 50 #endif 51 #endif /* not lint */ 52 #endif 53 54 /*- 55 * targ.c -- 56 * Functions for maintaining the Lst allTargets. Target nodes are 57 * kept in two structures: a Lst, maintained by the list library, and a 58 * hash table, maintained by the hash library. 59 * 60 * Interface: 61 * Targ_Init Initialization procedure. 62 * 63 * Targ_End Cleanup the module 64 * 65 * Targ_List Return the list of all targets so far. 66 * 67 * Targ_NewGN Create a new GNode for the passed target 68 * (string). The node is *not* placed in the 69 * hash table, though all its fields are 70 * initialized. 71 * 72 * Targ_FindNode Find the node for a given target, creating 73 * and storing it if it doesn't exist and the 74 * flags are right (TARG_CREATE) 75 * 76 * Targ_FindList Given a list of names, find nodes for all 77 * of them. If a name doesn't exist and the 78 * TARG_NOCREATE flag was given, an error message 79 * is printed. Else, if a name doesn't exist, 80 * its node is created. 81 * 82 * Targ_Ignore Return TRUE if errors should be ignored when 83 * creating the given target. 84 * 85 * Targ_Silent Return TRUE if we should be silent when 86 * creating the given target. 87 * 88 * Targ_Precious Return TRUE if the target is precious and 89 * should not be removed if we are interrupted. 90 * 91 * Debugging: 92 * Targ_PrintGraph Print out the entire graphm all variables 93 * and statistics for the directory cache. Should 94 * print something for suffixes, too, but... 95 */ 96 97 #include <stdio.h> 98 #include <time.h> 99 100 #include "make.h" 101 #include "hash.h" 102 #include "dir.h" 103 104 static Lst allTargets; /* the list of all targets found so far */ 105 #ifdef CLEANUP 106 static Lst allGNs; /* List of all the GNodes */ 107 #endif 108 static Hash_Table targets; /* a hash table of same */ 109 110 #define HTSIZE 191 /* initial size of hash table */ 111 112 static int TargPrintOnlySrc(ClientData, ClientData); 113 static int TargPrintName(ClientData, ClientData); 114 static int TargPrintNode(ClientData, ClientData); 115 #ifdef CLEANUP 116 static void TargFreeGN(ClientData); 117 #endif 118 static int TargPropagateCohort(ClientData, ClientData); 119 static int TargPropagateNode(ClientData, ClientData); 120 121 /*- 122 *----------------------------------------------------------------------- 123 * Targ_Init -- 124 * Initialize this module 125 * 126 * Results: 127 * None 128 * 129 * Side Effects: 130 * The allTargets list and the targets hash table are initialized 131 *----------------------------------------------------------------------- 132 */ 133 void 134 Targ_Init(void) 135 { 136 allTargets = Lst_Init (FALSE); 137 Hash_InitTable (&targets, HTSIZE); 138 } 139 140 /*- 141 *----------------------------------------------------------------------- 142 * Targ_End -- 143 * Finalize this module 144 * 145 * Results: 146 * None 147 * 148 * Side Effects: 149 * All lists and gnodes are cleared 150 *----------------------------------------------------------------------- 151 */ 152 void 153 Targ_End(void) 154 { 155 #ifdef CLEANUP 156 Lst_Destroy(allTargets, NOFREE); 157 if (allGNs) 158 Lst_Destroy(allGNs, TargFreeGN); 159 Hash_DeleteTable(&targets); 160 #endif 161 } 162 163 /*- 164 *----------------------------------------------------------------------- 165 * Targ_List -- 166 * Return the list of all targets 167 * 168 * Results: 169 * The list of all targets. 170 * 171 * Side Effects: 172 * None 173 *----------------------------------------------------------------------- 174 */ 175 Lst 176 Targ_List(void) 177 { 178 return allTargets; 179 } 180 181 /*- 182 *----------------------------------------------------------------------- 183 * Targ_NewGN -- 184 * Create and initialize a new graph node 185 * 186 * Input: 187 * name the name to stick in the new node 188 * 189 * Results: 190 * An initialized graph node with the name field filled with a copy 191 * of the passed name 192 * 193 * Side Effects: 194 * The gnode is added to the list of all gnodes. 195 *----------------------------------------------------------------------- 196 */ 197 GNode * 198 Targ_NewGN(char *name) 199 { 200 GNode *gn; 201 202 gn = (GNode *) emalloc (sizeof (GNode)); 203 gn->name = estrdup (name); 204 gn->uname = NULL; 205 gn->path = (char *) 0; 206 if (name[0] == '-' && name[1] == 'l') { 207 gn->type = OP_LIB; 208 } else { 209 gn->type = 0; 210 } 211 gn->unmade = 0; 212 gn->unmade_cohorts = 0; 213 gn->centurion = NULL; 214 gn->made = UNMADE; 215 gn->flags = 0; 216 gn->order = 0; 217 gn->mtime = gn->cmtime = 0; 218 gn->iParents = Lst_Init (FALSE); 219 gn->cohorts = Lst_Init (FALSE); 220 gn->parents = Lst_Init (FALSE); 221 gn->children = Lst_Init (FALSE); 222 gn->successors = Lst_Init (FALSE); 223 gn->preds = Lst_Init (FALSE); 224 Hash_InitTable(&gn->context, 0); 225 gn->commands = Lst_Init (FALSE); 226 gn->suffix = NULL; 227 gn->lineno = 0; 228 gn->fname = NULL; 229 230 #ifdef CLEANUP 231 if (allGNs == NULL) 232 allGNs = Lst_Init(FALSE); 233 Lst_AtEnd(allGNs, (ClientData) gn); 234 #endif 235 236 return (gn); 237 } 238 239 #ifdef CLEANUP 240 /*- 241 *----------------------------------------------------------------------- 242 * TargFreeGN -- 243 * Destroy a GNode 244 * 245 * Results: 246 * None. 247 * 248 * Side Effects: 249 * None. 250 *----------------------------------------------------------------------- 251 */ 252 static void 253 TargFreeGN(ClientData gnp) 254 { 255 GNode *gn = (GNode *) gnp; 256 257 258 free(gn->name); 259 if (gn->uname) 260 free(gn->uname); 261 if (gn->path) 262 free(gn->path); 263 if (gn->fname) 264 free(gn->fname); 265 266 Lst_Destroy(gn->iParents, NOFREE); 267 Lst_Destroy(gn->cohorts, NOFREE); 268 Lst_Destroy(gn->parents, NOFREE); 269 Lst_Destroy(gn->children, NOFREE); 270 Lst_Destroy(gn->successors, NOFREE); 271 Lst_Destroy(gn->preds, NOFREE); 272 Hash_DeleteTable(&gn->context); 273 Lst_Destroy(gn->commands, NOFREE); 274 free((Address)gn); 275 } 276 #endif 277 278 279 /*- 280 *----------------------------------------------------------------------- 281 * Targ_FindNode -- 282 * Find a node in the list using the given name for matching 283 * 284 * Input: 285 * name the name to find 286 * flags flags governing events when target not 287 * found 288 * 289 * Results: 290 * The node in the list if it was. If it wasn't, return NILGNODE of 291 * flags was TARG_NOCREATE or the newly created and initialized node 292 * if it was TARG_CREATE 293 * 294 * Side Effects: 295 * Sometimes a node is created and added to the list 296 *----------------------------------------------------------------------- 297 */ 298 GNode * 299 Targ_FindNode(char *name, int flags) 300 { 301 GNode *gn; /* node in that element */ 302 Hash_Entry *he; /* New or used hash entry for node */ 303 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 304 /* an entry for the node */ 305 306 307 if (flags & TARG_CREATE) { 308 he = Hash_CreateEntry (&targets, name, &isNew); 309 if (isNew) { 310 gn = Targ_NewGN (name); 311 Hash_SetValue (he, gn); 312 Var_Append(".ALLTARGETS", name, VAR_GLOBAL); 313 (void) Lst_AtEnd (allTargets, (ClientData)gn); 314 } 315 } else { 316 he = Hash_FindEntry (&targets, name); 317 } 318 319 if (he == (Hash_Entry *) NULL) { 320 return (NILGNODE); 321 } else { 322 return ((GNode *) Hash_GetValue (he)); 323 } 324 } 325 326 /*- 327 *----------------------------------------------------------------------- 328 * Targ_FindList -- 329 * Make a complete list of GNodes from the given list of names 330 * 331 * Input: 332 * name list of names to find 333 * flags flags used if no node is found for a given name 334 * 335 * Results: 336 * A complete list of graph nodes corresponding to all instances of all 337 * the names in names. 338 * 339 * Side Effects: 340 * If flags is TARG_CREATE, nodes will be created for all names in 341 * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 342 * an error message will be printed for each name which can't be found. 343 * ----------------------------------------------------------------------- 344 */ 345 Lst 346 Targ_FindList(Lst names, int flags) 347 { 348 Lst nodes; /* result list */ 349 LstNode ln; /* name list element */ 350 GNode *gn; /* node in tLn */ 351 char *name; 352 353 nodes = Lst_Init (FALSE); 354 355 if (Lst_Open (names) == FAILURE) { 356 return (nodes); 357 } 358 while ((ln = Lst_Next (names)) != NILLNODE) { 359 name = (char *)Lst_Datum(ln); 360 gn = Targ_FindNode (name, flags); 361 if (gn != NILGNODE) { 362 /* 363 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes 364 * are added to the list in the order in which they were 365 * encountered in the makefile. 366 */ 367 (void) Lst_AtEnd (nodes, (ClientData)gn); 368 } else if (flags == TARG_NOCREATE) { 369 Error ("\"%s\" -- target unknown.", name); 370 } 371 } 372 Lst_Close (names); 373 return (nodes); 374 } 375 376 /*- 377 *----------------------------------------------------------------------- 378 * Targ_Ignore -- 379 * Return true if should ignore errors when creating gn 380 * 381 * Input: 382 * gn node to check for 383 * 384 * Results: 385 * TRUE if should ignore errors 386 * 387 * Side Effects: 388 * None 389 *----------------------------------------------------------------------- 390 */ 391 Boolean 392 Targ_Ignore(GNode *gn) 393 { 394 if (ignoreErrors || gn->type & OP_IGNORE) { 395 return (TRUE); 396 } else { 397 return (FALSE); 398 } 399 } 400 401 /*- 402 *----------------------------------------------------------------------- 403 * Targ_Silent -- 404 * Return true if be silent when creating gn 405 * 406 * Input: 407 * gn node to check for 408 * 409 * Results: 410 * TRUE if should be silent 411 * 412 * Side Effects: 413 * None 414 *----------------------------------------------------------------------- 415 */ 416 Boolean 417 Targ_Silent(GNode *gn) 418 { 419 if (beSilent || gn->type & OP_SILENT) { 420 return (TRUE); 421 } else { 422 return (FALSE); 423 } 424 } 425 426 /*- 427 *----------------------------------------------------------------------- 428 * Targ_Precious -- 429 * See if the given target is precious 430 * 431 * Input: 432 * gn the node to check 433 * 434 * Results: 435 * TRUE if it is precious. FALSE otherwise 436 * 437 * Side Effects: 438 * None 439 *----------------------------------------------------------------------- 440 */ 441 Boolean 442 Targ_Precious(GNode *gn) 443 { 444 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 445 return (TRUE); 446 } else { 447 return (FALSE); 448 } 449 } 450 451 /******************* DEBUG INFO PRINTING ****************/ 452 453 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 454 /*- 455 *----------------------------------------------------------------------- 456 * Targ_SetMain -- 457 * Set our idea of the main target we'll be creating. Used for 458 * debugging output. 459 * 460 * Input: 461 * gn The main target we'll create 462 * 463 * Results: 464 * None. 465 * 466 * Side Effects: 467 * "mainTarg" is set to the main target's node. 468 *----------------------------------------------------------------------- 469 */ 470 void 471 Targ_SetMain(GNode *gn) 472 { 473 mainTarg = gn; 474 } 475 476 static int 477 TargPrintName(ClientData gnp, ClientData ppath) 478 { 479 GNode *gn = (GNode *) gnp; 480 printf ("%s ", gn->name); 481 #ifdef notdef 482 if (ppath) { 483 if (gn->path) { 484 printf ("[%s] ", gn->path); 485 } 486 if (gn == mainTarg) { 487 printf ("(MAIN NAME) "); 488 } 489 } 490 #endif /* notdef */ 491 return (ppath ? 0 : 0); 492 } 493 494 495 int 496 Targ_PrintCmd(ClientData cmd, ClientData dummy) 497 { 498 printf ("\t%s\n", (char *) cmd); 499 return (dummy ? 0 : 0); 500 } 501 502 /*- 503 *----------------------------------------------------------------------- 504 * Targ_FmtTime -- 505 * Format a modification time in some reasonable way and return it. 506 * 507 * Results: 508 * The time reformatted. 509 * 510 * Side Effects: 511 * The time is placed in a static area, so it is overwritten 512 * with each call. 513 * 514 *----------------------------------------------------------------------- 515 */ 516 char * 517 Targ_FmtTime(time_t tm) 518 { 519 struct tm *parts; 520 static char buf[128]; 521 522 parts = localtime(&tm); 523 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 524 return(buf); 525 } 526 527 /*- 528 *----------------------------------------------------------------------- 529 * Targ_PrintType -- 530 * Print out a type field giving only those attributes the user can 531 * set. 532 * 533 * Results: 534 * 535 * Side Effects: 536 * 537 *----------------------------------------------------------------------- 538 */ 539 void 540 Targ_PrintType(int type) 541 { 542 int tbit; 543 544 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 545 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 546 547 type &= ~OP_OPMASK; 548 549 while (type) { 550 tbit = 1 << (ffs(type) - 1); 551 type &= ~tbit; 552 553 switch(tbit) { 554 PRINTBIT(OPTIONAL); 555 PRINTBIT(USE); 556 PRINTBIT(EXEC); 557 PRINTBIT(IGNORE); 558 PRINTBIT(PRECIOUS); 559 PRINTBIT(SILENT); 560 PRINTBIT(MAKE); 561 PRINTBIT(JOIN); 562 PRINTBIT(INVISIBLE); 563 PRINTBIT(NOTMAIN); 564 PRINTDBIT(LIB); 565 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 566 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break; 567 PRINTDBIT(ARCHV); 568 PRINTDBIT(MADE); 569 PRINTDBIT(PHONY); 570 } 571 } 572 } 573 574 /*- 575 *----------------------------------------------------------------------- 576 * TargPrintNode -- 577 * print the contents of a node 578 *----------------------------------------------------------------------- 579 */ 580 static int 581 TargPrintNode(ClientData gnp, ClientData passp) 582 { 583 GNode *gn = (GNode *) gnp; 584 int pass = *(int *) passp; 585 if (!OP_NOP(gn->type)) { 586 printf("#\n"); 587 if (gn == mainTarg) { 588 printf("# *** MAIN TARGET ***\n"); 589 } 590 if (pass == 2) { 591 if (gn->unmade) { 592 printf("# %d unmade children\n", gn->unmade); 593 } else { 594 printf("# No unmade children\n"); 595 } 596 if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) { 597 if (gn->mtime != 0) { 598 printf("# last modified %s: %s\n", 599 Targ_FmtTime(gn->mtime), 600 (gn->made == UNMADE ? "unmade" : 601 (gn->made == MADE ? "made" : 602 (gn->made == UPTODATE ? "up-to-date" : 603 "error when made")))); 604 } else if (gn->made != UNMADE) { 605 printf("# non-existent (maybe): %s\n", 606 (gn->made == MADE ? "made" : 607 (gn->made == UPTODATE ? "up-to-date" : 608 (gn->made == ERROR ? "error when made" : 609 "aborted")))); 610 } else { 611 printf("# unmade\n"); 612 } 613 } 614 if (!Lst_IsEmpty (gn->iParents)) { 615 printf("# implicit parents: "); 616 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0); 617 fputc ('\n', stdout); 618 } 619 } 620 if (!Lst_IsEmpty (gn->parents)) { 621 printf("# parents: "); 622 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0); 623 fputc ('\n', stdout); 624 } 625 626 printf("%-16s", gn->name); 627 switch (gn->type & OP_OPMASK) { 628 case OP_DEPENDS: 629 printf(": "); break; 630 case OP_FORCE: 631 printf("! "); break; 632 case OP_DOUBLEDEP: 633 printf(":: "); break; 634 } 635 Targ_PrintType (gn->type); 636 Lst_ForEach (gn->children, TargPrintName, (ClientData)0); 637 fputc ('\n', stdout); 638 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0); 639 printf("\n\n"); 640 if (gn->type & OP_DOUBLEDEP) { 641 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass); 642 } 643 } 644 return (0); 645 } 646 647 /*- 648 *----------------------------------------------------------------------- 649 * TargPrintOnlySrc -- 650 * Print only those targets that are just a source. 651 * 652 * Results: 653 * 0. 654 * 655 * Side Effects: 656 * The name of each file is printed preceded by #\t 657 * 658 *----------------------------------------------------------------------- 659 */ 660 static int 661 TargPrintOnlySrc(ClientData gnp, ClientData dummy) 662 { 663 GNode *gn = (GNode *) gnp; 664 if (OP_NOP(gn->type)) 665 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 666 667 return (dummy ? 0 : 0); 668 } 669 670 /*- 671 *----------------------------------------------------------------------- 672 * Targ_PrintGraph -- 673 * print the entire graph. heh heh 674 * 675 * Input: 676 * pass Which pass this is. 1 => no processing 677 * 2 => processing done 678 * 679 * Results: 680 * none 681 * 682 * Side Effects: 683 * lots o' output 684 *----------------------------------------------------------------------- 685 */ 686 void 687 Targ_PrintGraph(int pass) 688 { 689 printf("#*** Input graph:\n"); 690 Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass); 691 printf("\n\n"); 692 printf("#\n# Files that are only sources:\n"); 693 Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0); 694 printf("#*** Global Variables:\n"); 695 Var_Dump (VAR_GLOBAL); 696 printf("#*** Command-line Variables:\n"); 697 Var_Dump (VAR_CMD); 698 printf("\n"); 699 Dir_PrintDirectories(); 700 printf("\n"); 701 Suff_PrintAll(); 702 } 703 704 static int 705 TargPropagateCohort(ClientData cgnp, ClientData pgnp) 706 { 707 GNode *cgn = (GNode *) cgnp; 708 GNode *pgn = (GNode *) pgnp; 709 710 cgn->type |= pgn->type & ~OP_OPMASK; 711 return (0); 712 } 713 714 static int 715 TargPropagateNode(ClientData gnp, ClientData junk) 716 { 717 GNode *gn = (GNode *) gnp; 718 if (gn->type & OP_DOUBLEDEP) 719 Lst_ForEach (gn->cohorts, TargPropagateCohort, gnp); 720 return (0); 721 } 722 723 void 724 Targ_Propagate(void) 725 { 726 Lst_ForEach (allTargets, TargPropagateNode, (ClientData)0); 727 } 728