xref: /openbsd-src/usr.bin/make/targ.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: targ.c,v 1.76 2015/01/23 22:35:58 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 #define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f)
126 
127 
128 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT;
129 
130 void
131 Targ_Init(void)
132 {
133 	/* A small make file already creates 200 targets.  */
134 	ohash_init(&targets, 10, &gnode_info);
135 	begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE);
136 	begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
137 	end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE);
138 	end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
139 	interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE);
140 	interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
141 	DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE);
142 	DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT;
143 
144 }
145 
146 GNode *
147 Targ_NewGNi(const char *name, const char *ename)
148 {
149 	GNode *gn;
150 
151 	gn = ohash_create_entry(&gnode_info, name, &ename);
152 	gn->path = NULL;
153 	gn->type = 0;
154 	gn->special = SPECIAL_NONE;
155 	gn->unmade = 0;
156 	gn->must_make = false;
157 	gn->built_status = UNKNOWN;
158 	gn->childMade =	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->successors);
166 	Lst_Init(&gn->preds);
167 	SymTable_Init(&gn->context);
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_FindNodei(const char *name, const char *ename, int flags)
185 {
186 	uint32_t hv;
187 
188 	hv = ohash_interval(name, &ename);
189 	return Targ_FindNodeih(name, ename, hv, flags);
190 }
191 
192 GNode *
193 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags)
194 {
195 	GNode *gn;
196 	unsigned int slot;
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 void
211 Targ_FindList(Lst nodes, Lst names)
212 {
213 	LstNode ln;
214 	GNode *gn;
215 	char *name;
216 
217 	for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
218 		name = (char *)Lst_Datum(ln);
219 		gn = Targ_FindNode(name, TARG_CREATE);
220 		/* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
221 		 * are added to the list in the order in which they were
222 		 * encountered in the makefile.  */
223 		Lst_AtEnd(nodes, gn);
224 		if (gn->type & OP_DOUBLEDEP)
225 			Lst_Concat(nodes, &gn->cohorts);
226 	}
227 }
228 
229 bool
230 Targ_Ignore(GNode *gn)
231 {
232 	if (ignoreErrors || gn->type & OP_IGNORE)
233 		return true;
234 	else
235 		return false;
236 }
237 
238 bool
239 Targ_Silent(GNode *gn)
240 {
241 	if (beSilent || gn->type & OP_SILENT)
242 		return true;
243 	else
244 		return false;
245 }
246 
247 bool
248 Targ_Precious(GNode *gn)
249 {
250 	if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP|OP_PHONY)))
251 		return true;
252 	else
253 		return false;
254 }
255 
256 void
257 Targ_PrintCmd(void *p)
258 {
259 	const struct command *cmd = p;
260 	printf("\t%s\n", cmd->string);
261 }
262 
263 void
264 Targ_PrintType(int type)
265 {
266 	int    tbit;
267 
268 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
269 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
270 
271 	type &= ~OP_OPMASK;
272 
273 	while (type) {
274 		tbit = 1 << (ffs(type) - 1);
275 		type &= ~tbit;
276 
277 		switch (tbit) {
278 		PRINTBIT(OPTIONAL);
279 		PRINTBIT(USE);
280 		PRINTBIT(EXEC);
281 		PRINTBIT(IGNORE);
282 		PRINTBIT(PRECIOUS);
283 		PRINTBIT(SILENT);
284 		PRINTBIT(MAKE);
285 		PRINTBIT(JOIN);
286 		PRINTBIT(INVISIBLE);
287 		PRINTBIT(NOTMAIN);
288 		/*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
289 		case OP_MEMBER:
290 			if (DEBUG(TARG))
291 				printf(".MEMBER ");
292 			break;
293 		PRINTDBIT(ARCHV);
294 		}
295     }
296 }
297 
298 const char *
299 status_to_string(GNode *gn)
300 {
301 	switch (gn->built_status) {
302 	case UNKNOWN:
303 		return "unknown";
304 	case MADE:
305 		return "made";
306 	case UPTODATE:
307 		return "up-to-date";
308 	case ERROR:
309 		return "error when made";
310 	case ABORTED:
311 		return "aborted";
312 	default:
313 		return "other status";
314 	}
315 }
316 
317 struct ohash *
318 targets_hash()
319 {
320 	return &targets;
321 }
322 
323 GNode *
324 Targ_FindNodeh(const char *name, size_t n, uint32_t hv, int flags)
325 {
326 	return Targ_FindNodeih(name, name + n - 1, hv, flags);
327 }
328