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