1 /* $OpenBSD: targ.c,v 1.62 2010/07/19 19:46:44 espie Exp $ */ 2 /* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1999 Marc Espie. 6 * 7 * Extensive code changes for the OpenBSD project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 22 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 /* 31 * Copyright (c) 1988, 1989, 1990, 1993 32 * The Regents of the University of California. All rights reserved. 33 * Copyright (c) 1989 by Berkeley Softworks 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Adam de Boor. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 /*- 65 * targ.c -- 66 * Target nodes are kept into a hash table. 67 * 68 * Interface: 69 * Targ_Init Initialization procedure. 70 * 71 * Targ_End Cleanup the module 72 * 73 * Targ_NewGN Create a new GNode for the passed target 74 * (string). The node is *not* placed in the 75 * hash table, though all its fields are 76 * initialized. 77 * 78 * Targ_FindNode Find the node for a given target, creating 79 * and storing it if it doesn't exist and the 80 * flags are right (TARG_CREATE) 81 * 82 * Targ_FindList Given a list of names, find nodes for all 83 * of them, creating nodes if needed. 84 * 85 * Targ_Ignore Return true if errors should be ignored when 86 * creating the given target. 87 * 88 * Targ_Silent Return true if we should be silent when 89 * creating the given target. 90 * 91 * Targ_Precious Return true if the target is precious and 92 * should not be removed if we are interrupted. 93 * 94 * Debugging: 95 * Targ_PrintGraph Print out the entire graphm all variables 96 * and statistics for the directory cache. Should 97 * print something for suffixes, too, but... 98 */ 99 100 #include <limits.h> 101 #include <stddef.h> 102 #include <stdio.h> 103 #include <stdint.h> 104 #include <string.h> 105 #include "config.h" 106 #include "defines.h" 107 #include "ohash.h" 108 #include "stats.h" 109 #include "suff.h" 110 #include "var.h" 111 #include "targ.h" 112 #include "memory.h" 113 #include "gnode.h" 114 #include "extern.h" 115 #include "timestamp.h" 116 #include "lst.h" 117 #include "node_int.h" 118 #include "nodehashconsts.h" 119 #ifdef CLEANUP 120 #include <stdlib.h> 121 #endif 122 123 static struct ohash targets; /* hash table of targets */ 124 struct ohash_info gnode_info = { 125 offsetof(GNode, name), NULL, hash_alloc, hash_free, element_alloc 126 }; 127 128 static void TargPrintOnlySrc(GNode *); 129 static void TargPrintName(void *); 130 static void TargPrintNode(GNode *, int); 131 #ifdef CLEANUP 132 static LIST allTargets; 133 static void TargFreeGN(void *); 134 #endif 135 #define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f) 136 137 138 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; 139 140 void 141 Targ_Init(void) 142 { 143 /* A small make file already creates 200 targets. */ 144 ohash_init(&targets, 10, &gnode_info); 145 #ifdef CLEANUP 146 Lst_Init(&allTargets); 147 #endif 148 begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE); 149 begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 150 end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE); 151 end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 152 interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE); 153 interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 154 DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE); 155 DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT; 156 157 } 158 159 #ifdef CLEANUP 160 void 161 Targ_End(void) 162 { 163 Lst_Every(&allTargets, TargFreeGN); 164 ohash_delete(&targets); 165 } 166 #endif 167 168 GNode * 169 Targ_NewGNi(const char *name, const char *ename) 170 { 171 GNode *gn; 172 173 gn = ohash_create_entry(&gnode_info, name, &ename); 174 gn->path = NULL; 175 if (name[0] == '-' && name[1] == 'l') 176 gn->type = OP_LIB; 177 else 178 gn->type = 0; 179 180 gn->special = SPECIAL_NONE; 181 gn->unmade = 0; 182 gn->must_make = false; 183 gn->built_status = UNKNOWN; 184 gn->childMade = false; 185 gn->order = 0; 186 ts_set_out_of_date(gn->mtime); 187 ts_set_out_of_date(gn->cmtime); 188 Lst_Init(&gn->cohorts); 189 Lst_Init(&gn->parents); 190 Lst_Init(&gn->children); 191 Lst_Init(&gn->successors); 192 Lst_Init(&gn->preds); 193 SymTable_Init(&gn->context); 194 gn->lineno = 0; 195 gn->fname = NULL; 196 gn->impliedsrc = NULL; 197 Lst_Init(&gn->commands); 198 Lst_Init(&gn->expanded); 199 gn->suffix = NULL; 200 gn->next = NULL; 201 gn->basename = NULL; 202 gn->sibling = gn; 203 gn->build_lock = false; 204 205 #ifdef STATS_GN_CREATION 206 STAT_GN_COUNT++; 207 #endif 208 209 #ifdef CLEANUP 210 Lst_AtEnd(&allTargets, gn); 211 #endif 212 return gn; 213 } 214 215 #ifdef CLEANUP 216 static void 217 TargFreeGN(void *gnp) 218 { 219 GNode *gn = (GNode *)gnp; 220 221 efree(gn->path); 222 Lst_Destroy(&gn->cohorts, NOFREE); 223 Lst_Destroy(&gn->parents, NOFREE); 224 Lst_Destroy(&gn->children, NOFREE); 225 Lst_Destroy(&gn->successors, NOFREE); 226 Lst_Destroy(&gn->preds, NOFREE); 227 Lst_Destroy(&gn->commands, NOFREE); 228 SymTable_Destroy(&gn->context); 229 free(gn); 230 } 231 #endif 232 233 GNode * 234 Targ_FindNodei(const char *name, const char *ename, int flags) 235 { 236 uint32_t hv; 237 238 hv = ohash_interval(name, &ename); 239 return Targ_FindNodeih(name, ename, hv, flags); 240 } 241 242 GNode * 243 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags) 244 { 245 GNode *gn; 246 unsigned int slot; 247 248 slot = ohash_lookup_interval(&targets, name, ename, hv); 249 250 gn = ohash_find(&targets, slot); 251 252 if (gn == NULL && (flags & TARG_CREATE)) { 253 gn = Targ_NewGNi(name, ename); 254 ohash_insert(&targets, slot, gn); 255 } 256 257 return gn; 258 } 259 260 void 261 Targ_FindList(Lst nodes, Lst names) 262 { 263 LstNode ln; 264 GNode *gn; 265 char *name; 266 267 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 268 name = (char *)Lst_Datum(ln); 269 gn = Targ_FindNode(name, TARG_CREATE); 270 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 271 * are added to the list in the order in which they were 272 * encountered in the makefile. */ 273 Lst_AtEnd(nodes, gn); 274 if (gn->type & OP_DOUBLEDEP) 275 Lst_Concat(nodes, &gn->cohorts); 276 } 277 } 278 279 bool 280 Targ_Ignore(GNode *gn) 281 { 282 if (ignoreErrors || gn->type & OP_IGNORE) 283 return true; 284 else 285 return false; 286 } 287 288 bool 289 Targ_Silent(GNode *gn) 290 { 291 if (beSilent || gn->type & OP_SILENT) 292 return true; 293 else 294 return false; 295 } 296 297 bool 298 Targ_Precious(GNode *gn) 299 { 300 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP|OP_PHONY))) 301 return true; 302 else 303 return false; 304 } 305 306 static void 307 TargPrintName(void *gnp) 308 { 309 GNode *gn = (GNode *)gnp; 310 printf("%s ", gn->name); 311 } 312 313 314 void 315 Targ_PrintCmd(void *cmd) 316 { 317 printf("\t%s\n", (char *)cmd); 318 } 319 320 void 321 Targ_PrintType(int type) 322 { 323 int tbit; 324 325 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 326 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 327 328 type &= ~OP_OPMASK; 329 330 while (type) { 331 tbit = 1 << (ffs(type) - 1); 332 type &= ~tbit; 333 334 switch (tbit) { 335 PRINTBIT(OPTIONAL); 336 PRINTBIT(USE); 337 PRINTBIT(EXEC); 338 PRINTBIT(IGNORE); 339 PRINTBIT(PRECIOUS); 340 PRINTBIT(SILENT); 341 PRINTBIT(MAKE); 342 PRINTBIT(JOIN); 343 PRINTBIT(INVISIBLE); 344 PRINTBIT(NOTMAIN); 345 PRINTDBIT(LIB); 346 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 347 case OP_MEMBER: 348 if (DEBUG(TARG)) 349 printf(".MEMBER "); 350 break; 351 PRINTDBIT(ARCHV); 352 } 353 } 354 } 355 const char * 356 status_to_string(GNode *gn) 357 { 358 switch (gn->built_status) { 359 case UNKNOWN: 360 return "unknown"; 361 case MADE: 362 return "made"; 363 case UPTODATE: 364 return "up-to-date"; 365 case ERROR: 366 return "error when made"; 367 case ABORTED: 368 return "aborted"; 369 default: 370 return "other status"; 371 } 372 } 373 374 static void 375 TargPrintNode(GNode *gn, int pass) 376 { 377 if (OP_NOP(gn->type)) 378 return; 379 printf("#\n"); 380 if (pass == 2) { 381 printf("# %d unmade children\n", gn->unmade); 382 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 383 if (!is_out_of_date(gn->mtime)) { 384 printf("# last modified %s: %s\n", 385 time_to_string(gn->mtime), 386 status_to_string(gn)); 387 } else if (gn->built_status != UNKNOWN) { 388 printf("# non-existent (maybe): %s\n", 389 status_to_string(gn)); 390 } else { 391 printf("# unmade\n"); 392 } 393 } 394 } 395 if (!Lst_IsEmpty(&gn->parents)) { 396 printf("# parents: "); 397 Lst_Every(&gn->parents, TargPrintName); 398 fputc('\n', stdout); 399 } 400 if (gn->impliedsrc) 401 printf("# implied source: %s\n", gn->impliedsrc->name); 402 403 printf("%-16s", gn->name); 404 switch (gn->type & OP_OPMASK) { 405 case OP_DEPENDS: 406 printf(": "); break; 407 case OP_FORCE: 408 printf("! "); break; 409 case OP_DOUBLEDEP: 410 printf(":: "); break; 411 } 412 Targ_PrintType(gn->type); 413 Lst_Every(&gn->children, TargPrintName); 414 fputc('\n', stdout); 415 Lst_Every(&gn->commands, Targ_PrintCmd); 416 printf("\n\n"); 417 if (gn->type & OP_DOUBLEDEP) { 418 LstNode ln; 419 420 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 421 TargPrintNode((GNode *)Lst_Datum(ln), pass); 422 } 423 } 424 425 static void 426 TargPrintOnlySrc(GNode *gn) 427 { 428 if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE && 429 !(gn->type & OP_DUMMY)) 430 printf("#\t%s [%s]\n", gn->name, 431 gn->path != NULL ? gn->path : gn->name); 432 } 433 434 void 435 Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing 436 * 2 => processing done */ 437 { 438 GNode *gn; 439 unsigned int i; 440 441 printf("#*** Input graph:\n"); 442 for (gn = ohash_first(&targets, &i); gn != NULL; 443 gn = ohash_next(&targets, &i)) 444 TargPrintNode(gn, pass); 445 printf("\n\n"); 446 printf("#\n# Files that are only sources:\n"); 447 for (gn = ohash_first(&targets, &i); gn != NULL; 448 gn = ohash_next(&targets, &i)) 449 TargPrintOnlySrc(gn); 450 Var_Dump(); 451 printf("\n"); 452 #ifdef DEBUG_DIRECTORY_CACHE 453 Dir_PrintDirectories(); 454 printf("\n"); 455 #endif 456 Suff_PrintAll(); 457 } 458 459 struct ohash * 460 targets_hash() 461 { 462 return &targets; 463 } 464 465 GNode * 466 Targ_FindNodeh(const char *name, size_t n, uint32_t hv, int flags) 467 { 468 return Targ_FindNodeih(name, name + n - 1, hv, flags); 469 } 470