1 /* $OpenPackages$ */ 2 /* $OpenBSD: targ.c,v 1.56 2008/01/29 22:23:10 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 #include "node_int.h" 119 #include "nodehashconsts.h" 120 #ifdef CLEANUP 121 #include <stdlib.h> 122 #endif 123 124 static struct ohash targets; /* a hash table of same */ 125 struct ohash_info gnode_info = { 126 offsetof(GNode, name), NULL, hash_alloc, hash_free, element_alloc 127 }; 128 129 static void TargPrintOnlySrc(GNode *); 130 static void TargPrintName(void *); 131 static void TargPrintNode(GNode *, int); 132 #ifdef CLEANUP 133 static LIST allTargets; 134 static void TargFreeGN(void *); 135 #endif 136 #define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f) 137 138 139 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; 140 141 void 142 Targ_Init(void) 143 { 144 /* A small make file already creates 200 targets. */ 145 ohash_init(&targets, 10, &gnode_info); 146 #ifdef CLEANUP 147 Lst_Init(&allTargets); 148 #endif 149 begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE); 150 begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 151 end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE); 152 end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 153 interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE); 154 interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 155 DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE); 156 DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT; 157 158 } 159 160 #ifdef CLEANUP 161 void 162 Targ_End(void) 163 { 164 Lst_Every(&allTargets, TargFreeGN); 165 ohash_delete(&targets); 166 } 167 #endif 168 169 GNode * 170 Targ_NewGNi(const char *name, const char *ename) 171 { 172 GNode *gn; 173 174 gn = ohash_create_entry(&gnode_info, name, &ename); 175 gn->path = NULL; 176 if (name[0] == '-' && name[1] == 'l') 177 gn->type = OP_LIB; 178 else 179 gn->type = 0; 180 181 gn->special = SPECIAL_NONE; 182 gn->unmade = 0; 183 gn->must_make = false; 184 gn->built_status = UNKNOWN; 185 gn->childMade = false; 186 gn->order = 0; 187 ts_set_out_of_date(gn->mtime); 188 ts_set_out_of_date(gn->cmtime); 189 Lst_Init(&gn->cohorts); 190 Lst_Init(&gn->parents); 191 Lst_Init(&gn->children); 192 Lst_Init(&gn->successors); 193 Lst_Init(&gn->preds); 194 SymTable_Init(&gn->context); 195 gn->lineno = 0; 196 gn->fname = NULL; 197 gn->impliedsrc = NULL; 198 Lst_Init(&gn->commands); 199 Lst_Init(&gn->expanded); 200 gn->suffix = NULL; 201 202 #ifdef STATS_GN_CREATION 203 STAT_GN_COUNT++; 204 #endif 205 206 #ifdef CLEANUP 207 Lst_AtEnd(&allTargets, gn); 208 #endif 209 return gn; 210 } 211 212 #ifdef CLEANUP 213 static void 214 TargFreeGN(void *gnp) 215 { 216 GNode *gn = (GNode *)gnp; 217 218 efree(gn->path); 219 Lst_Destroy(&gn->cohorts, NOFREE); 220 Lst_Destroy(&gn->parents, NOFREE); 221 Lst_Destroy(&gn->children, NOFREE); 222 Lst_Destroy(&gn->successors, NOFREE); 223 Lst_Destroy(&gn->preds, NOFREE); 224 Lst_Destroy(&gn->commands, NOFREE); 225 SymTable_Destroy(&gn->context); 226 free(gn); 227 } 228 #endif 229 230 GNode * 231 Targ_FindNodei(const char *name, const char *ename, int flags) 232 { 233 uint32_t hv; 234 235 hv = ohash_interval(name, &ename); 236 return Targ_FindNodeih(name, ename, hv, flags); 237 } 238 239 GNode * 240 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags) 241 { 242 GNode *gn; 243 unsigned int slot; 244 245 slot = ohash_lookup_interval(&targets, name, ename, hv); 246 247 gn = ohash_find(&targets, slot); 248 249 if (gn == NULL && (flags & TARG_CREATE)) { 250 gn = Targ_NewGNi(name, ename); 251 ohash_insert(&targets, slot, gn); 252 } 253 254 return gn; 255 } 256 257 void 258 Targ_FindList(Lst nodes, Lst names) 259 { 260 LstNode ln; 261 GNode *gn; 262 char *name; 263 264 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 265 name = (char *)Lst_Datum(ln); 266 gn = Targ_FindNode(name, TARG_CREATE); 267 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 268 * are added to the list in the order in which they were 269 * encountered in the makefile. */ 270 Lst_AtEnd(nodes, gn); 271 if (gn->type & OP_DOUBLEDEP) 272 Lst_Concat(nodes, &gn->cohorts); 273 } 274 } 275 276 bool 277 Targ_Ignore(GNode *gn) 278 { 279 if (ignoreErrors || gn->type & OP_IGNORE) 280 return true; 281 else 282 return false; 283 } 284 285 bool 286 Targ_Silent(GNode *gn) 287 { 288 if (beSilent || gn->type & OP_SILENT) 289 return true; 290 else 291 return false; 292 } 293 294 bool 295 Targ_Precious(GNode *gn) 296 { 297 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) 298 return true; 299 else 300 return false; 301 } 302 303 static void 304 TargPrintName(void *gnp) 305 { 306 GNode *gn = (GNode *)gnp; 307 printf("%s ", gn->name); 308 } 309 310 311 void 312 Targ_PrintCmd(void *cmd) 313 { 314 printf("\t%s\n", (char *)cmd); 315 } 316 317 void 318 Targ_PrintType(int type) 319 { 320 int tbit; 321 322 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 323 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 324 325 type &= ~OP_OPMASK; 326 327 while (type) { 328 tbit = 1 << (ffs(type) - 1); 329 type &= ~tbit; 330 331 switch (tbit) { 332 PRINTBIT(OPTIONAL); 333 PRINTBIT(USE); 334 PRINTBIT(EXEC); 335 PRINTBIT(IGNORE); 336 PRINTBIT(PRECIOUS); 337 PRINTBIT(SILENT); 338 PRINTBIT(MAKE); 339 PRINTBIT(JOIN); 340 PRINTBIT(INVISIBLE); 341 PRINTBIT(NOTMAIN); 342 PRINTDBIT(LIB); 343 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 344 case OP_MEMBER: 345 if (DEBUG(TARG)) 346 printf(".MEMBER "); 347 break; 348 PRINTDBIT(ARCHV); 349 } 350 } 351 } 352 const char * 353 status_to_string(GNode *gn) 354 { 355 switch (gn->built_status) { 356 case UNKNOWN: 357 return "unknown"; 358 case MADE: 359 return "made"; 360 case UPTODATE: 361 return "up-to-date"; 362 case ERROR: 363 return "error when made"; 364 case ABORTED: 365 return "aborted"; 366 default: 367 return "other status"; 368 } 369 } 370 371 static void 372 TargPrintNode(GNode *gn, int pass) 373 { 374 if (OP_NOP(gn->type)) 375 return; 376 printf("#\n"); 377 if (pass == 2) { 378 printf("# %d unmade children\n", gn->unmade); 379 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 380 if (!is_out_of_date(gn->mtime)) { 381 printf("# last modified %s: %s\n", 382 time_to_string(gn->mtime), 383 status_to_string(gn)); 384 } else if (gn->built_status != UNKNOWN) { 385 printf("# non-existent (maybe): %s\n", 386 status_to_string(gn)); 387 } else { 388 printf("# unmade\n"); 389 } 390 } 391 } 392 if (!Lst_IsEmpty(&gn->parents)) { 393 printf("# parents: "); 394 Lst_Every(&gn->parents, TargPrintName); 395 fputc('\n', stdout); 396 } 397 if (gn->impliedsrc) 398 printf("# implied source: %s\n", gn->impliedsrc->name); 399 400 printf("%-16s", gn->name); 401 switch (gn->type & OP_OPMASK) { 402 case OP_DEPENDS: 403 printf(": "); break; 404 case OP_FORCE: 405 printf("! "); break; 406 case OP_DOUBLEDEP: 407 printf(":: "); break; 408 } 409 Targ_PrintType(gn->type); 410 Lst_Every(&gn->children, TargPrintName); 411 fputc('\n', stdout); 412 Lst_Every(&gn->commands, Targ_PrintCmd); 413 printf("\n\n"); 414 if (gn->type & OP_DOUBLEDEP) { 415 LstNode ln; 416 417 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 418 TargPrintNode((GNode *)Lst_Datum(ln), pass); 419 } 420 } 421 422 static void 423 TargPrintOnlySrc(GNode *gn) 424 { 425 if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE && 426 !(gn->type & OP_DUMMY)) 427 printf("#\t%s [%s]\n", gn->name, 428 gn->path != NULL ? gn->path : gn->name); 429 } 430 431 void 432 Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing 433 * 2 => processing done */ 434 { 435 GNode *gn; 436 unsigned int i; 437 438 printf("#*** Input graph:\n"); 439 for (gn = ohash_first(&targets, &i); gn != NULL; 440 gn = ohash_next(&targets, &i)) 441 TargPrintNode(gn, pass); 442 printf("\n\n"); 443 printf("#\n# Files that are only sources:\n"); 444 for (gn = ohash_first(&targets, &i); gn != NULL; 445 gn = ohash_next(&targets, &i)) 446 TargPrintOnlySrc(gn); 447 Var_Dump(); 448 printf("\n"); 449 #ifdef DEBUG_DIRECTORY_CACHE 450 Dir_PrintDirectories(); 451 printf("\n"); 452 #endif 453 Suff_PrintAll(); 454 } 455 456 static char *curdir, *objdir; 457 static size_t curdir_len, objdir_len; 458 459 void 460 Targ_setdirs(const char *c, const char *o) 461 { 462 curdir_len = strlen(c); 463 curdir = emalloc(curdir_len+2); 464 memcpy(curdir, c, curdir_len); 465 curdir[curdir_len++] = '/'; 466 curdir[curdir_len] = 0; 467 468 objdir_len = strlen(o); 469 objdir = emalloc(objdir_len+2); 470 memcpy(objdir, o, objdir_len); 471 objdir[objdir_len++] = '/'; 472 objdir[objdir_len] = 0; 473 } 474 475 void 476 look_harder_for_target(GNode *gn) 477 { 478 GNode *extra, *cgn; 479 LstNode ln; 480 481 if (gn->type & (OP_RESOLVED|OP_PHONY)) 482 return; 483 gn->type |= OP_RESOLVED; 484 if (strncmp(gn->name, objdir, objdir_len) == 0) { 485 extra = Targ_FindNode(gn->name + objdir_len, TARG_NOCREATE); 486 if (extra != NULL) { 487 if (Lst_IsEmpty(&gn->commands)) 488 Lst_Concat(&gn->commands, &extra->commands); 489 for (ln = Lst_First(&extra->children); ln != NULL; 490 ln = Lst_Adv(ln)) { 491 cgn = (GNode *)Lst_Datum(ln); 492 493 if (Lst_AddNew(&gn->children, cgn)) { 494 Lst_AtEnd(&cgn->parents, gn); 495 gn->unmade++; 496 } 497 } 498 } 499 } 500 } 501