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