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