xref: /openbsd-src/usr.bin/make/targ.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenPackages$ */
2 /*	$OpenBSD: targ.c,v 1.56 2008/01/29 22:23:10 espie Exp $ */
3 /*	$NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $	*/
4 
5 /*
6  * Copyright (c) 1999 Marc Espie.
7  *
8  * Extensive code changes for the OpenBSD project.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
23  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * Copyright (c) 1988, 1989, 1990, 1993
33  *	The Regents of the University of California.  All rights reserved.
34  * Copyright (c) 1989 by Berkeley Softworks
35  * All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * Adam de Boor.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 
65 /*-
66  * targ.c --
67  *		Target nodes are kept into a hash table.
68  *
69  * Interface:
70  *	Targ_Init		Initialization procedure.
71  *
72  *	Targ_End		Cleanup the module
73  *
74  *	Targ_NewGN		Create a new GNode for the passed target
75  *				(string). The node is *not* placed in the
76  *				hash table, though all its fields are
77  *				initialized.
78  *
79  *	Targ_FindNode		Find the node for a given target, creating
80  *				and storing it if it doesn't exist and the
81  *				flags are right (TARG_CREATE)
82  *
83  *	Targ_FindList		Given a list of names, find nodes for all
84  *				of them, creating nodes if needed.
85  *
86  *	Targ_Ignore		Return true if errors should be ignored when
87  *				creating the given target.
88  *
89  *	Targ_Silent		Return true if we should be silent when
90  *				creating the given target.
91  *
92  *	Targ_Precious		Return true if the target is precious and
93  *				should not be removed if we are interrupted.
94  *
95  * Debugging:
96  *	Targ_PrintGraph 	Print out the entire graphm all variables
97  *				and statistics for the directory cache. Should
98  *				print something for suffixes, too, but...
99  */
100 
101 #include <limits.h>
102 #include <stddef.h>
103 #include <stdio.h>
104 #include <stdint.h>
105 #include <string.h>
106 #include "config.h"
107 #include "defines.h"
108 #include "ohash.h"
109 #include "stats.h"
110 #include "suff.h"
111 #include "var.h"
112 #include "targ.h"
113 #include "memory.h"
114 #include "gnode.h"
115 #include "extern.h"
116 #include "timestamp.h"
117 #include "lst.h"
118 #include "node_int.h"
119 #include "nodehashconsts.h"
120 #ifdef CLEANUP
121 #include <stdlib.h>
122 #endif
123 
124 static struct ohash targets;	/* a hash table of same */
125 struct ohash_info gnode_info = {
126 	offsetof(GNode, name), NULL, hash_alloc, hash_free, element_alloc
127 };
128 
129 static void TargPrintOnlySrc(GNode *);
130 static void TargPrintName(void *);
131 static void TargPrintNode(GNode *, int);
132 #ifdef CLEANUP
133 static LIST allTargets;
134 static void TargFreeGN(void *);
135 #endif
136 #define Targ_FindConstantNode(n, f) Targ_FindNodeh(n, sizeof(n), K_##n, f)
137 
138 
139 GNode *begin_node, *end_node, *interrupt_node, *DEFAULT;
140 
141 void
142 Targ_Init(void)
143 {
144 	/* A small make file already creates 200 targets.  */
145 	ohash_init(&targets, 10, &gnode_info);
146 #ifdef CLEANUP
147 	Lst_Init(&allTargets);
148 #endif
149 	begin_node = Targ_FindConstantNode(NODE_BEGIN, TARG_CREATE);
150 	begin_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
151 	end_node = Targ_FindConstantNode(NODE_END, TARG_CREATE);
152 	end_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
153 	interrupt_node = Targ_FindConstantNode(NODE_INTERRUPT, TARG_CREATE);
154 	interrupt_node->type |= OP_DUMMY | OP_NOTMAIN | OP_NODEFAULT;
155 	DEFAULT = Targ_FindConstantNode(NODE_DEFAULT, TARG_CREATE);
156 	DEFAULT->type |= OP_DUMMY | OP_NOTMAIN| OP_TRANSFORM | OP_NODEFAULT;
157 
158 }
159 
160 #ifdef CLEANUP
161 void
162 Targ_End(void)
163 {
164 	Lst_Every(&allTargets, TargFreeGN);
165 	ohash_delete(&targets);
166 }
167 #endif
168 
169 GNode *
170 Targ_NewGNi(const char *name, const char *ename)
171 {
172 	GNode *gn;
173 
174 	gn = ohash_create_entry(&gnode_info, name, &ename);
175 	gn->path = NULL;
176 	if (name[0] == '-' && name[1] == 'l')
177 		gn->type = OP_LIB;
178 	else
179 		gn->type = 0;
180 
181 	gn->special = SPECIAL_NONE;
182 	gn->unmade = 0;
183 	gn->must_make = false;
184 	gn->built_status = UNKNOWN;
185 	gn->childMade =	false;
186 	gn->order = 0;
187 	ts_set_out_of_date(gn->mtime);
188 	ts_set_out_of_date(gn->cmtime);
189 	Lst_Init(&gn->cohorts);
190 	Lst_Init(&gn->parents);
191 	Lst_Init(&gn->children);
192 	Lst_Init(&gn->successors);
193 	Lst_Init(&gn->preds);
194 	SymTable_Init(&gn->context);
195 	gn->lineno = 0;
196 	gn->fname = NULL;
197 	gn->impliedsrc = NULL;
198 	Lst_Init(&gn->commands);
199 	Lst_Init(&gn->expanded);
200 	gn->suffix = NULL;
201 
202 #ifdef STATS_GN_CREATION
203 	STAT_GN_COUNT++;
204 #endif
205 
206 #ifdef CLEANUP
207 	Lst_AtEnd(&allTargets, gn);
208 #endif
209 	return gn;
210 }
211 
212 #ifdef CLEANUP
213 static void
214 TargFreeGN(void *gnp)
215 {
216 	GNode *gn = (GNode *)gnp;
217 
218 	efree(gn->path);
219 	Lst_Destroy(&gn->cohorts, NOFREE);
220 	Lst_Destroy(&gn->parents, NOFREE);
221 	Lst_Destroy(&gn->children, NOFREE);
222 	Lst_Destroy(&gn->successors, NOFREE);
223 	Lst_Destroy(&gn->preds, NOFREE);
224 	Lst_Destroy(&gn->commands, NOFREE);
225 	SymTable_Destroy(&gn->context);
226 	free(gn);
227 }
228 #endif
229 
230 GNode *
231 Targ_FindNodei(const char *name, const char *ename, int flags)
232 {
233 	uint32_t hv;
234 
235 	hv = ohash_interval(name, &ename);
236 	return Targ_FindNodeih(name, ename, hv, flags);
237 }
238 
239 GNode *
240 Targ_FindNodeih(const char *name, const char *ename, uint32_t hv, int flags)
241 {
242 	GNode *gn;
243 	unsigned int slot;
244 
245 	slot = ohash_lookup_interval(&targets, name, ename, hv);
246 
247 	gn = ohash_find(&targets, slot);
248 
249 	if (gn == NULL && (flags & TARG_CREATE)) {
250 		gn = Targ_NewGNi(name, ename);
251 		ohash_insert(&targets, slot, gn);
252 	}
253 
254 	return gn;
255 }
256 
257 void
258 Targ_FindList(Lst nodes, Lst names)
259 {
260 	LstNode ln;
261 	GNode *gn;
262 	char *name;
263 
264 	for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
265 		name = (char *)Lst_Datum(ln);
266 		gn = Targ_FindNode(name, TARG_CREATE);
267 		/* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
268 		 * are added to the list in the order in which they were
269 		 * encountered in the makefile.  */
270 		Lst_AtEnd(nodes, gn);
271 		if (gn->type & OP_DOUBLEDEP)
272 			Lst_Concat(nodes, &gn->cohorts);
273 	}
274 }
275 
276 bool
277 Targ_Ignore(GNode *gn)
278 {
279 	if (ignoreErrors || gn->type & OP_IGNORE)
280 		return true;
281 	else
282 		return false;
283 }
284 
285 bool
286 Targ_Silent(GNode *gn)
287 {
288 	if (beSilent || gn->type & OP_SILENT)
289 		return true;
290 	else
291 		return false;
292 }
293 
294 bool
295 Targ_Precious(GNode *gn)
296 {
297 	if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
298 		return true;
299 	else
300 		return false;
301 }
302 
303 static void
304 TargPrintName(void *gnp)
305 {
306 	GNode *gn = (GNode *)gnp;
307 	printf("%s ", gn->name);
308 }
309 
310 
311 void
312 Targ_PrintCmd(void *cmd)
313 {
314 	printf("\t%s\n", (char *)cmd);
315 }
316 
317 void
318 Targ_PrintType(int type)
319 {
320 	int    tbit;
321 
322 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
323 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
324 
325 	type &= ~OP_OPMASK;
326 
327 	while (type) {
328 		tbit = 1 << (ffs(type) - 1);
329 		type &= ~tbit;
330 
331 		switch (tbit) {
332 		PRINTBIT(OPTIONAL);
333 		PRINTBIT(USE);
334 		PRINTBIT(EXEC);
335 		PRINTBIT(IGNORE);
336 		PRINTBIT(PRECIOUS);
337 		PRINTBIT(SILENT);
338 		PRINTBIT(MAKE);
339 		PRINTBIT(JOIN);
340 		PRINTBIT(INVISIBLE);
341 		PRINTBIT(NOTMAIN);
342 		PRINTDBIT(LIB);
343 		/*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
344 		case OP_MEMBER:
345 			if (DEBUG(TARG))
346 				printf(".MEMBER ");
347 			break;
348 		PRINTDBIT(ARCHV);
349 		}
350     }
351 }
352 const char *
353 status_to_string(GNode *gn)
354 {
355 	switch (gn->built_status) {
356 	case UNKNOWN:
357 		return "unknown";
358 	case MADE:
359 		return "made";
360 	case UPTODATE:
361 		return "up-to-date";
362 	case ERROR:
363 		return "error when made";
364 	case ABORTED:
365 		return "aborted";
366 	default:
367 		return "other status";
368 	}
369 }
370 
371 static void
372 TargPrintNode(GNode *gn, int pass)
373 {
374 	if (OP_NOP(gn->type))
375 		return;
376 	printf("#\n");
377 	if (pass == 2) {
378 		printf("# %d unmade children\n", gn->unmade);
379 		if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
380 			if (!is_out_of_date(gn->mtime)) {
381 				printf("# last modified %s: %s\n",
382 				      time_to_string(gn->mtime),
383 				      status_to_string(gn));
384 			} else if (gn->built_status != UNKNOWN) {
385 				printf("# non-existent (maybe): %s\n",
386 				    status_to_string(gn));
387 			} else {
388 				printf("# unmade\n");
389 			}
390 		}
391 	}
392 	if (!Lst_IsEmpty(&gn->parents)) {
393 		printf("# parents: ");
394 		Lst_Every(&gn->parents, TargPrintName);
395 		fputc('\n', stdout);
396 	}
397 	if (gn->impliedsrc)
398 		printf("# implied source: %s\n", gn->impliedsrc->name);
399 
400 	printf("%-16s", gn->name);
401 	switch (gn->type & OP_OPMASK) {
402 	case OP_DEPENDS:
403 		printf(": "); break;
404 	case OP_FORCE:
405 		printf("! "); break;
406 	case OP_DOUBLEDEP:
407 		printf(":: "); break;
408 	}
409 	Targ_PrintType(gn->type);
410 	Lst_Every(&gn->children, TargPrintName);
411 	fputc('\n', stdout);
412 	Lst_Every(&gn->commands, Targ_PrintCmd);
413 	printf("\n\n");
414 	if (gn->type & OP_DOUBLEDEP) {
415 		LstNode ln;
416 
417 		for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
418 			TargPrintNode((GNode *)Lst_Datum(ln), pass);
419 	}
420 }
421 
422 static void
423 TargPrintOnlySrc(GNode *gn)
424 {
425 	if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE &&
426 	    !(gn->type & OP_DUMMY))
427 		printf("#\t%s [%s]\n", gn->name,
428 		    gn->path != NULL ? gn->path : gn->name);
429 }
430 
431 void
432 Targ_PrintGraph(int pass)	/* Which pass this is. 1 => no processing
433 				 * 2 => processing done */
434 {
435 	GNode		*gn;
436 	unsigned int	i;
437 
438 	printf("#*** Input graph:\n");
439 	for (gn = ohash_first(&targets, &i); gn != NULL;
440 	    gn = ohash_next(&targets, &i))
441 		TargPrintNode(gn, pass);
442 	printf("\n\n");
443 	printf("#\n#   Files that are only sources:\n");
444 	for (gn = ohash_first(&targets, &i); gn != NULL;
445 	    gn = ohash_next(&targets, &i))
446 		TargPrintOnlySrc(gn);
447 	Var_Dump();
448 	printf("\n");
449 #ifdef DEBUG_DIRECTORY_CACHE
450 	Dir_PrintDirectories();
451 	printf("\n");
452 #endif
453 	Suff_PrintAll();
454 }
455 
456 static char *curdir, *objdir;
457 static size_t curdir_len, objdir_len;
458 
459 void
460 Targ_setdirs(const char *c, const char *o)
461 {
462 	curdir_len = strlen(c);
463 	curdir = emalloc(curdir_len+2);
464 	memcpy(curdir, c, curdir_len);
465 	curdir[curdir_len++] = '/';
466 	curdir[curdir_len] = 0;
467 
468 	objdir_len = strlen(o);
469 	objdir = emalloc(objdir_len+2);
470 	memcpy(objdir, o, objdir_len);
471 	objdir[objdir_len++] = '/';
472 	objdir[objdir_len] = 0;
473 }
474 
475 void
476 look_harder_for_target(GNode *gn)
477 {
478 	GNode *extra, *cgn;
479 	LstNode ln;
480 
481 	if (gn->type & (OP_RESOLVED|OP_PHONY))
482 		return;
483 	gn->type |= OP_RESOLVED;
484 	if (strncmp(gn->name, objdir, objdir_len) == 0) {
485 		extra = Targ_FindNode(gn->name + objdir_len, TARG_NOCREATE);
486 		if (extra != NULL) {
487 			if (Lst_IsEmpty(&gn->commands))
488 				Lst_Concat(&gn->commands, &extra->commands);
489 			for (ln = Lst_First(&extra->children); ln != NULL;
490 			    ln = Lst_Adv(ln)) {
491 				cgn = (GNode *)Lst_Datum(ln);
492 
493 				if (Lst_AddNew(&gn->children, cgn)) {
494 					Lst_AtEnd(&cgn->parents, gn);
495 					gn->unmade++;
496 				}
497 			}
498 		}
499 	}
500 }
501