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