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