1 /* $OpenPackages$ */ 2 /* $OpenBSD: targ.c,v 1.38 2003/06/03 02:56:12 millert Exp $ */ 3 /* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */ 4 5 /* 6 * Copyright (c) 1999 Marc Espie. 7 * 8 * Extensive code changes for the OpenBSD project. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 23 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * Copyright (c) 1988, 1989, 1990, 1993 33 * The Regents of the University of California. All rights reserved. 34 * Copyright (c) 1989 by Berkeley Softworks 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to Berkeley by 38 * Adam de Boor. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /*- 66 * targ.c -- 67 * Target nodes are kept into a hash table. 68 * 69 * Interface: 70 * Targ_Init Initialization procedure. 71 * 72 * Targ_End Cleanup the module 73 * 74 * Targ_NewGN Create a new GNode for the passed target 75 * (string). The node is *not* placed in the 76 * hash table, though all its fields are 77 * initialized. 78 * 79 * Targ_FindNode Find the node for a given target, creating 80 * and storing it if it doesn't exist and the 81 * flags are right (TARG_CREATE) 82 * 83 * Targ_FindList Given a list of names, find nodes for all 84 * of them, creating nodes if needed. 85 * 86 * Targ_Ignore Return true if errors should be ignored when 87 * creating the given target. 88 * 89 * Targ_Silent Return true if we should be silent when 90 * creating the given target. 91 * 92 * Targ_Precious Return true if the target is precious and 93 * should not be removed if we are interrupted. 94 * 95 * Debugging: 96 * Targ_PrintGraph Print out the entire graphm all variables 97 * and statistics for the directory cache. Should 98 * print something for suffixes, too, but... 99 */ 100 101 #include <sys/types.h> 102 #include <limits.h> 103 #include <stddef.h> 104 #include <stdio.h> 105 #include <string.h> 106 #include "config.h" 107 #include "defines.h" 108 #include "ohash.h" 109 #include "stats.h" 110 #include "suff.h" 111 #include "var.h" 112 #include "targ.h" 113 #include "memory.h" 114 #include "gnode.h" 115 #include "extern.h" 116 #include "timestamp.h" 117 #include "lst.h" 118 #ifdef CLEANUP 119 #include <stdlib.h> 120 #endif 121 122 static struct ohash targets; /* a hash table of same */ 123 static struct ohash_info gnode_info = { 124 offsetof(GNode, name), 125 NULL, hash_alloc, hash_free, element_alloc }; 126 127 static void TargPrintOnlySrc(GNode *); 128 static void TargPrintName(void *); 129 static void TargPrintNode(GNode *, int); 130 #ifdef CLEANUP 131 static LIST allTargets; 132 static void TargFreeGN(void *); 133 #endif 134 135 /*- 136 *----------------------------------------------------------------------- 137 * Targ_Init -- 138 * Initialize this module 139 * 140 * Side Effects: 141 * The targets hash table is initialized 142 *----------------------------------------------------------------------- 143 */ 144 void 145 Targ_Init() 146 { 147 /* A small make file already creates 200 targets. */ 148 ohash_init(&targets, 10, &gnode_info); 149 #ifdef CLEANUP 150 Lst_Init(&allTargets); 151 #endif 152 } 153 154 /*- 155 *----------------------------------------------------------------------- 156 * Targ_End -- 157 * Finalize this module 158 * 159 * Side Effects: 160 * All lists and gnodes are cleared 161 *----------------------------------------------------------------------- 162 */ 163 #ifdef CLEANUP 164 void 165 Targ_End() 166 { 167 Lst_Every(&allTargets, TargFreeGN); 168 ohash_delete(&targets); 169 } 170 #endif 171 172 /*- 173 *----------------------------------------------------------------------- 174 * Targ_NewGNi -- 175 * Create and initialize a new graph node 176 * 177 * Results: 178 * An initialized graph node with the name field filled with a copy 179 * of the passed name 180 * 181 * Side effect: 182 * add targets to list of all targets if CLEANUP 183 *----------------------------------------------------------------------- 184 */ 185 GNode * 186 Targ_NewGNi(name, end) 187 const char *name; /* the name to stick in the new node */ 188 const char *end; 189 { 190 GNode *gn; 191 192 gn = ohash_create_entry(&gnode_info, name, &end); 193 gn->path = NULL; 194 if (name[0] == '-' && name[1] == 'l') { 195 gn->type = OP_LIB; 196 } else { 197 gn->type = 0; 198 } 199 gn->unmade = 0; 200 gn->make = false; 201 gn->made = UNMADE; 202 gn->childMade = false; 203 gn->order = 0; 204 ts_set_out_of_date(gn->mtime); 205 ts_set_out_of_date(gn->cmtime); 206 Lst_Init(&gn->iParents); 207 Lst_Init(&gn->cohorts); 208 Lst_Init(&gn->parents); 209 Lst_Init(&gn->children); 210 Lst_Init(&gn->successors); 211 Lst_Init(&gn->preds); 212 SymTable_Init(&gn->context); 213 gn->lineno = 0; 214 gn->fname = NULL; 215 Lst_Init(&gn->commands); 216 gn->suffix = NULL; 217 218 #ifdef STATS_GN_CREATION 219 STAT_GN_COUNT++; 220 #endif 221 222 #ifdef CLEANUP 223 Lst_AtEnd(&allTargets, gn); 224 #endif 225 return gn; 226 } 227 228 #ifdef CLEANUP 229 /*- 230 *----------------------------------------------------------------------- 231 * TargFreeGN -- 232 * Destroy a GNode 233 *----------------------------------------------------------------------- 234 */ 235 static void 236 TargFreeGN(gnp) 237 void *gnp; 238 { 239 GNode *gn = (GNode *)gnp; 240 241 efree(gn->path); 242 Lst_Destroy(&gn->iParents, NOFREE); 243 Lst_Destroy(&gn->cohorts, NOFREE); 244 Lst_Destroy(&gn->parents, NOFREE); 245 Lst_Destroy(&gn->children, NOFREE); 246 Lst_Destroy(&gn->successors, NOFREE); 247 Lst_Destroy(&gn->preds, NOFREE); 248 Lst_Destroy(&gn->commands, NOFREE); 249 SymTable_Destroy(&gn->context); 250 free(gn); 251 } 252 #endif 253 254 255 /*- 256 *----------------------------------------------------------------------- 257 * Targ_FindNodei -- 258 * Find a node in the list using the given name for matching 259 * 260 * Results: 261 * The node in the list if it was. If it wasn't, return NULL if 262 * flags was TARG_NOCREATE or the newly created and initialized node 263 * if flags was TARG_CREATE 264 * 265 * Side Effects: 266 * Sometimes a node is created and added to the list 267 *----------------------------------------------------------------------- 268 */ 269 GNode * 270 Targ_FindNodei(name, end, flags) 271 const char *name; /* the name to find */ 272 const char *end; 273 int flags; /* flags governing events when target not 274 * found */ 275 { 276 GNode *gn; /* node in that element */ 277 unsigned int slot; 278 279 slot = ohash_qlookupi(&targets, name, &end); 280 281 gn = ohash_find(&targets, slot); 282 283 if (gn == NULL && (flags & TARG_CREATE)) { 284 gn = Targ_NewGNi(name, end); 285 ohash_insert(&targets, slot, gn); 286 } 287 288 return gn; 289 } 290 291 /*- 292 *----------------------------------------------------------------------- 293 * Targ_FindList -- 294 * Make a complete list of GNodes from the given list of names 295 * 296 * Side Effects: 297 * Nodes will be created for all names in names which do not yet have graph 298 * nodes. 299 * 300 * A complete list of graph nodes corresponding to all instances of all 301 * the names in names is added to nodes. 302 * ----------------------------------------------------------------------- 303 */ 304 void 305 Targ_FindList(nodes, names) 306 Lst nodes; /* result list */ 307 Lst names; /* list of names to find */ 308 { 309 LstNode ln; /* name list element */ 310 GNode *gn; /* node in tLn */ 311 char *name; 312 313 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 314 name = (char *)Lst_Datum(ln); 315 gn = Targ_FindNode(name, TARG_CREATE); 316 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 317 * are added to the list in the order in which they were 318 * encountered in the makefile. */ 319 Lst_AtEnd(nodes, gn); 320 if (gn->type & OP_DOUBLEDEP) 321 Lst_Concat(nodes, &gn->cohorts); 322 } 323 } 324 325 /*- 326 *----------------------------------------------------------------------- 327 * Targ_Ignore -- 328 * Return true if should ignore errors when creating gn 329 *----------------------------------------------------------------------- 330 */ 331 bool 332 Targ_Ignore(gn) 333 GNode *gn; /* node to check for */ 334 { 335 if (ignoreErrors || gn->type & OP_IGNORE) 336 return true; 337 else 338 return false; 339 } 340 341 /*- 342 *----------------------------------------------------------------------- 343 * Targ_Silent -- 344 * Return true if be silent when creating gn 345 *----------------------------------------------------------------------- 346 */ 347 bool 348 Targ_Silent(gn) 349 GNode *gn; /* node to check for */ 350 { 351 if (beSilent || gn->type & OP_SILENT) 352 return true; 353 else 354 return false; 355 } 356 357 /*- 358 *----------------------------------------------------------------------- 359 * Targ_Precious -- 360 * See if the given target is precious 361 *----------------------------------------------------------------------- 362 */ 363 bool 364 Targ_Precious(gn) 365 GNode *gn; /* the node to check */ 366 { 367 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) 368 return true; 369 else 370 return false; 371 } 372 373 /******************* DEBUG INFO PRINTING ****************/ 374 375 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 376 /*- 377 *----------------------------------------------------------------------- 378 * Targ_SetMain -- 379 * Set our idea of the main target we'll be creating. Used for 380 * debugging output. 381 * 382 * Side Effects: 383 * "mainTarg" is set to the main target's node. 384 *----------------------------------------------------------------------- 385 */ 386 void 387 Targ_SetMain(gn) 388 GNode *gn; /* The main target we'll create */ 389 { 390 mainTarg = gn; 391 } 392 393 static void 394 TargPrintName(gnp) 395 void *gnp; 396 { 397 GNode *gn = (GNode *)gnp; 398 printf("%s ", gn->name); 399 } 400 401 402 void 403 Targ_PrintCmd(cmd) 404 void *cmd; 405 { 406 printf("\t%s\n", (char *)cmd); 407 } 408 409 /*- 410 *----------------------------------------------------------------------- 411 * Targ_FmtTime -- 412 * Format a modification time in some reasonable way and return it. 413 * 414 * Results: 415 * The time reformatted. 416 * 417 * Side Effects: 418 * The time is placed in a static area, so it is overwritten 419 * with each call. 420 *----------------------------------------------------------------------- 421 */ 422 char * 423 Targ_FmtTime(time) 424 TIMESTAMP time; 425 { 426 struct tm *parts; 427 static char buf[128]; 428 time_t t; 429 430 t = timestamp2time_t(time); 431 432 parts = localtime(&t); 433 strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts); 434 buf[sizeof(buf) - 1] = '\0'; 435 return buf; 436 } 437 438 /*- 439 *----------------------------------------------------------------------- 440 * Targ_PrintType -- 441 * Print out a type field giving only those attributes the user can 442 * set. 443 *----------------------------------------------------------------------- 444 */ 445 void 446 Targ_PrintType(type) 447 int type; 448 { 449 int tbit; 450 451 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 452 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 453 454 type &= ~OP_OPMASK; 455 456 while (type) { 457 tbit = 1 << (ffs(type) - 1); 458 type &= ~tbit; 459 460 switch (tbit) { 461 PRINTBIT(OPTIONAL); 462 PRINTBIT(USE); 463 PRINTBIT(EXEC); 464 PRINTBIT(IGNORE); 465 PRINTBIT(PRECIOUS); 466 PRINTBIT(SILENT); 467 PRINTBIT(MAKE); 468 PRINTBIT(JOIN); 469 PRINTBIT(INVISIBLE); 470 PRINTBIT(NOTMAIN); 471 PRINTDBIT(LIB); 472 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 473 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break; 474 PRINTDBIT(ARCHV); 475 } 476 } 477 } 478 479 /*- 480 *----------------------------------------------------------------------- 481 * TargPrintNode -- 482 * print the contents of a node 483 *----------------------------------------------------------------------- 484 */ 485 static void 486 TargPrintNode(gn, pass) 487 GNode *gn; 488 int pass; 489 { 490 if (!OP_NOP(gn->type)) { 491 printf("#\n"); 492 if (gn == mainTarg) { 493 printf("# *** MAIN TARGET ***\n"); 494 } 495 if (pass == 2) { 496 if (gn->unmade) { 497 printf("# %d unmade children\n", gn->unmade); 498 } else { 499 printf("# No unmade children\n"); 500 } 501 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 502 if (!is_out_of_date(gn->mtime)) { 503 printf("# last modified %s: %s\n", 504 Targ_FmtTime(gn->mtime), 505 (gn->made == UNMADE ? "unmade" : 506 (gn->made == MADE ? "made" : 507 (gn->made == UPTODATE ? "up-to-date" : 508 "error when made")))); 509 } else if (gn->made != UNMADE) { 510 printf("# non-existent (maybe): %s\n", 511 (gn->made == MADE ? "made" : 512 (gn->made == UPTODATE ? "up-to-date" : 513 (gn->made == ERROR ? "error when made" : 514 "aborted")))); 515 } else { 516 printf("# unmade\n"); 517 } 518 } 519 if (!Lst_IsEmpty(&gn->iParents)) { 520 printf("# implicit parents: "); 521 Lst_Every(&gn->iParents, TargPrintName); 522 fputc('\n', stdout); 523 } 524 } 525 if (!Lst_IsEmpty(&gn->parents)) { 526 printf("# parents: "); 527 Lst_Every(&gn->parents, TargPrintName); 528 fputc('\n', stdout); 529 } 530 531 printf("%-16s", gn->name); 532 switch (gn->type & OP_OPMASK) { 533 case OP_DEPENDS: 534 printf(": "); break; 535 case OP_FORCE: 536 printf("! "); break; 537 case OP_DOUBLEDEP: 538 printf(":: "); break; 539 } 540 Targ_PrintType(gn->type); 541 Lst_Every(&gn->children, TargPrintName); 542 fputc('\n', stdout); 543 Lst_Every(&gn->commands, Targ_PrintCmd); 544 printf("\n\n"); 545 if (gn->type & OP_DOUBLEDEP) { 546 LstNode ln; 547 548 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 549 TargPrintNode((GNode *)Lst_Datum(ln), pass); 550 } 551 } 552 } 553 554 /*- 555 *----------------------------------------------------------------------- 556 * TargPrintOnlySrc -- 557 * Print targets that are just a source. 558 *----------------------------------------------------------------------- 559 */ 560 static void 561 TargPrintOnlySrc(gn) 562 GNode *gn; 563 { 564 if (OP_NOP(gn->type)) 565 printf("#\t%s [%s]\n", gn->name, 566 gn->path != NULL ? gn->path : gn->name); 567 } 568 569 /*- 570 *----------------------------------------------------------------------- 571 * Targ_PrintGraph -- 572 * print the entire graph. 573 *----------------------------------------------------------------------- 574 */ 575 void 576 Targ_PrintGraph(pass) 577 int pass; /* Which pass this is. 1 => no processing 578 * 2 => processing done */ 579 { 580 GNode *gn; 581 unsigned int i; 582 583 printf("#*** Input graph:\n"); 584 for (gn = ohash_first(&targets, &i); gn != NULL; 585 gn = ohash_next(&targets, &i)) 586 TargPrintNode(gn, pass); 587 printf("\n\n"); 588 printf("#\n# Files that are only sources:\n"); 589 for (gn = ohash_first(&targets, &i); gn != NULL; 590 gn = ohash_next(&targets, &i)) 591 TargPrintOnlySrc(gn); 592 Var_Dump(); 593 printf("\n"); 594 #ifdef DEBUG_DIRECTORY_CACHE 595 Dir_PrintDirectories(); 596 printf("\n"); 597 #endif 598 Suff_PrintAll(); 599 } 600