1 /* $OpenBSD: targ.c,v 1.88 2024/06/18 02:11:03 millert 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 93 #include <limits.h> 94 #include <stddef.h> 95 #include <stdint.h> 96 #include <stdio.h> 97 #include <stdlib.h> 98 #include <string.h> 99 #include <ohash.h> 100 #include "defines.h" 101 #include "stats.h" 102 #include "suff.h" 103 #include "var.h" 104 #include "targ.h" 105 #include "memory.h" 106 #include "gnode.h" 107 #include "extern.h" 108 #include "timestamp.h" 109 #include "lst.h" 110 #include "node_int.h" 111 #include "nodehashconsts.h" 112 #include "dump.h" 113 114 static struct ohash targets; /* hash table of targets */ 115 struct ohash_info gnode_info = { 116 offsetof(GNode, name), NULL, hash_calloc, hash_free, element_alloc 117 }; 118 119 static GNode *Targ_mk_node(const char *, const char *, unsigned int, 120 unsigned char, unsigned int); 121 122 #define Targ_mk_constant(n, type) \ 123 Targ_mk_special_node(n, sizeof(n), K_##n, type, SPECIAL_NONE, 0) 124 125 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; 126 127 void 128 Targ_Init(void) 129 { 130 /* A small make file already creates 200 targets. */ 131 ohash_init(&targets, 10, &gnode_info); 132 begin_node = Targ_mk_constant(NODE_BEGIN, 133 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 134 end_node = Targ_mk_constant(NODE_END, 135 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 136 interrupt_node = Targ_mk_constant(NODE_INTERRUPT, 137 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 138 DEFAULT = Targ_mk_constant(NODE_DEFAULT, 139 OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT); 140 141 } 142 143 static GNode * 144 Targ_mk_node(const char *name, const char *ename, 145 unsigned int type, unsigned char special, unsigned int special_op) 146 { 147 GNode *gn; 148 149 gn = ohash_create_entry(&gnode_info, name, &ename); 150 gn->path = NULL; 151 gn->type = type; 152 gn->special = special; 153 gn->special_op = special_op; 154 gn->children_left = 0; 155 gn->must_make = false; 156 gn->built_status = UNKNOWN; 157 gn->in_cycle = false; 158 gn->child_rebuilt = 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->predecessors); 166 Lst_Init(&gn->successors); 167 SymTable_Init(&gn->localvars); 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_NewGNi(const char *name, const char *ename) 185 { 186 return Targ_mk_node(name, ename, OP_ZERO, SPECIAL_NONE, 0); 187 } 188 189 GNode * 190 Targ_FindNodei(const char *name, const char *ename, int flags) 191 { 192 uint32_t hv; 193 GNode *gn; 194 unsigned int slot; 195 196 hv = ohash_interval(name, &ename); 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 GNode * 211 Targ_mk_special_node(const char *name, size_t n, uint32_t hv, 212 unsigned int type, unsigned char special, unsigned int special_op) 213 { 214 GNode *gn; 215 unsigned int slot; 216 const char *ename = name + n - 1; 217 218 slot = ohash_lookup_interval(&targets, name, ename, hv); 219 220 assert(ohash_find(&targets, slot) == NULL); 221 222 gn = Targ_mk_node(name, ename, type, special, special_op); 223 ohash_insert(&targets, slot, gn); 224 225 return gn; 226 } 227 228 void 229 Targ_FindList(Lst nodes, Lst names) 230 { 231 LstNode ln; 232 GNode *gn; 233 char *name; 234 235 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 236 name = Lst_Datum(ln); 237 gn = Targ_FindNode(name, TARG_CREATE); 238 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 239 * are added to the list in the order in which they were 240 * encountered in the makefile. */ 241 Lst_AtEnd(nodes, gn); 242 if (gn->type & OP_DOUBLEDEP) 243 Lst_Concat(nodes, &gn->cohorts); 244 } 245 } 246 247 bool 248 Targ_Ignore(GNode *gn) 249 { 250 if (ignoreErrors || gn->type & OP_IGNORE) 251 return true; 252 else 253 return false; 254 } 255 256 bool 257 Targ_Silent(GNode *gn) 258 { 259 if (beSilent || gn->type & OP_SILENT) 260 return true; 261 else 262 return false; 263 } 264 265 bool 266 Targ_Precious(GNode *gn) 267 { 268 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP|OP_PHONY))) 269 return true; 270 else 271 return false; 272 } 273 274 bool 275 node_is_real(GNode *gn) 276 { 277 return (gn->type & OP_DUMMY) == 0; 278 } 279 280 void 281 Targ_PrintCmd(void *p) 282 { 283 const struct command *cmd = p; 284 printf("\t%s\n", cmd->string); 285 } 286 287 void 288 Targ_PrintType(int type) 289 { 290 int tbit; 291 292 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 293 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 294 295 type &= ~OP_OPMASK; 296 297 while (type) { 298 tbit = 1 << (ffs(type) - 1); 299 type &= ~tbit; 300 301 switch (tbit) { 302 PRINTBIT(OPTIONAL); 303 PRINTBIT(USE); 304 PRINTBIT(IGNORE); 305 PRINTBIT(PRECIOUS); 306 PRINTBIT(SILENT); 307 PRINTBIT(MAKE); 308 PRINTBIT(INVISIBLE); 309 PRINTBIT(NOTMAIN); 310 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 311 case OP_MEMBER: 312 if (DEBUG(TARG)) 313 printf(".MEMBER "); 314 break; 315 PRINTDBIT(ARCHV); 316 } 317 } 318 } 319 320 const char * 321 status_to_string(GNode *gn) 322 { 323 switch (gn->built_status) { 324 case UNKNOWN: 325 return "unknown"; 326 case REBUILT: 327 return "made"; 328 case UPTODATE: 329 return "up-to-date"; 330 case ERROR: 331 return "error when made"; 332 case ABORTED: 333 return "aborted"; 334 default: 335 return "other status"; 336 } 337 } 338 339 struct ohash * 340 targets_hash(void) 341 { 342 return &targets; 343 } 344