xref: /openbsd-src/usr.bin/make/targ.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenPackages$ */
2 /*	$OpenBSD: targ.c,v 1.34 2001/05/29 12:53:43 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. All advertising materials mentioning features or use of this software
49  *    must display the following acknowledgement:
50  *	This product includes software developed by the University of
51  *	California, Berkeley and its contributors.
52  * 4. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  */
68 
69 /*-
70  * targ.c --
71  *		Target nodes are kept into a hash table.
72  *
73  * Interface:
74  *	Targ_Init		Initialization procedure.
75  *
76  *	Targ_End		Cleanup the module
77  *
78  *	Targ_NewGN		Create a new GNode for the passed target
79  *				(string). The node is *not* placed in the
80  *				hash table, though all its fields are
81  *				initialized.
82  *
83  *	Targ_FindNode		Find the node for a given target, creating
84  *				and storing it if it doesn't exist and the
85  *				flags are right (TARG_CREATE)
86  *
87  *	Targ_FindList		Given a list of names, find nodes for all
88  *				of them, creating nodes if needed.
89  *
90  *	Targ_Ignore		Return true if errors should be ignored when
91  *				creating the given target.
92  *
93  *	Targ_Silent		Return true if we should be silent when
94  *				creating the given target.
95  *
96  *	Targ_Precious		Return true if the target is precious and
97  *				should not be removed if we are interrupted.
98  *
99  * Debugging:
100  *	Targ_PrintGraph 	Print out the entire graphm all variables
101  *				and statistics for the directory cache. Should
102  *				print something for suffixes, too, but...
103  */
104 
105 #include <sys/types.h>
106 #include <limits.h>
107 #include <stddef.h>
108 #include <stdio.h>
109 #include <string.h>
110 #include "config.h"
111 #include "defines.h"
112 #include "ohash.h"
113 #include "stats.h"
114 #include "suff.h"
115 #include "var.h"
116 #include "targ.h"
117 #include "memory.h"
118 #include "gnode.h"
119 #include "extern.h"
120 #include "timestamp.h"
121 #include "lst.h"
122 
123 static struct ohash targets;	/* a hash table of same */
124 static struct ohash_info gnode_info = {
125 	offsetof(GNode, name),
126     NULL, hash_alloc, hash_free, element_alloc };
127 
128 static void TargPrintOnlySrc(GNode *);
129 static void TargPrintName(void *);
130 static void TargPrintNode(GNode *, int);
131 #ifdef CLEANUP
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()
146 {
147     /* A small make file already creates 200 targets.  */
148     ohash_init(&targets, 10, &gnode_info);
149 }
150 
151 /*-
152  *-----------------------------------------------------------------------
153  * Targ_End --
154  *	Finalize this module
155  *
156  * Side Effects:
157  *	All lists and gnodes are cleared
158  *-----------------------------------------------------------------------
159  */
160 #ifdef CLEANUP
161 void
162 Targ_End()
163 {
164     unsigned int i;
165     GNode *n;
166 
167      for (n = ohash_first(&targets, &i); n != NULL; n = ohash_next(&targets, &i))
168      	TargFreeGN(n);
169 
170     ohash_delete(&targets);
171 }
172 #endif
173 
174 /*-
175  *-----------------------------------------------------------------------
176  * Targ_NewGNi  --
177  *	Create and initialize a new graph node
178  *
179  * Results:
180  *	An initialized graph node with the name field filled with a copy
181  *	of the passed name
182  *
183  * Side Effects:
184  *	The gnode is added to the list of all gnodes.
185  *-----------------------------------------------------------------------
186  */
187 GNode *
188 Targ_NewGNi(name, end)
189     const char	*name;	/* the name to stick in the new node */
190     const char	*end;
191 {
192     GNode *gn;
193 
194     gn = ohash_create_entry(&gnode_info, name, &end);
195     gn->path = NULL;
196     if (name[0] == '-' && name[1] == 'l') {
197 	gn->type = OP_LIB;
198     } else {
199 	gn->type = 0;
200     }
201     gn->unmade =	0;
202     gn->make =		false;
203     gn->made =		UNMADE;
204     gn->childMade =	false;
205     gn->order = 	0;
206     ts_set_out_of_date(gn->mtime);
207     ts_set_out_of_date(gn->cmtime);
208     Lst_Init(&gn->iParents);
209     Lst_Init(&gn->cohorts);
210     Lst_Init(&gn->parents);
211     Lst_Init(&gn->children);
212     Lst_Init(&gn->successors);
213     Lst_Init(&gn->preds);
214     SymTable_Init(&gn->context);
215     gn->lineno = 0;
216     gn->fname = NULL;
217     Lst_Init(&gn->commands);
218     gn->suffix =	NULL;
219 
220 #ifdef STATS_GN_CREATION
221     STAT_GN_COUNT++;
222 #endif
223 
224     return gn;
225 }
226 
227 #ifdef CLEANUP
228 /*-
229  *-----------------------------------------------------------------------
230  * TargFreeGN  --
231  *	Destroy a GNode
232  *-----------------------------------------------------------------------
233  */
234 static void
235 TargFreeGN(gnp)
236     void *gnp;
237 {
238     GNode *gn = (GNode *)gnp;
239 
240     efree(gn->path);
241     Lst_Destroy(&gn->iParents, NOFREE);
242     Lst_Destroy(&gn->cohorts, NOFREE);
243     Lst_Destroy(&gn->parents, NOFREE);
244     Lst_Destroy(&gn->children, NOFREE);
245     Lst_Destroy(&gn->successors, NOFREE);
246     Lst_Destroy(&gn->preds, NOFREE);
247     Lst_Destroy(&gn->commands, NOFREE);
248     SymTable_Destroy(&gn->context);
249     free(gn);
250 }
251 #endif
252 
253 
254 /*-
255  *-----------------------------------------------------------------------
256  * Targ_FindNodei  --
257  *	Find a node in the list using the given name for matching
258  *
259  * Results:
260  *	The node in the list if it was. If it wasn't, return NULL if
261  *	flags was TARG_NOCREATE or the newly created and initialized node
262  *	if flags was TARG_CREATE
263  *
264  * Side Effects:
265  *	Sometimes a node is created and added to the list
266  *-----------------------------------------------------------------------
267  */
268 GNode *
269 Targ_FindNodei(name, end, flags)
270     const char		*name;	/* the name to find */
271     const char		*end;
272     int 		flags;	/* flags governing events when target not
273 				 * found */
274 {
275     GNode		*gn;	/* node in that element */
276     unsigned int	slot;
277 
278     slot = ohash_qlookupi(&targets, name, &end);
279 
280     gn = ohash_find(&targets, slot);
281 
282     if (gn == NULL && (flags & TARG_CREATE)) {
283 	gn = Targ_NewGNi(name, end);
284 	ohash_insert(&targets, slot, gn);
285     }
286 
287     return gn;
288 }
289 
290 /*-
291  *-----------------------------------------------------------------------
292  * Targ_FindList --
293  *	Make a complete list of GNodes from the given list of names
294  *
295  * Side Effects:
296  *	Nodes will be created for all names in names which do not yet have graph
297  *	nodes.
298  *
299  *	A complete list of graph nodes corresponding to all instances of all
300  *	the names in names is added to nodes.
301  * -----------------------------------------------------------------------
302  */
303 void
304 Targ_FindList(nodes, names)
305     Lst 	   nodes;	/* result list */
306     Lst 	   names;	/* list of names to find */
307 {
308     LstNode	   ln;		/* name list element */
309     GNode	  *gn;		/* node in tLn */
310     char	  *name;
311 
312     for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
313 	name = (char *)Lst_Datum(ln);
314 	gn = Targ_FindNode(name, TARG_CREATE);
315 	    /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
316 	     * are added to the list in the order in which they were
317 	     * encountered in the makefile.  */
318 	Lst_AtEnd(nodes, gn);
319 	if (gn->type & OP_DOUBLEDEP)
320 	    Lst_Concat(nodes, &gn->cohorts);
321     }
322 }
323 
324 /*-
325  *-----------------------------------------------------------------------
326  * Targ_Ignore	--
327  *	Return true if should ignore errors when creating gn
328  *-----------------------------------------------------------------------
329  */
330 bool
331 Targ_Ignore(gn)
332     GNode	   *gn; 	/* node to check for */
333 {
334     if (ignoreErrors || gn->type & OP_IGNORE)
335 	return true;
336     else
337 	return false;
338 }
339 
340 /*-
341  *-----------------------------------------------------------------------
342  * Targ_Silent	--
343  *	Return true if be silent when creating gn
344  *-----------------------------------------------------------------------
345  */
346 bool
347 Targ_Silent(gn)
348     GNode	   *gn; 	/* node to check for */
349 {
350     if (beSilent || gn->type & OP_SILENT)
351 	return true;
352     else
353 	return false;
354 }
355 
356 /*-
357  *-----------------------------------------------------------------------
358  * Targ_Precious --
359  *	See if the given target is precious
360  *-----------------------------------------------------------------------
361  */
362 bool
363 Targ_Precious(gn)
364     GNode	   *gn; 	/* the node to check */
365 {
366     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
367 	return true;
368     else
369 	return false;
370 }
371 
372 /******************* DEBUG INFO PRINTING ****************/
373 
374 static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
375 /*-
376  *-----------------------------------------------------------------------
377  * Targ_SetMain --
378  *	Set our idea of the main target we'll be creating. Used for
379  *	debugging output.
380  *
381  * Side Effects:
382  *	"mainTarg" is set to the main target's node.
383  *-----------------------------------------------------------------------
384  */
385 void
386 Targ_SetMain(gn)
387     GNode   *gn;	/* The main target we'll create */
388 {
389     mainTarg = gn;
390 }
391 
392 static void
393 TargPrintName(gnp)
394     void *gnp;
395 {
396     GNode *gn = (GNode *)gnp;
397     printf("%s ", gn->name);
398 }
399 
400 
401 void
402 Targ_PrintCmd(cmd)
403     void *cmd;
404 {
405     printf("\t%s\n", (char *)cmd);
406 }
407 
408 /*-
409  *-----------------------------------------------------------------------
410  * Targ_FmtTime --
411  *	Format a modification time in some reasonable way and return it.
412  *
413  * Results:
414  *	The time reformatted.
415  *
416  * Side Effects:
417  *	The time is placed in a static area, so it is overwritten
418  *	with each call.
419  *-----------------------------------------------------------------------
420  */
421 char *
422 Targ_FmtTime(time)
423     TIMESTAMP	 time;
424 {
425     struct tm		*parts;
426     static char 	buf[128];
427     time_t t;
428 
429     t = timestamp2time_t(time);
430 
431     parts = localtime(&t);
432     strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
433     buf[sizeof(buf) - 1] = '\0';
434     return buf;
435 }
436 
437 /*-
438  *-----------------------------------------------------------------------
439  * Targ_PrintType --
440  *	Print out a type field giving only those attributes the user can
441  *	set.
442  *-----------------------------------------------------------------------
443  */
444 void
445 Targ_PrintType(type)
446     int    type;
447 {
448     int    tbit;
449 
450 #ifdef __STDC__
451 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
452 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
453 #else
454 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf(".attr "); break
455 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
456 #endif /* __STDC__ */
457 
458     type &= ~OP_OPMASK;
459 
460     while (type) {
461 	tbit = 1 << (ffs(type) - 1);
462 	type &= ~tbit;
463 
464 	switch (tbit) {
465 	    PRINTBIT(OPTIONAL);
466 	    PRINTBIT(USE);
467 	    PRINTBIT(EXEC);
468 	    PRINTBIT(IGNORE);
469 	    PRINTBIT(PRECIOUS);
470 	    PRINTBIT(SILENT);
471 	    PRINTBIT(MAKE);
472 	    PRINTBIT(JOIN);
473 	    PRINTBIT(INVISIBLE);
474 	    PRINTBIT(NOTMAIN);
475 	    PRINTDBIT(LIB);
476 	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
477 	    case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
478 	    PRINTDBIT(ARCHV);
479 	}
480     }
481 }
482 
483 /*-
484  *-----------------------------------------------------------------------
485  * TargPrintNode --
486  *	print the contents of a node
487  *-----------------------------------------------------------------------
488  */
489 static void
490 TargPrintNode(gn, pass)
491     GNode	  *gn;
492     int 	  pass;
493 {
494     if (!OP_NOP(gn->type)) {
495 	printf("#\n");
496 	if (gn == mainTarg) {
497 	    printf("# *** MAIN TARGET ***\n");
498 	}
499 	if (pass == 2) {
500 	    if (gn->unmade) {
501 		printf("# %d unmade children\n", gn->unmade);
502 	    } else {
503 		printf("# No unmade children\n");
504 	    }
505 	    if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
506 		if (!is_out_of_date(gn->mtime)) {
507 		    printf("# last modified %s: %s\n",
508 			      Targ_FmtTime(gn->mtime),
509 			      (gn->made == UNMADE ? "unmade" :
510 			       (gn->made == MADE ? "made" :
511 				(gn->made == UPTODATE ? "up-to-date" :
512 				 "error when made"))));
513 		} else if (gn->made != UNMADE) {
514 		    printf("# non-existent (maybe): %s\n",
515 			      (gn->made == MADE ? "made" :
516 			       (gn->made == UPTODATE ? "up-to-date" :
517 				(gn->made == ERROR ? "error when made" :
518 				 "aborted"))));
519 		} else {
520 		    printf("# unmade\n");
521 		}
522 	    }
523 	    if (!Lst_IsEmpty(&gn->iParents)) {
524 		printf("# implicit parents: ");
525 		Lst_Every(&gn->iParents, TargPrintName);
526 		fputc('\n', stdout);
527 	    }
528 	}
529 	if (!Lst_IsEmpty(&gn->parents)) {
530 	    printf("# parents: ");
531 	    Lst_Every(&gn->parents, TargPrintName);
532 	    fputc('\n', stdout);
533 	}
534 
535 	printf("%-16s", gn->name);
536 	switch (gn->type & OP_OPMASK) {
537 	    case OP_DEPENDS:
538 		printf(": "); break;
539 	    case OP_FORCE:
540 		printf("! "); break;
541 	    case OP_DOUBLEDEP:
542 		printf(":: "); break;
543 	}
544 	Targ_PrintType(gn->type);
545 	Lst_Every(&gn->children, TargPrintName);
546 	fputc('\n', stdout);
547 	Lst_Every(&gn->commands, Targ_PrintCmd);
548 	printf("\n\n");
549 	if (gn->type & OP_DOUBLEDEP) {
550 	    LstNode ln;
551 
552 	    for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
553 		    TargPrintNode((GNode *)Lst_Datum(ln), pass);
554 	}
555     }
556 }
557 
558 /*-
559  *-----------------------------------------------------------------------
560  * TargPrintOnlySrc --
561  *	Print targets that are just a source.
562  *-----------------------------------------------------------------------
563  */
564 static void
565 TargPrintOnlySrc(gn)
566     GNode *gn;
567 {
568     if (OP_NOP(gn->type))
569 	printf("#\t%s [%s]\n", gn->name,
570 	    gn->path != NULL ? gn->path : gn->name);
571 }
572 
573 /*-
574  *-----------------------------------------------------------------------
575  * Targ_PrintGraph --
576  *	print the entire graph.
577  *-----------------------------------------------------------------------
578  */
579 void
580 Targ_PrintGraph(pass)
581     int 		pass;	/* Which pass this is. 1 => no processing
582 				 * 2 => processing done */
583 {
584     GNode		*gn;
585     unsigned int	i;
586 
587     printf("#*** Input graph:\n");
588     for (gn = ohash_first(&targets, &i); gn != NULL;
589 	gn = ohash_next(&targets, &i))
590 	    TargPrintNode(gn, pass);
591     printf("\n\n");
592     printf("#\n#   Files that are only sources:\n");
593     for (gn = ohash_first(&targets, &i); gn != NULL;
594 	gn = ohash_next(&targets, &i))
595 		TargPrintOnlySrc(gn);
596     Var_Dump();
597     printf("\n");
598 #ifdef DEBUG_DIRECTORY_CACHE
599     Dir_PrintDirectories();
600     printf("\n");
601 #endif
602     Suff_PrintAll();
603 }
604