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