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