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