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