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