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