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