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