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