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