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
Targ_Init(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 *
Targ_mk_node(const char * name,const char * ename,unsigned int type,unsigned char special,unsigned int special_op)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 *
Targ_NewGNi(const char * name,const char * ename)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 *
Targ_FindNodei(const char * name,const char * ename,int flags)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 *
Targ_mk_special_node(const char * name,size_t n,uint32_t hv,unsigned int type,unsigned char special,unsigned int special_op)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
Targ_FindList(Lst nodes,Lst names)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
Targ_Ignore(GNode * gn)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
Targ_Silent(GNode * gn)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
Targ_Precious(GNode * gn)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
node_is_real(GNode * gn)275 node_is_real(GNode *gn)
276 {
277 return (gn->type & OP_DUMMY) == 0;
278 }
279
280 void
Targ_PrintCmd(void * p)281 Targ_PrintCmd(void *p)
282 {
283 const struct command *cmd = p;
284 printf("\t%s\n", cmd->string);
285 }
286
287 void
Targ_PrintType(int type)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 *
status_to_string(GNode * gn)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 *
targets_hash(void)340 targets_hash(void)
341 {
342 return &targets;
343 }
344