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 * 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 * @(#)targ.c 8.2 (Berkeley) 3/19/94 39 */ 40 41#include <sys/cdefs.h>
|
42__FBSDID("$FreeBSD: head/usr.bin/make/targ.c 103508 2002-09-17 22:31:26Z jmallett $");
|
42__FBSDID("$FreeBSD: head/usr.bin/make/targ.c 103545 2002-09-18 16:13:03Z jmallett $"); |
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 91static Lst allTargets; /* the list of all targets found so far */ 92static Lst allGNs; /* List of all the GNodes */ 93static Hash_Table targets; /* a hash table of same */ 94 95#define HTSIZE 191 /* initial size of hash table */ 96 97static int TargPrintOnlySrc(void *, void *); 98static int TargPrintName(void *, void *); 99static int TargPrintNode(void *, void *); 100static void TargFreeGN(void *); 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 */ 114void 115Targ_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 */ 133void 134Targ_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 */ 155GNode * 156Targ_NewGN (name) 157 char *name; /* the name to stick in the new node */ 158{ 159 GNode *gn; 160 161 gn = (GNode *) emalloc (sizeof (GNode)); 162 gn->name = estrdup (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->order = 0; 174 gn->mtime = gn->cmtime = 0; 175 gn->iParents = Lst_Init (FALSE); 176 gn->cohorts = Lst_Init (FALSE); 177 gn->parents = Lst_Init (FALSE); 178 gn->children = Lst_Init (FALSE); 179 gn->successors = Lst_Init (FALSE); 180 gn->preds = Lst_Init (FALSE); 181 gn->context = Lst_Init (FALSE); 182 gn->commands = Lst_Init (FALSE); 183 gn->suffix = NULL; 184 185 if (allGNs == NULL) 186 allGNs = Lst_Init(FALSE); 187 Lst_AtEnd(allGNs, (void *) gn); 188 189 return (gn); 190} 191 192/*- 193 *----------------------------------------------------------------------- 194 * TargFreeGN -- 195 * Destroy a GNode 196 * 197 * Results: 198 * None. 199 * 200 * Side Effects: 201 * None. 202 *----------------------------------------------------------------------- 203 */ 204static void 205TargFreeGN (gnp) 206 void * gnp; 207{ 208 GNode *gn = (GNode *) gnp; 209 210 211 free(gn->name); 212 efree(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(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 NULL 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 */ 240GNode * 241Targ_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, (void *)gn); 258 } 259 } else { 260 he = Hash_FindEntry (&targets, name); 261 } 262 263 if (he == (Hash_Entry *) NULL) { 264 return (NULL); 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 */ 285Lst 286Targ_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 LstNode ln; /* name list element */ 293 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)) != NULL) { 302 name = (char *)Lst_Datum(ln); 303 gn = Targ_FindNode (name, flags); 304 if (gn != NULL) { 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, (void *)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 */ 334Boolean 335Targ_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 */ 357Boolean 358Targ_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 */ 380Boolean 381Targ_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 393static 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 */ 407void 408Targ_SetMain (gn) 409 GNode *gn; /* The main target we'll create */ 410{ 411 mainTarg = gn; 412} 413 414static int 415TargPrintName (gnp, ppath) 416 void * gnp; 417 void * 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 435int 436Targ_PrintCmd (cmd, dummy) 437 void * cmd; 438 void * 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 */ 458char * 459Targ_FmtTime (time) 460 time_t time; 461{ 462 struct tm *parts; 463 static char buf[128]; 464 465 parts = localtime(&time); 466 467 strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts); 468 buf[sizeof(buf) - 1] = '\0'; 469 return(buf); 470} 471 472/*- 473 *----------------------------------------------------------------------- 474 * Targ_PrintType -- 475 * Print out a type field giving only those attributes the user can 476 * set. 477 * 478 * Results: 479 * 480 * Side Effects: 481 * 482 *----------------------------------------------------------------------- 483 */ 484void 485Targ_PrintType (type) 486 int type; 487{ 488 int tbit; 489 490#define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
|
491#define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, "." #attr " "); break
|
491#define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break |
492 493 type &= ~OP_OPMASK; 494 495 while (type) { 496 tbit = 1 << (ffs(type) - 1); 497 type &= ~tbit; 498 499 switch(tbit) { 500 PRINTBIT(OPTIONAL); 501 PRINTBIT(USE); 502 PRINTBIT(EXEC); 503 PRINTBIT(IGNORE); 504 PRINTBIT(PRECIOUS); 505 PRINTBIT(SILENT); 506 PRINTBIT(MAKE); 507 PRINTBIT(JOIN); 508 PRINTBIT(INVISIBLE); 509 PRINTBIT(NOTMAIN); 510 PRINTDBIT(LIB); 511 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
|
512 case OP_MEMBER: DEBUGF(TARG, ".MEMBER "); break;
|
512 case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break; |
513 PRINTDBIT(ARCHV); 514 } 515 } 516} 517 518/*- 519 *----------------------------------------------------------------------- 520 * TargPrintNode -- 521 * print the contents of a node 522 *----------------------------------------------------------------------- 523 */ 524static int 525TargPrintNode (gnp, passp) 526 void * gnp; 527 void * passp; 528{ 529 GNode *gn = (GNode *) gnp; 530 int pass = *(int *) passp; 531 if (!OP_NOP(gn->type)) { 532 printf("#\n"); 533 if (gn == mainTarg) { 534 printf("# *** MAIN TARGET ***\n"); 535 } 536 if (pass == 2) { 537 if (gn->unmade) { 538 printf("# %d unmade children\n", gn->unmade); 539 } else { 540 printf("# No unmade children\n"); 541 } 542 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 543 if (gn->mtime != 0) { 544 printf("# last modified %s: %s\n", 545 Targ_FmtTime(gn->mtime), 546 (gn->made == UNMADE ? "unmade" : 547 (gn->made == MADE ? "made" : 548 (gn->made == UPTODATE ? "up-to-date" : 549 "error when made")))); 550 } else if (gn->made != UNMADE) { 551 printf("# non-existent (maybe): %s\n", 552 (gn->made == MADE ? "made" : 553 (gn->made == UPTODATE ? "up-to-date" : 554 (gn->made == ERROR ? "error when made" : 555 "aborted")))); 556 } else { 557 printf("# unmade\n"); 558 } 559 } 560 if (!Lst_IsEmpty (gn->iParents)) { 561 printf("# implicit parents: "); 562 Lst_ForEach (gn->iParents, TargPrintName, (void *)0); 563 fputc ('\n', stdout); 564 } 565 } 566 if (!Lst_IsEmpty (gn->parents)) { 567 printf("# parents: "); 568 Lst_ForEach (gn->parents, TargPrintName, (void *)0); 569 fputc ('\n', stdout); 570 } 571 572 printf("%-16s", gn->name); 573 switch (gn->type & OP_OPMASK) { 574 case OP_DEPENDS: 575 printf(": "); break; 576 case OP_FORCE: 577 printf("! "); break; 578 case OP_DOUBLEDEP: 579 printf(":: "); break; 580 } 581 Targ_PrintType (gn->type); 582 Lst_ForEach (gn->children, TargPrintName, (void *)0); 583 fputc ('\n', stdout); 584 Lst_ForEach (gn->commands, Targ_PrintCmd, (void *)0); 585 printf("\n\n"); 586 if (gn->type & OP_DOUBLEDEP) { 587 Lst_ForEach (gn->cohorts, TargPrintNode, (void *)&pass); 588 } 589 } 590 return (0); 591} 592 593/*- 594 *----------------------------------------------------------------------- 595 * TargPrintOnlySrc -- 596 * Print only those targets that are just a source. 597 * 598 * Results: 599 * 0. 600 * 601 * Side Effects: 602 * The name of each file is printed preceded by #\t 603 * 604 *----------------------------------------------------------------------- 605 */ 606static int 607TargPrintOnlySrc(gnp, dummy) 608 void * gnp; 609 void * dummy; 610{ 611 GNode *gn = (GNode *) gnp; 612 if (OP_NOP(gn->type)) 613 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 614 615 return (dummy ? 0 : 0); 616} 617 618/*- 619 *----------------------------------------------------------------------- 620 * Targ_PrintGraph -- 621 * print the entire graph. heh heh 622 * 623 * Results: 624 * none 625 * 626 * Side Effects: 627 * lots o' output 628 *----------------------------------------------------------------------- 629 */ 630void 631Targ_PrintGraph (pass) 632 int pass; /* Which pass this is. 1 => no processing 633 * 2 => processing done */ 634{ 635 printf("#*** Input graph:\n"); 636 Lst_ForEach (allTargets, TargPrintNode, (void *)&pass); 637 printf("\n\n"); 638 printf("#\n# Files that are only sources:\n"); 639 Lst_ForEach (allTargets, TargPrintOnlySrc, (void *) 0); 640 printf("#*** Global Variables:\n"); 641 Var_Dump (VAR_GLOBAL); 642 printf("#*** Command-line Variables:\n"); 643 Var_Dump (VAR_CMD); 644 printf("\n"); 645 Dir_PrintDirectories(); 646 printf("\n"); 647 Suff_PrintAll(); 648}
|