1 /* $OpenBSD: targ.c,v 1.85 2020/01/26 12:41:21 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 static GNode *Targ_mk_node(const char *, const char *, unsigned int, 126 unsigned char, unsigned int); 127 128 #define Targ_mk_constant(n, type) \ 129 Targ_mk_special_node(n, sizeof(n), K_##n, type, SPECIAL_NONE, 0) 130 131 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT; 132 133 void 134 Targ_Init(void) 135 { 136 /* A small make file already creates 200 targets. */ 137 ohash_init(&targets, 10, &gnode_info); 138 begin_node = Targ_mk_constant(NODE_BEGIN, 139 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 140 end_node = Targ_mk_constant(NODE_END, 141 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 142 interrupt_node = Targ_mk_constant(NODE_INTERRUPT, 143 OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT); 144 DEFAULT = Targ_mk_constant(NODE_DEFAULT, 145 OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT); 146 147 } 148 149 static GNode * 150 Targ_mk_node(const char *name, const char *ename, 151 unsigned int type, unsigned char special, unsigned int special_op) 152 { 153 GNode *gn; 154 155 gn = ohash_create_entry(&gnode_info, name, &ename); 156 gn->path = NULL; 157 gn->type = type; 158 gn->special = special; 159 gn->special_op = special_op; 160 gn->children_left = 0; 161 gn->must_make = false; 162 gn->built_status = UNKNOWN; 163 gn->in_cycle = false; 164 gn->child_rebuilt = false; 165 gn->order = 0; 166 ts_set_out_of_date(gn->mtime); 167 gn->youngest = gn; 168 Lst_Init(&gn->cohorts); 169 Lst_Init(&gn->parents); 170 Lst_Init(&gn->children); 171 Lst_Init(&gn->predecessors); 172 Lst_Init(&gn->successors); 173 SymTable_Init(&gn->localvars); 174 gn->impliedsrc = NULL; 175 Lst_Init(&gn->commands); 176 gn->suffix = NULL; 177 gn->next = NULL; 178 gn->basename = NULL; 179 gn->sibling = gn; 180 gn->groupling = NULL; 181 182 #ifdef STATS_GN_CREATION 183 STAT_GN_COUNT++; 184 #endif 185 186 return gn; 187 } 188 189 GNode * 190 Targ_NewGNi(const char *name, const char *ename) 191 { 192 return Targ_mk_node(name, ename, OP_ZERO, SPECIAL_NONE, 0); 193 } 194 195 GNode * 196 Targ_FindNodei(const char *name, const char *ename, int flags) 197 { 198 uint32_t hv; 199 GNode *gn; 200 unsigned int slot; 201 202 hv = ohash_interval(name, &ename); 203 204 slot = ohash_lookup_interval(&targets, name, ename, hv); 205 206 gn = ohash_find(&targets, slot); 207 208 if (gn == NULL && (flags & TARG_CREATE)) { 209 gn = Targ_NewGNi(name, ename); 210 ohash_insert(&targets, slot, gn); 211 } 212 213 return gn; 214 } 215 216 GNode * 217 Targ_mk_special_node(const char *name, size_t n, uint32_t hv, 218 unsigned int type, unsigned char special, unsigned int special_op) 219 { 220 GNode *gn; 221 unsigned int slot; 222 const char *ename = name + n - 1; 223 224 slot = ohash_lookup_interval(&targets, name, ename, hv); 225 226 assert(ohash_find(&targets, slot) == NULL); 227 228 gn = Targ_mk_node(name, ename, type, special, special_op); 229 ohash_insert(&targets, slot, gn); 230 231 return gn; 232 } 233 234 void 235 Targ_FindList(Lst nodes, Lst names) 236 { 237 LstNode ln; 238 GNode *gn; 239 char *name; 240 241 for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) { 242 name = Lst_Datum(ln); 243 gn = Targ_FindNode(name, TARG_CREATE); 244 /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes 245 * are added to the list in the order in which they were 246 * encountered in the makefile. */ 247 Lst_AtEnd(nodes, gn); 248 if (gn->type & OP_DOUBLEDEP) 249 Lst_Concat(nodes, &gn->cohorts); 250 } 251 } 252 253 bool 254 Targ_Ignore(GNode *gn) 255 { 256 if (ignoreErrors || gn->type & OP_IGNORE) 257 return true; 258 else 259 return false; 260 } 261 262 bool 263 Targ_Silent(GNode *gn) 264 { 265 if (beSilent || gn->type & OP_SILENT) 266 return true; 267 else 268 return false; 269 } 270 271 bool 272 Targ_Precious(GNode *gn) 273 { 274 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP|OP_PHONY))) 275 return true; 276 else 277 return false; 278 } 279 280 bool 281 node_is_real(GNode *gn) 282 { 283 return (gn->type & OP_DUMMY) == 0; 284 } 285 286 void 287 Targ_PrintCmd(void *p) 288 { 289 const struct command *cmd = p; 290 printf("\t%s\n", cmd->string); 291 } 292 293 void 294 Targ_PrintType(int type) 295 { 296 int tbit; 297 298 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 299 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 300 301 type &= ~OP_OPMASK; 302 303 while (type) { 304 tbit = 1 << (ffs(type) - 1); 305 type &= ~tbit; 306 307 switch (tbit) { 308 PRINTBIT(OPTIONAL); 309 PRINTBIT(USE); 310 PRINTBIT(IGNORE); 311 PRINTBIT(PRECIOUS); 312 PRINTBIT(SILENT); 313 PRINTBIT(MAKE); 314 PRINTBIT(INVISIBLE); 315 PRINTBIT(NOTMAIN); 316 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 317 case OP_MEMBER: 318 if (DEBUG(TARG)) 319 printf(".MEMBER "); 320 break; 321 PRINTDBIT(ARCHV); 322 } 323 } 324 } 325 326 const char * 327 status_to_string(GNode *gn) 328 { 329 switch (gn->built_status) { 330 case UNKNOWN: 331 return "unknown"; 332 case REBUILT: 333 return "made"; 334 case UPTODATE: 335 return "up-to-date"; 336 case ERROR: 337 return "error when made"; 338 case ABORTED: 339 return "aborted"; 340 default: 341 return "other status"; 342 } 343 } 344 345 struct ohash * 346 targets_hash() 347 { 348 return &targets; 349 } 350