xref: /openbsd-src/usr.bin/make/targ.c (revision 799f675f6700f14e59124f9825c723e9f2ce19dc)
1 /*	$OpenPackages$ */
2 /*	$OpenBSD: targ.c,v 1.40 2006/01/20 23:10:19 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 #ifdef CLEANUP
119 #include <stdlib.h>
120 #endif
121 
122 static struct ohash targets;	/* a hash table of same */
123 static struct ohash_info gnode_info = {
124 	offsetof(GNode, name),
125     NULL, hash_alloc, hash_free, element_alloc };
126 
127 static void TargPrintOnlySrc(GNode *);
128 static void TargPrintName(void *);
129 static void TargPrintNode(GNode *, int);
130 #ifdef CLEANUP
131 static LIST allTargets;
132 static void TargFreeGN(void *);
133 #endif
134 
135 /*-
136  *-----------------------------------------------------------------------
137  * Targ_Init --
138  *	Initialize this module
139  *
140  * Side Effects:
141  *	The targets hash table is initialized
142  *-----------------------------------------------------------------------
143  */
144 void
145 Targ_Init(void)
146 {
147     /* A small make file already creates 200 targets.  */
148     ohash_init(&targets, 10, &gnode_info);
149 #ifdef CLEANUP
150     Lst_Init(&allTargets);
151 #endif
152 }
153 
154 /*-
155  *-----------------------------------------------------------------------
156  * Targ_End --
157  *	Finalize this module
158  *
159  * Side Effects:
160  *	All lists and gnodes are cleared
161  *-----------------------------------------------------------------------
162  */
163 #ifdef CLEANUP
164 void
165 Targ_End(void)
166 {
167     Lst_Every(&allTargets, TargFreeGN);
168     ohash_delete(&targets);
169 }
170 #endif
171 
172 /*-
173  *-----------------------------------------------------------------------
174  * Targ_NewGNi  --
175  *	Create and initialize a new graph node
176  *
177  * Results:
178  *	An initialized graph node with the name field filled with a copy
179  *	of the passed name
180  *
181  * Side effect:
182  *	add targets to list of all targets if CLEANUP
183  *-----------------------------------------------------------------------
184  */
185 GNode *
186 Targ_NewGNi(const char *name, /* the name to stick in the new node */
187     const char *ename)
188 {
189     GNode *gn;
190 
191     gn = ohash_create_entry(&gnode_info, name, &ename);
192     gn->path = NULL;
193     if (name[0] == '-' && name[1] == 'l') {
194 	gn->type = OP_LIB;
195     } else {
196 	gn->type = 0;
197     }
198     gn->unmade =	0;
199     gn->make =		false;
200     gn->made =		UNMADE;
201     gn->childMade =	false;
202     gn->order = 	0;
203     ts_set_out_of_date(gn->mtime);
204     ts_set_out_of_date(gn->cmtime);
205     Lst_Init(&gn->iParents);
206     Lst_Init(&gn->cohorts);
207     Lst_Init(&gn->parents);
208     Lst_Init(&gn->children);
209     Lst_Init(&gn->successors);
210     Lst_Init(&gn->preds);
211     SymTable_Init(&gn->context);
212     gn->lineno = 0;
213     gn->fname = NULL;
214     Lst_Init(&gn->commands);
215     gn->suffix =	NULL;
216 
217 #ifdef STATS_GN_CREATION
218     STAT_GN_COUNT++;
219 #endif
220 
221 #ifdef CLEANUP
222     Lst_AtEnd(&allTargets, gn);
223 #endif
224     return gn;
225 }
226 
227 #ifdef CLEANUP
228 /*-
229  *-----------------------------------------------------------------------
230  * TargFreeGN  --
231  *	Destroy a GNode
232  *-----------------------------------------------------------------------
233  */
234 static void
235 TargFreeGN(void *gnp)
236 {
237     GNode *gn = (GNode *)gnp;
238 
239     efree(gn->path);
240     Lst_Destroy(&gn->iParents, NOFREE);
241     Lst_Destroy(&gn->cohorts, NOFREE);
242     Lst_Destroy(&gn->parents, NOFREE);
243     Lst_Destroy(&gn->children, NOFREE);
244     Lst_Destroy(&gn->successors, NOFREE);
245     Lst_Destroy(&gn->preds, NOFREE);
246     Lst_Destroy(&gn->commands, NOFREE);
247     SymTable_Destroy(&gn->context);
248     free(gn);
249 }
250 #endif
251 
252 
253 /*-
254  *-----------------------------------------------------------------------
255  * Targ_FindNodei  --
256  *	Find a node in the list using the given name for matching
257  *
258  * Results:
259  *	The node in the list if it was. If it wasn't, return NULL if
260  *	flags was TARG_NOCREATE or the newly created and initialized node
261  *	if flags was TARG_CREATE
262  *
263  * Side Effects:
264  *	Sometimes a node is created and added to the list
265  *-----------------------------------------------------------------------
266  */
267 GNode *
268 Targ_FindNodei(const char *name, const char *ename,
269     int flags)			/* flags governing events when target not
270 				 * found */
271 {
272     GNode		*gn;	/* node in that element */
273     unsigned int	slot;
274 
275     slot = ohash_qlookupi(&targets, name, &ename);
276 
277     gn = ohash_find(&targets, slot);
278 
279     if (gn == NULL && (flags & TARG_CREATE)) {
280 	gn = Targ_NewGNi(name, ename);
281 	ohash_insert(&targets, slot, gn);
282     }
283 
284     return gn;
285 }
286 
287 /*-
288  *-----------------------------------------------------------------------
289  * Targ_FindList --
290  *	Make a complete list of GNodes from the given list of names
291  *
292  * Side Effects:
293  *	Nodes will be created for all names in names which do not yet have graph
294  *	nodes.
295  *
296  *	A complete list of graph nodes corresponding to all instances of all
297  *	the names in names is added to nodes.
298  * -----------------------------------------------------------------------
299  */
300 void
301 Targ_FindList(Lst nodes, 	/* result list */
302     Lst names) 			/* list of names to find */
303 {
304     LstNode	   ln;		/* name list element */
305     GNode	  *gn;		/* node in tLn */
306     char	  *name;
307 
308     for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
309 	name = (char *)Lst_Datum(ln);
310 	gn = Targ_FindNode(name, TARG_CREATE);
311 	    /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
312 	     * are added to the list in the order in which they were
313 	     * encountered in the makefile.  */
314 	Lst_AtEnd(nodes, gn);
315 	if (gn->type & OP_DOUBLEDEP)
316 	    Lst_Concat(nodes, &gn->cohorts);
317     }
318 }
319 
320 /*-
321  *-----------------------------------------------------------------------
322  * Targ_Ignore	--
323  *	Return true if should ignore errors when creating gn
324  *-----------------------------------------------------------------------
325  */
326 bool
327 Targ_Ignore(GNode *gn)
328 {
329     if (ignoreErrors || gn->type & OP_IGNORE)
330 	return true;
331     else
332 	return false;
333 }
334 
335 /*-
336  *-----------------------------------------------------------------------
337  * Targ_Silent	--
338  *	Return true if be silent when creating gn
339  *-----------------------------------------------------------------------
340  */
341 bool
342 Targ_Silent(GNode *gn)
343 {
344     if (beSilent || gn->type & OP_SILENT)
345 	return true;
346     else
347 	return false;
348 }
349 
350 /*-
351  *-----------------------------------------------------------------------
352  * Targ_Precious --
353  *	See if the given target is precious
354  *-----------------------------------------------------------------------
355  */
356 bool
357 Targ_Precious(GNode *gn)
358 {
359     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
360 	return true;
361     else
362 	return false;
363 }
364 
365 /******************* DEBUG INFO PRINTING ****************/
366 
367 static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
368 /*-
369  *-----------------------------------------------------------------------
370  * Targ_SetMain --
371  *	Set our idea of the main target we'll be creating. Used for
372  *	debugging output.
373  *
374  * Side Effects:
375  *	"mainTarg" is set to the main target's node.
376  *-----------------------------------------------------------------------
377  */
378 void
379 Targ_SetMain(GNode *gn)
380 {
381     mainTarg = gn;
382 }
383 
384 static void
385 TargPrintName(void *gnp)
386 {
387     GNode *gn = (GNode *)gnp;
388     printf("%s ", gn->name);
389 }
390 
391 
392 void
393 Targ_PrintCmd(void *cmd)
394 {
395     printf("\t%s\n", (char *)cmd);
396 }
397 
398 /*-
399  *-----------------------------------------------------------------------
400  * Targ_FmtTime --
401  *	Format a modification time in some reasonable way and return it.
402  *
403  * Results:
404  *	The time reformatted.
405  *
406  * Side Effects:
407  *	The time is placed in a static area, so it is overwritten
408  *	with each call.
409  *-----------------------------------------------------------------------
410  */
411 char *
412 Targ_FmtTime(TIMESTAMP time)
413 {
414     struct tm		*parts;
415     static char 	buf[128];
416     time_t t;
417 
418     t = timestamp2time_t(time);
419 
420     parts = localtime(&t);
421     strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
422     buf[sizeof(buf) - 1] = '\0';
423     return buf;
424 }
425 
426 /*-
427  *-----------------------------------------------------------------------
428  * Targ_PrintType --
429  *	Print out a type field giving only those attributes the user can
430  *	set.
431  *-----------------------------------------------------------------------
432  */
433 void
434 Targ_PrintType(int type)
435 {
436     int    tbit;
437 
438 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
439 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
440 
441     type &= ~OP_OPMASK;
442 
443     while (type) {
444 	tbit = 1 << (ffs(type) - 1);
445 	type &= ~tbit;
446 
447 	switch (tbit) {
448 	    PRINTBIT(OPTIONAL);
449 	    PRINTBIT(USE);
450 	    PRINTBIT(EXEC);
451 	    PRINTBIT(IGNORE);
452 	    PRINTBIT(PRECIOUS);
453 	    PRINTBIT(SILENT);
454 	    PRINTBIT(MAKE);
455 	    PRINTBIT(JOIN);
456 	    PRINTBIT(INVISIBLE);
457 	    PRINTBIT(NOTMAIN);
458 	    PRINTDBIT(LIB);
459 	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
460 	    case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
461 	    PRINTDBIT(ARCHV);
462 	}
463     }
464 }
465 
466 /*-
467  *-----------------------------------------------------------------------
468  * TargPrintNode --
469  *	print the contents of a node
470  *-----------------------------------------------------------------------
471  */
472 static void
473 TargPrintNode(GNode *gn, int pass)
474 {
475     if (!OP_NOP(gn->type)) {
476 	printf("#\n");
477 	if (gn == mainTarg) {
478 	    printf("# *** MAIN TARGET ***\n");
479 	}
480 	if (pass == 2) {
481 	    if (gn->unmade) {
482 		printf("# %d unmade children\n", gn->unmade);
483 	    } else {
484 		printf("# No unmade children\n");
485 	    }
486 	    if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
487 		if (!is_out_of_date(gn->mtime)) {
488 		    printf("# last modified %s: %s\n",
489 			      Targ_FmtTime(gn->mtime),
490 			      (gn->made == UNMADE ? "unmade" :
491 			       (gn->made == MADE ? "made" :
492 				(gn->made == UPTODATE ? "up-to-date" :
493 				 "error when made"))));
494 		} else if (gn->made != UNMADE) {
495 		    printf("# non-existent (maybe): %s\n",
496 			      (gn->made == MADE ? "made" :
497 			       (gn->made == UPTODATE ? "up-to-date" :
498 				(gn->made == ERROR ? "error when made" :
499 				 "aborted"))));
500 		} else {
501 		    printf("# unmade\n");
502 		}
503 	    }
504 	    if (!Lst_IsEmpty(&gn->iParents)) {
505 		printf("# implicit parents: ");
506 		Lst_Every(&gn->iParents, TargPrintName);
507 		fputc('\n', stdout);
508 	    }
509 	}
510 	if (!Lst_IsEmpty(&gn->parents)) {
511 	    printf("# parents: ");
512 	    Lst_Every(&gn->parents, TargPrintName);
513 	    fputc('\n', stdout);
514 	}
515 
516 	printf("%-16s", gn->name);
517 	switch (gn->type & OP_OPMASK) {
518 	    case OP_DEPENDS:
519 		printf(": "); break;
520 	    case OP_FORCE:
521 		printf("! "); break;
522 	    case OP_DOUBLEDEP:
523 		printf(":: "); break;
524 	}
525 	Targ_PrintType(gn->type);
526 	Lst_Every(&gn->children, TargPrintName);
527 	fputc('\n', stdout);
528 	Lst_Every(&gn->commands, Targ_PrintCmd);
529 	printf("\n\n");
530 	if (gn->type & OP_DOUBLEDEP) {
531 	    LstNode ln;
532 
533 	    for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
534 		    TargPrintNode((GNode *)Lst_Datum(ln), pass);
535 	}
536     }
537 }
538 
539 /*-
540  *-----------------------------------------------------------------------
541  * TargPrintOnlySrc --
542  *	Print targets that are just a source.
543  *-----------------------------------------------------------------------
544  */
545 static void
546 TargPrintOnlySrc(GNode *gn)
547 {
548     if (OP_NOP(gn->type))
549 	printf("#\t%s [%s]\n", gn->name,
550 	    gn->path != NULL ? gn->path : gn->name);
551 }
552 
553 /*-
554  *-----------------------------------------------------------------------
555  * Targ_PrintGraph --
556  *	print the entire graph.
557  *-----------------------------------------------------------------------
558  */
559 void
560 Targ_PrintGraph(int pass)	/* Which pass this is. 1 => no processing
561 				 * 2 => processing done */
562 {
563     GNode		*gn;
564     unsigned int	i;
565 
566     printf("#*** Input graph:\n");
567     for (gn = ohash_first(&targets, &i); gn != NULL;
568 	gn = ohash_next(&targets, &i))
569 	    TargPrintNode(gn, pass);
570     printf("\n\n");
571     printf("#\n#   Files that are only sources:\n");
572     for (gn = ohash_first(&targets, &i); gn != NULL;
573 	gn = ohash_next(&targets, &i))
574 		TargPrintOnlySrc(gn);
575     Var_Dump();
576     printf("\n");
577 #ifdef DEBUG_DIRECTORY_CACHE
578     Dir_PrintDirectories();
579     printf("\n");
580 #endif
581     Suff_PrintAll();
582 }
583