1 /* $OpenPackages$ */ 2 /* $OpenBSD: targ.c,v 1.40 2006/01/20 23:10:19 espie 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 <limits.h> 102 #include <stddef.h> 103 #include <stdio.h> 104 #include <stdint.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(void) 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(void) 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(const char *name, /* the name to stick in the new node */ 187 const char *ename) 188 { 189 GNode *gn; 190 191 gn = ohash_create_entry(&gnode_info, name, &ename); 192 gn->path = NULL; 193 if (name[0] == '-' && name[1] == 'l') { 194 gn->type = OP_LIB; 195 } else { 196 gn->type = 0; 197 } 198 gn->unmade = 0; 199 gn->make = false; 200 gn->made = UNMADE; 201 gn->childMade = false; 202 gn->order = 0; 203 ts_set_out_of_date(gn->mtime); 204 ts_set_out_of_date(gn->cmtime); 205 Lst_Init(&gn->iParents); 206 Lst_Init(&gn->cohorts); 207 Lst_Init(&gn->parents); 208 Lst_Init(&gn->children); 209 Lst_Init(&gn->successors); 210 Lst_Init(&gn->preds); 211 SymTable_Init(&gn->context); 212 gn->lineno = 0; 213 gn->fname = NULL; 214 Lst_Init(&gn->commands); 215 gn->suffix = NULL; 216 217 #ifdef STATS_GN_CREATION 218 STAT_GN_COUNT++; 219 #endif 220 221 #ifdef CLEANUP 222 Lst_AtEnd(&allTargets, gn); 223 #endif 224 return gn; 225 } 226 227 #ifdef CLEANUP 228 /*- 229 *----------------------------------------------------------------------- 230 * TargFreeGN -- 231 * Destroy a GNode 232 *----------------------------------------------------------------------- 233 */ 234 static void 235 TargFreeGN(void *gnp) 236 { 237 GNode *gn = (GNode *)gnp; 238 239 efree(gn->path); 240 Lst_Destroy(&gn->iParents, NOFREE); 241 Lst_Destroy(&gn->cohorts, NOFREE); 242 Lst_Destroy(&gn->parents, NOFREE); 243 Lst_Destroy(&gn->children, NOFREE); 244 Lst_Destroy(&gn->successors, NOFREE); 245 Lst_Destroy(&gn->preds, NOFREE); 246 Lst_Destroy(&gn->commands, NOFREE); 247 SymTable_Destroy(&gn->context); 248 free(gn); 249 } 250 #endif 251 252 253 /*- 254 *----------------------------------------------------------------------- 255 * Targ_FindNodei -- 256 * Find a node in the list using the given name for matching 257 * 258 * Results: 259 * The node in the list if it was. If it wasn't, return NULL if 260 * flags was TARG_NOCREATE or the newly created and initialized node 261 * if flags was TARG_CREATE 262 * 263 * Side Effects: 264 * Sometimes a node is created and added to the list 265 *----------------------------------------------------------------------- 266 */ 267 GNode * 268 Targ_FindNodei(const char *name, const char *ename, 269 int flags) /* flags governing events when target not 270 * found */ 271 { 272 GNode *gn; /* node in that element */ 273 unsigned int slot; 274 275 slot = ohash_qlookupi(&targets, name, &ename); 276 277 gn = ohash_find(&targets, slot); 278 279 if (gn == NULL && (flags & TARG_CREATE)) { 280 gn = Targ_NewGNi(name, ename); 281 ohash_insert(&targets, slot, gn); 282 } 283 284 return gn; 285 } 286 287 /*- 288 *----------------------------------------------------------------------- 289 * Targ_FindList -- 290 * Make a complete list of GNodes from the given list of names 291 * 292 * Side Effects: 293 * Nodes will be created for all names in names which do not yet have graph 294 * nodes. 295 * 296 * A complete list of graph nodes corresponding to all instances of all 297 * the names in names is added to nodes. 298 * ----------------------------------------------------------------------- 299 */ 300 void 301 Targ_FindList(Lst nodes, /* result list */ 302 Lst names) /* list of names to find */ 303 { 304 LstNode ln; /* name list element */ 305 GNode *gn; /* node in tLn */ 306 char *name; 307 308 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 309 name = (char *)Lst_Datum(ln); 310 gn = Targ_FindNode(name, TARG_CREATE); 311 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 312 * are added to the list in the order in which they were 313 * encountered in the makefile. */ 314 Lst_AtEnd(nodes, gn); 315 if (gn->type & OP_DOUBLEDEP) 316 Lst_Concat(nodes, &gn->cohorts); 317 } 318 } 319 320 /*- 321 *----------------------------------------------------------------------- 322 * Targ_Ignore -- 323 * Return true if should ignore errors when creating gn 324 *----------------------------------------------------------------------- 325 */ 326 bool 327 Targ_Ignore(GNode *gn) 328 { 329 if (ignoreErrors || gn->type & OP_IGNORE) 330 return true; 331 else 332 return false; 333 } 334 335 /*- 336 *----------------------------------------------------------------------- 337 * Targ_Silent -- 338 * Return true if be silent when creating gn 339 *----------------------------------------------------------------------- 340 */ 341 bool 342 Targ_Silent(GNode *gn) 343 { 344 if (beSilent || gn->type & OP_SILENT) 345 return true; 346 else 347 return false; 348 } 349 350 /*- 351 *----------------------------------------------------------------------- 352 * Targ_Precious -- 353 * See if the given target is precious 354 *----------------------------------------------------------------------- 355 */ 356 bool 357 Targ_Precious(GNode *gn) 358 { 359 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) 360 return true; 361 else 362 return false; 363 } 364 365 /******************* DEBUG INFO PRINTING ****************/ 366 367 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 368 /*- 369 *----------------------------------------------------------------------- 370 * Targ_SetMain -- 371 * Set our idea of the main target we'll be creating. Used for 372 * debugging output. 373 * 374 * Side Effects: 375 * "mainTarg" is set to the main target's node. 376 *----------------------------------------------------------------------- 377 */ 378 void 379 Targ_SetMain(GNode *gn) 380 { 381 mainTarg = gn; 382 } 383 384 static void 385 TargPrintName(void *gnp) 386 { 387 GNode *gn = (GNode *)gnp; 388 printf("%s ", gn->name); 389 } 390 391 392 void 393 Targ_PrintCmd(void *cmd) 394 { 395 printf("\t%s\n", (char *)cmd); 396 } 397 398 /*- 399 *----------------------------------------------------------------------- 400 * Targ_FmtTime -- 401 * Format a modification time in some reasonable way and return it. 402 * 403 * Results: 404 * The time reformatted. 405 * 406 * Side Effects: 407 * The time is placed in a static area, so it is overwritten 408 * with each call. 409 *----------------------------------------------------------------------- 410 */ 411 char * 412 Targ_FmtTime(TIMESTAMP time) 413 { 414 struct tm *parts; 415 static char buf[128]; 416 time_t t; 417 418 t = timestamp2time_t(time); 419 420 parts = localtime(&t); 421 strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts); 422 buf[sizeof(buf) - 1] = '\0'; 423 return buf; 424 } 425 426 /*- 427 *----------------------------------------------------------------------- 428 * Targ_PrintType -- 429 * Print out a type field giving only those attributes the user can 430 * set. 431 *----------------------------------------------------------------------- 432 */ 433 void 434 Targ_PrintType(int type) 435 { 436 int tbit; 437 438 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 439 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 440 441 type &= ~OP_OPMASK; 442 443 while (type) { 444 tbit = 1 << (ffs(type) - 1); 445 type &= ~tbit; 446 447 switch (tbit) { 448 PRINTBIT(OPTIONAL); 449 PRINTBIT(USE); 450 PRINTBIT(EXEC); 451 PRINTBIT(IGNORE); 452 PRINTBIT(PRECIOUS); 453 PRINTBIT(SILENT); 454 PRINTBIT(MAKE); 455 PRINTBIT(JOIN); 456 PRINTBIT(INVISIBLE); 457 PRINTBIT(NOTMAIN); 458 PRINTDBIT(LIB); 459 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 460 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break; 461 PRINTDBIT(ARCHV); 462 } 463 } 464 } 465 466 /*- 467 *----------------------------------------------------------------------- 468 * TargPrintNode -- 469 * print the contents of a node 470 *----------------------------------------------------------------------- 471 */ 472 static void 473 TargPrintNode(GNode *gn, int pass) 474 { 475 if (!OP_NOP(gn->type)) { 476 printf("#\n"); 477 if (gn == mainTarg) { 478 printf("# *** MAIN TARGET ***\n"); 479 } 480 if (pass == 2) { 481 if (gn->unmade) { 482 printf("# %d unmade children\n", gn->unmade); 483 } else { 484 printf("# No unmade children\n"); 485 } 486 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 487 if (!is_out_of_date(gn->mtime)) { 488 printf("# last modified %s: %s\n", 489 Targ_FmtTime(gn->mtime), 490 (gn->made == UNMADE ? "unmade" : 491 (gn->made == MADE ? "made" : 492 (gn->made == UPTODATE ? "up-to-date" : 493 "error when made")))); 494 } else if (gn->made != UNMADE) { 495 printf("# non-existent (maybe): %s\n", 496 (gn->made == MADE ? "made" : 497 (gn->made == UPTODATE ? "up-to-date" : 498 (gn->made == ERROR ? "error when made" : 499 "aborted")))); 500 } else { 501 printf("# unmade\n"); 502 } 503 } 504 if (!Lst_IsEmpty(&gn->iParents)) { 505 printf("# implicit parents: "); 506 Lst_Every(&gn->iParents, TargPrintName); 507 fputc('\n', stdout); 508 } 509 } 510 if (!Lst_IsEmpty(&gn->parents)) { 511 printf("# parents: "); 512 Lst_Every(&gn->parents, TargPrintName); 513 fputc('\n', stdout); 514 } 515 516 printf("%-16s", gn->name); 517 switch (gn->type & OP_OPMASK) { 518 case OP_DEPENDS: 519 printf(": "); break; 520 case OP_FORCE: 521 printf("! "); break; 522 case OP_DOUBLEDEP: 523 printf(":: "); break; 524 } 525 Targ_PrintType(gn->type); 526 Lst_Every(&gn->children, TargPrintName); 527 fputc('\n', stdout); 528 Lst_Every(&gn->commands, Targ_PrintCmd); 529 printf("\n\n"); 530 if (gn->type & OP_DOUBLEDEP) { 531 LstNode ln; 532 533 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 534 TargPrintNode((GNode *)Lst_Datum(ln), pass); 535 } 536 } 537 } 538 539 /*- 540 *----------------------------------------------------------------------- 541 * TargPrintOnlySrc -- 542 * Print targets that are just a source. 543 *----------------------------------------------------------------------- 544 */ 545 static void 546 TargPrintOnlySrc(GNode *gn) 547 { 548 if (OP_NOP(gn->type)) 549 printf("#\t%s [%s]\n", gn->name, 550 gn->path != NULL ? gn->path : gn->name); 551 } 552 553 /*- 554 *----------------------------------------------------------------------- 555 * Targ_PrintGraph -- 556 * print the entire graph. 557 *----------------------------------------------------------------------- 558 */ 559 void 560 Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing 561 * 2 => processing done */ 562 { 563 GNode *gn; 564 unsigned int i; 565 566 printf("#*** Input graph:\n"); 567 for (gn = ohash_first(&targets, &i); gn != NULL; 568 gn = ohash_next(&targets, &i)) 569 TargPrintNode(gn, pass); 570 printf("\n\n"); 571 printf("#\n# Files that are only sources:\n"); 572 for (gn = ohash_first(&targets, &i); gn != NULL; 573 gn = ohash_next(&targets, &i)) 574 TargPrintOnlySrc(gn); 575 Var_Dump(); 576 printf("\n"); 577 #ifdef DEBUG_DIRECTORY_CACHE 578 Dir_PrintDirectories(); 579 printf("\n"); 580 #endif 581 Suff_PrintAll(); 582 } 583