xref: /openbsd/usr.bin/make/targ.c (revision 7e30afce)
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