1 /* $OpenPackages$ */ 2 /* $OpenBSD: targ.c,v 1.57 2008/11/04 07:22:36 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; /* hash table of targets */ 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 gn->next = NULL; 202 gn->basename = NULL; 203 gn->sibling = gn; 204 gn->build_lock = false; 205 206 #ifdef STATS_GN_CREATION 207 STAT_GN_COUNT++; 208 #endif 209 210 #ifdef CLEANUP 211 Lst_AtEnd(&allTargets, gn); 212 #endif 213 return gn; 214 } 215 216 #ifdef CLEANUP 217 static void 218 TargFreeGN(void *gnp) 219 { 220 GNode *gn = (GNode *)gnp; 221 222 efree(gn->path); 223 Lst_Destroy(&gn->cohorts, NOFREE); 224 Lst_Destroy(&gn->parents, NOFREE); 225 Lst_Destroy(&gn->children, NOFREE); 226 Lst_Destroy(&gn->successors, NOFREE); 227 Lst_Destroy(&gn->preds, NOFREE); 228 Lst_Destroy(&gn->commands, NOFREE); 229 SymTable_Destroy(&gn->context); 230 free(gn); 231 } 232 #endif 233 234 GNode * 235 Targ_FindNodei(const char *name, const char *ename, int flags) 236 { 237 uint32_t hv; 238 239 hv = ohash_interval(name, &ename); 240 return Targ_FindNodeih(name, ename, hv, flags); 241 } 242 243 GNode * 244 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags) 245 { 246 GNode *gn; 247 unsigned int slot; 248 249 slot = ohash_lookup_interval(&targets, name, ename, hv); 250 251 gn = ohash_find(&targets, slot); 252 253 if (gn == NULL && (flags & TARG_CREATE)) { 254 gn = Targ_NewGNi(name, ename); 255 ohash_insert(&targets, slot, gn); 256 } 257 258 return gn; 259 } 260 261 void 262 Targ_FindList(Lst nodes, Lst names) 263 { 264 LstNode ln; 265 GNode *gn; 266 char *name; 267 268 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 269 name = (char *)Lst_Datum(ln); 270 gn = Targ_FindNode(name, TARG_CREATE); 271 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 272 * are added to the list in the order in which they were 273 * encountered in the makefile. */ 274 Lst_AtEnd(nodes, gn); 275 if (gn->type & OP_DOUBLEDEP) 276 Lst_Concat(nodes, &gn->cohorts); 277 } 278 } 279 280 bool 281 Targ_Ignore(GNode *gn) 282 { 283 if (ignoreErrors || gn->type & OP_IGNORE) 284 return true; 285 else 286 return false; 287 } 288 289 bool 290 Targ_Silent(GNode *gn) 291 { 292 if (beSilent || gn->type & OP_SILENT) 293 return true; 294 else 295 return false; 296 } 297 298 bool 299 Targ_Precious(GNode *gn) 300 { 301 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) 302 return true; 303 else 304 return false; 305 } 306 307 static void 308 TargPrintName(void *gnp) 309 { 310 GNode *gn = (GNode *)gnp; 311 printf("%s ", gn->name); 312 } 313 314 315 void 316 Targ_PrintCmd(void *cmd) 317 { 318 printf("\t%s\n", (char *)cmd); 319 } 320 321 void 322 Targ_PrintType(int type) 323 { 324 int tbit; 325 326 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 327 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 328 329 type &= ~OP_OPMASK; 330 331 while (type) { 332 tbit = 1 << (ffs(type) - 1); 333 type &= ~tbit; 334 335 switch (tbit) { 336 PRINTBIT(OPTIONAL); 337 PRINTBIT(USE); 338 PRINTBIT(EXEC); 339 PRINTBIT(IGNORE); 340 PRINTBIT(PRECIOUS); 341 PRINTBIT(SILENT); 342 PRINTBIT(MAKE); 343 PRINTBIT(JOIN); 344 PRINTBIT(INVISIBLE); 345 PRINTBIT(NOTMAIN); 346 PRINTDBIT(LIB); 347 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 348 case OP_MEMBER: 349 if (DEBUG(TARG)) 350 printf(".MEMBER "); 351 break; 352 PRINTDBIT(ARCHV); 353 } 354 } 355 } 356 const char * 357 status_to_string(GNode *gn) 358 { 359 switch (gn->built_status) { 360 case UNKNOWN: 361 return "unknown"; 362 case MADE: 363 return "made"; 364 case UPTODATE: 365 return "up-to-date"; 366 case ERROR: 367 return "error when made"; 368 case ABORTED: 369 return "aborted"; 370 default: 371 return "other status"; 372 } 373 } 374 375 static void 376 TargPrintNode(GNode *gn, int pass) 377 { 378 if (OP_NOP(gn->type)) 379 return; 380 printf("#\n"); 381 if (pass == 2) { 382 printf("# %d unmade children\n", gn->unmade); 383 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 384 if (!is_out_of_date(gn->mtime)) { 385 printf("# last modified %s: %s\n", 386 time_to_string(gn->mtime), 387 status_to_string(gn)); 388 } else if (gn->built_status != UNKNOWN) { 389 printf("# non-existent (maybe): %s\n", 390 status_to_string(gn)); 391 } else { 392 printf("# unmade\n"); 393 } 394 } 395 } 396 if (!Lst_IsEmpty(&gn->parents)) { 397 printf("# parents: "); 398 Lst_Every(&gn->parents, TargPrintName); 399 fputc('\n', stdout); 400 } 401 if (gn->impliedsrc) 402 printf("# implied source: %s\n", gn->impliedsrc->name); 403 404 printf("%-16s", gn->name); 405 switch (gn->type & OP_OPMASK) { 406 case OP_DEPENDS: 407 printf(": "); break; 408 case OP_FORCE: 409 printf("! "); break; 410 case OP_DOUBLEDEP: 411 printf(":: "); break; 412 } 413 Targ_PrintType(gn->type); 414 Lst_Every(&gn->children, TargPrintName); 415 fputc('\n', stdout); 416 Lst_Every(&gn->commands, Targ_PrintCmd); 417 printf("\n\n"); 418 if (gn->type & OP_DOUBLEDEP) { 419 LstNode ln; 420 421 for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)) 422 TargPrintNode((GNode *)Lst_Datum(ln), pass); 423 } 424 } 425 426 static void 427 TargPrintOnlySrc(GNode *gn) 428 { 429 if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE && 430 !(gn->type & OP_DUMMY)) 431 printf("#\t%s [%s]\n", gn->name, 432 gn->path != NULL ? gn->path : gn->name); 433 } 434 435 void 436 Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing 437 * 2 => processing done */ 438 { 439 GNode *gn; 440 unsigned int i; 441 442 printf("#*** Input graph:\n"); 443 for (gn = ohash_first(&targets, &i); gn != NULL; 444 gn = ohash_next(&targets, &i)) 445 TargPrintNode(gn, pass); 446 printf("\n\n"); 447 printf("#\n# Files that are only sources:\n"); 448 for (gn = ohash_first(&targets, &i); gn != NULL; 449 gn = ohash_next(&targets, &i)) 450 TargPrintOnlySrc(gn); 451 Var_Dump(); 452 printf("\n"); 453 #ifdef DEBUG_DIRECTORY_CACHE 454 Dir_PrintDirectories(); 455 printf("\n"); 456 #endif 457 Suff_PrintAll(); 458 } 459 460 struct ohash * 461 targets_hash() 462 { 463 return &targets; 464 } 465