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