1 /* $OpenBSD: targ.c,v 1.76 2015/01/23 22:35:58 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_NewGN Create a new GNode for the passed target 72 * (string). The node is *not* placed in the 73 * hash table, though all its fields are 74 * initialized. 75 * 76 * Targ_FindNode Find the node for a given target, creating 77 * and storing it if it doesn't exist and the 78 * flags are right (TARG_CREATE) 79 * 80 * Targ_FindList Given a list of names, find nodes for all 81 * of them, creating nodes if needed. 82 * 83 * Targ_Ignore Return true if errors should be ignored when 84 * creating the given target. 85 * 86 * Targ_Silent Return true if we should be silent when 87 * creating the given target. 88 * 89 * Targ_Precious Return true if the target is precious and 90 * should not be removed if we are interrupted. 91 * 92 * Debugging: 93 * Targ_PrintGraph Print out the entire graphm all variables 94 * and statistics for the directory cache. Should 95 * print something for suffixes, too, but... 96 */ 97 98 #include <limits.h> 99 #include <stddef.h> 100 #include <stdint.h> 101 #include <stdio.h> 102 #include <stdlib.h> 103 #include <string.h> 104 #include <ohash.h> 105 #include "config.h" 106 #include "defines.h" 107 #include "stats.h" 108 #include "suff.h" 109 #include "var.h" 110 #include "targ.h" 111 #include "memory.h" 112 #include "gnode.h" 113 #include "extern.h" 114 #include "timestamp.h" 115 #include "lst.h" 116 #include "node_int.h" 117 #include "nodehashconsts.h" 118 #include "dump.h" 119 120 static struct ohash targets; /* hash table of targets */ 121 struct ohash_info gnode_info = { 122 offsetof(GNode, name), NULL, hash_calloc, hash_free, element_alloc 123 }; 124 125 #define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f) 126 127 128 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; 129 130 void 131 Targ_Init(void) 132 { 133 /* A small make file already creates 200 targets. */ 134 ohash_init(&targets, 10, &gnode_info); 135 begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE); 136 begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 137 end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE); 138 end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 139 interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE); 140 interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT; 141 DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE); 142 DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT; 143 144 } 145 146 GNode * 147 Targ_NewGNi(const char *name, const char *ename) 148 { 149 GNode *gn; 150 151 gn = ohash_create_entry(&gnode_info, name, &ename); 152 gn->path = NULL; 153 gn->type = 0; 154 gn->special = SPECIAL_NONE; 155 gn->unmade = 0; 156 gn->must_make = false; 157 gn->built_status = UNKNOWN; 158 gn->childMade = false; 159 gn->order = 0; 160 ts_set_out_of_date(gn->mtime); 161 gn->youngest = gn; 162 Lst_Init(&gn->cohorts); 163 Lst_Init(&gn->parents); 164 Lst_Init(&gn->children); 165 Lst_Init(&gn->successors); 166 Lst_Init(&gn->preds); 167 SymTable_Init(&gn->context); 168 gn->impliedsrc = NULL; 169 Lst_Init(&gn->commands); 170 gn->suffix = NULL; 171 gn->next = NULL; 172 gn->basename = NULL; 173 gn->sibling = gn; 174 gn->groupling = NULL; 175 176 #ifdef STATS_GN_CREATION 177 STAT_GN_COUNT++; 178 #endif 179 180 return gn; 181 } 182 183 GNode * 184 Targ_FindNodei(const char *name, const char *ename, int flags) 185 { 186 uint32_t hv; 187 188 hv = ohash_interval(name, &ename); 189 return Targ_FindNodeih(name, ename, hv, flags); 190 } 191 192 GNode * 193 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags) 194 { 195 GNode *gn; 196 unsigned int slot; 197 198 slot = ohash_lookup_interval(&targets, name, ename, hv); 199 200 gn = ohash_find(&targets, slot); 201 202 if (gn == NULL && (flags & TARG_CREATE)) { 203 gn = Targ_NewGNi(name, ename); 204 ohash_insert(&targets, slot, gn); 205 } 206 207 return gn; 208 } 209 210 void 211 Targ_FindList(Lst nodes, Lst names) 212 { 213 LstNode ln; 214 GNode *gn; 215 char *name; 216 217 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 218 name = (char *)Lst_Datum(ln); 219 gn = Targ_FindNode(name, TARG_CREATE); 220 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 221 * are added to the list in the order in which they were 222 * encountered in the makefile. */ 223 Lst_AtEnd(nodes, gn); 224 if (gn->type & OP_DOUBLEDEP) 225 Lst_Concat(nodes, &gn->cohorts); 226 } 227 } 228 229 bool 230 Targ_Ignore(GNode *gn) 231 { 232 if (ignoreErrors || gn->type & OP_IGNORE) 233 return true; 234 else 235 return false; 236 } 237 238 bool 239 Targ_Silent(GNode *gn) 240 { 241 if (beSilent || gn->type & OP_SILENT) 242 return true; 243 else 244 return false; 245 } 246 247 bool 248 Targ_Precious(GNode *gn) 249 { 250 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP|OP_PHONY))) 251 return true; 252 else 253 return false; 254 } 255 256 void 257 Targ_PrintCmd(void *p) 258 { 259 const struct command *cmd = p; 260 printf("\t%s\n", cmd->string); 261 } 262 263 void 264 Targ_PrintType(int type) 265 { 266 int tbit; 267 268 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 269 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 270 271 type &= ~OP_OPMASK; 272 273 while (type) { 274 tbit = 1 << (ffs(type) - 1); 275 type &= ~tbit; 276 277 switch (tbit) { 278 PRINTBIT(OPTIONAL); 279 PRINTBIT(USE); 280 PRINTBIT(EXEC); 281 PRINTBIT(IGNORE); 282 PRINTBIT(PRECIOUS); 283 PRINTBIT(SILENT); 284 PRINTBIT(MAKE); 285 PRINTBIT(JOIN); 286 PRINTBIT(INVISIBLE); 287 PRINTBIT(NOTMAIN); 288 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 289 case OP_MEMBER: 290 if (DEBUG(TARG)) 291 printf(".MEMBER "); 292 break; 293 PRINTDBIT(ARCHV); 294 } 295 } 296 } 297 298 const char * 299 status_to_string(GNode *gn) 300 { 301 switch (gn->built_status) { 302 case UNKNOWN: 303 return "unknown"; 304 case MADE: 305 return "made"; 306 case UPTODATE: 307 return "up-to-date"; 308 case ERROR: 309 return "error when made"; 310 case ABORTED: 311 return "aborted"; 312 default: 313 return "other status"; 314 } 315 } 316 317 struct ohash * 318 targets_hash() 319 { 320 return &targets; 321 } 322 323 GNode * 324 Targ_FindNodeh(const char *name, size_t n, uint32_t hv, int flags) 325 { 326 return Targ_FindNodeih(name, name + n - 1, hv, flags); 327 } 328