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