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