1 /* $NetBSD: targ.c,v 1.22 2001/07/03 18:08:51 christos 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.22 2001/07/03 18:08:51 christos 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.22 2001/07/03 18:08:51 christos 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 (void) Lst_AtEnd (allTargets, (ClientData)gn); 307 } 308 } else { 309 he = Hash_FindEntry (&targets, name); 310 } 311 312 if (he == (Hash_Entry *) NULL) { 313 return (NILGNODE); 314 } else { 315 return ((GNode *) Hash_GetValue (he)); 316 } 317 } 318 319 /*- 320 *----------------------------------------------------------------------- 321 * Targ_FindList -- 322 * Make a complete list of GNodes from the given list of names 323 * 324 * Results: 325 * A complete list of graph nodes corresponding to all instances of all 326 * the names in names. 327 * 328 * Side Effects: 329 * If flags is TARG_CREATE, nodes will be created for all names in 330 * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 331 * an error message will be printed for each name which can't be found. 332 * ----------------------------------------------------------------------- 333 */ 334 Lst 335 Targ_FindList (names, flags) 336 Lst names; /* list of names to find */ 337 int flags; /* flags used if no node is found for a given 338 * name */ 339 { 340 Lst nodes; /* result list */ 341 register LstNode ln; /* name list element */ 342 register GNode *gn; /* node in tLn */ 343 char *name; 344 345 nodes = Lst_Init (FALSE); 346 347 if (Lst_Open (names) == FAILURE) { 348 return (nodes); 349 } 350 while ((ln = Lst_Next (names)) != NILLNODE) { 351 name = (char *)Lst_Datum(ln); 352 gn = Targ_FindNode (name, flags); 353 if (gn != NILGNODE) { 354 /* 355 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes 356 * are added to the list in the order in which they were 357 * encountered in the makefile. 358 */ 359 (void) Lst_AtEnd (nodes, (ClientData)gn); 360 } else if (flags == TARG_NOCREATE) { 361 Error ("\"%s\" -- target unknown.", name); 362 } 363 } 364 Lst_Close (names); 365 return (nodes); 366 } 367 368 /*- 369 *----------------------------------------------------------------------- 370 * Targ_Ignore -- 371 * Return true if should ignore errors when creating gn 372 * 373 * Results: 374 * TRUE if should ignore errors 375 * 376 * Side Effects: 377 * None 378 *----------------------------------------------------------------------- 379 */ 380 Boolean 381 Targ_Ignore (gn) 382 GNode *gn; /* node to check for */ 383 { 384 if (ignoreErrors || gn->type & OP_IGNORE) { 385 return (TRUE); 386 } else { 387 return (FALSE); 388 } 389 } 390 391 /*- 392 *----------------------------------------------------------------------- 393 * Targ_Silent -- 394 * Return true if be silent when creating gn 395 * 396 * Results: 397 * TRUE if should be silent 398 * 399 * Side Effects: 400 * None 401 *----------------------------------------------------------------------- 402 */ 403 Boolean 404 Targ_Silent (gn) 405 GNode *gn; /* node to check for */ 406 { 407 if (beSilent || gn->type & OP_SILENT) { 408 return (TRUE); 409 } else { 410 return (FALSE); 411 } 412 } 413 414 /*- 415 *----------------------------------------------------------------------- 416 * Targ_Precious -- 417 * See if the given target is precious 418 * 419 * Results: 420 * TRUE if it is precious. FALSE otherwise 421 * 422 * Side Effects: 423 * None 424 *----------------------------------------------------------------------- 425 */ 426 Boolean 427 Targ_Precious (gn) 428 GNode *gn; /* the node to check */ 429 { 430 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 431 return (TRUE); 432 } else { 433 return (FALSE); 434 } 435 } 436 437 /******************* DEBUG INFO PRINTING ****************/ 438 439 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 440 /*- 441 *----------------------------------------------------------------------- 442 * Targ_SetMain -- 443 * Set our idea of the main target we'll be creating. Used for 444 * debugging output. 445 * 446 * Results: 447 * None. 448 * 449 * Side Effects: 450 * "mainTarg" is set to the main target's node. 451 *----------------------------------------------------------------------- 452 */ 453 void 454 Targ_SetMain (gn) 455 GNode *gn; /* The main target we'll create */ 456 { 457 mainTarg = gn; 458 } 459 460 static int 461 TargPrintName (gnp, ppath) 462 ClientData gnp; 463 ClientData ppath; 464 { 465 GNode *gn = (GNode *) gnp; 466 printf ("%s ", gn->name); 467 #ifdef notdef 468 if (ppath) { 469 if (gn->path) { 470 printf ("[%s] ", gn->path); 471 } 472 if (gn == mainTarg) { 473 printf ("(MAIN NAME) "); 474 } 475 } 476 #endif /* notdef */ 477 return (ppath ? 0 : 0); 478 } 479 480 481 int 482 Targ_PrintCmd (cmd, dummy) 483 ClientData cmd; 484 ClientData dummy; 485 { 486 printf ("\t%s\n", (char *) cmd); 487 return (dummy ? 0 : 0); 488 } 489 490 /*- 491 *----------------------------------------------------------------------- 492 * Targ_FmtTime -- 493 * Format a modification time in some reasonable way and return it. 494 * 495 * Results: 496 * The time reformatted. 497 * 498 * Side Effects: 499 * The time is placed in a static area, so it is overwritten 500 * with each call. 501 * 502 *----------------------------------------------------------------------- 503 */ 504 char * 505 Targ_FmtTime (time) 506 time_t time; 507 { 508 struct tm *parts; 509 static char buf[128]; 510 511 parts = localtime(&time); 512 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 513 return(buf); 514 } 515 516 /*- 517 *----------------------------------------------------------------------- 518 * Targ_PrintType -- 519 * Print out a type field giving only those attributes the user can 520 * set. 521 * 522 * Results: 523 * 524 * Side Effects: 525 * 526 *----------------------------------------------------------------------- 527 */ 528 void 529 Targ_PrintType (type) 530 register int type; 531 { 532 register int tbit; 533 534 #ifdef __STDC__ 535 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 536 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 537 #else 538 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break 539 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break 540 #endif /* __STDC__ */ 541 542 type &= ~OP_OPMASK; 543 544 while (type) { 545 tbit = 1 << (ffs(type) - 1); 546 type &= ~tbit; 547 548 switch(tbit) { 549 PRINTBIT(OPTIONAL); 550 PRINTBIT(USE); 551 PRINTBIT(EXEC); 552 PRINTBIT(IGNORE); 553 PRINTBIT(PRECIOUS); 554 PRINTBIT(SILENT); 555 PRINTBIT(MAKE); 556 PRINTBIT(JOIN); 557 PRINTBIT(INVISIBLE); 558 PRINTBIT(NOTMAIN); 559 PRINTDBIT(LIB); 560 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 561 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break; 562 PRINTDBIT(ARCHV); 563 } 564 } 565 } 566 567 /*- 568 *----------------------------------------------------------------------- 569 * TargPrintNode -- 570 * print the contents of a node 571 *----------------------------------------------------------------------- 572 */ 573 static int 574 TargPrintNode (gnp, passp) 575 ClientData gnp; 576 ClientData passp; 577 { 578 GNode *gn = (GNode *) gnp; 579 int pass = *(int *) passp; 580 if (!OP_NOP(gn->type)) { 581 printf("#\n"); 582 if (gn == mainTarg) { 583 printf("# *** MAIN TARGET ***\n"); 584 } 585 if (pass == 2) { 586 if (gn->unmade) { 587 printf("# %d unmade children\n", gn->unmade); 588 } else { 589 printf("# No unmade children\n"); 590 } 591 if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) { 592 if (gn->mtime != 0) { 593 printf("# last modified %s: %s\n", 594 Targ_FmtTime(gn->mtime), 595 (gn->made == UNMADE ? "unmade" : 596 (gn->made == MADE ? "made" : 597 (gn->made == UPTODATE ? "up-to-date" : 598 "error when made")))); 599 } else if (gn->made != UNMADE) { 600 printf("# non-existent (maybe): %s\n", 601 (gn->made == MADE ? "made" : 602 (gn->made == UPTODATE ? "up-to-date" : 603 (gn->made == ERROR ? "error when made" : 604 "aborted")))); 605 } else { 606 printf("# unmade\n"); 607 } 608 } 609 if (!Lst_IsEmpty (gn->iParents)) { 610 printf("# implicit parents: "); 611 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0); 612 fputc ('\n', stdout); 613 } 614 } 615 if (!Lst_IsEmpty (gn->parents)) { 616 printf("# parents: "); 617 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0); 618 fputc ('\n', stdout); 619 } 620 621 printf("%-16s", gn->name); 622 switch (gn->type & OP_OPMASK) { 623 case OP_DEPENDS: 624 printf(": "); break; 625 case OP_FORCE: 626 printf("! "); break; 627 case OP_DOUBLEDEP: 628 printf(":: "); break; 629 } 630 Targ_PrintType (gn->type); 631 Lst_ForEach (gn->children, TargPrintName, (ClientData)0); 632 fputc ('\n', stdout); 633 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0); 634 printf("\n\n"); 635 if (gn->type & OP_DOUBLEDEP) { 636 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass); 637 } 638 } 639 return (0); 640 } 641 642 /*- 643 *----------------------------------------------------------------------- 644 * TargPrintOnlySrc -- 645 * Print only those targets that are just a source. 646 * 647 * Results: 648 * 0. 649 * 650 * Side Effects: 651 * The name of each file is printed preceeded by #\t 652 * 653 *----------------------------------------------------------------------- 654 */ 655 static int 656 TargPrintOnlySrc(gnp, dummy) 657 ClientData gnp; 658 ClientData dummy; 659 { 660 GNode *gn = (GNode *) gnp; 661 if (OP_NOP(gn->type)) 662 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 663 664 return (dummy ? 0 : 0); 665 } 666 667 /*- 668 *----------------------------------------------------------------------- 669 * Targ_PrintGraph -- 670 * print the entire graph. heh heh 671 * 672 * Results: 673 * none 674 * 675 * Side Effects: 676 * lots o' output 677 *----------------------------------------------------------------------- 678 */ 679 void 680 Targ_PrintGraph (pass) 681 int pass; /* Which pass this is. 1 => no processing 682 * 2 => processing done */ 683 { 684 printf("#*** Input graph:\n"); 685 Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass); 686 printf("\n\n"); 687 printf("#\n# Files that are only sources:\n"); 688 Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0); 689 printf("#*** Global Variables:\n"); 690 Var_Dump (VAR_GLOBAL); 691 printf("#*** Command-line Variables:\n"); 692 Var_Dump (VAR_CMD); 693 printf("\n"); 694 Dir_PrintDirectories(); 695 printf("\n"); 696 Suff_PrintAll(); 697 } 698 699 static int 700 TargPropagateCohort (cgnp, pgnp) 701 ClientData cgnp; 702 ClientData pgnp; 703 { 704 GNode *cgn = (GNode *) cgnp; 705 GNode *pgn = (GNode *) pgnp; 706 707 cgn->type |= pgn->type & ~OP_OPMASK; 708 return (0); 709 } 710 711 static int 712 TargPropagateNode (gnp, junk) 713 ClientData gnp; 714 ClientData junk; 715 { 716 GNode *gn = (GNode *) gnp; 717 if (gn->type & OP_DOUBLEDEP) 718 Lst_ForEach (gn->cohorts, TargPropagateCohort, gnp); 719 return (0); 720 } 721 722 void 723 Targ_Propagate () 724 { 725 Lst_ForEach (allTargets, TargPropagateNode, (ClientData)0); 726 } 727