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