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