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