xref: /netbsd-src/usr.bin/make/targ.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Adam de Boor.
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  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1989 by Berkeley Softworks
37  * All rights reserved.
38  *
39  * This code is derived from software contributed to Berkeley by
40  * Adam de Boor.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *	This product includes software developed by the University of
53  *	California, Berkeley and its contributors.
54  * 4. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  */
70 
71 #ifndef MAKE_NATIVE
72 static char rcsid[] = "$NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $";
73 #else
74 #include <sys/cdefs.h>
75 #ifndef lint
76 #if 0
77 static char sccsid[] = "@(#)targ.c	8.2 (Berkeley) 3/19/94";
78 #else
79 __RCSID("$NetBSD: targ.c,v 1.42 2006/02/26 22:45:46 apb Exp $");
80 #endif
81 #endif /* not lint */
82 #endif
83 
84 /*-
85  * targ.c --
86  *	Functions for maintaining the Lst allTargets. Target nodes are
87  * kept in two structures: a Lst, maintained by the list library, and a
88  * hash table, maintained by the hash library.
89  *
90  * Interface:
91  *	Targ_Init 	    	Initialization procedure.
92  *
93  *	Targ_End 	    	Cleanup the module
94  *
95  *	Targ_List 	    	Return the list of all targets so far.
96  *
97  *	Targ_NewGN	    	Create a new GNode for the passed target
98  *	    	  	    	(string). The node is *not* placed in the
99  *	    	  	    	hash table, though all its fields are
100  *	    	  	    	initialized.
101  *
102  *	Targ_FindNode	    	Find the node for a given target, creating
103  *	    	  	    	and storing it if it doesn't exist and the
104  *	    	  	    	flags are right (TARG_CREATE)
105  *
106  *	Targ_FindList	    	Given a list of names, find nodes for all
107  *	    	  	    	of them. If a name doesn't exist and the
108  *	    	  	    	TARG_NOCREATE flag was given, an error message
109  *	    	  	    	is printed. Else, if a name doesn't exist,
110  *	    	  	    	its node is created.
111  *
112  *	Targ_Ignore	    	Return TRUE if errors should be ignored when
113  *	    	  	    	creating the given target.
114  *
115  *	Targ_Silent	    	Return TRUE if we should be silent when
116  *	    	  	    	creating the given target.
117  *
118  *	Targ_Precious	    	Return TRUE if the target is precious and
119  *	    	  	    	should not be removed if we are interrupted.
120  *
121  *	Targ_Propagate		Propagate information between related
122  *				nodes.	Should be called after the
123  *				makefiles are parsed but before any
124  *				action is taken.
125  *
126  * Debugging:
127  *	Targ_PrintGraph	    	Print out the entire graphm all variables
128  *	    	  	    	and statistics for the directory cache. Should
129  *	    	  	    	print something for suffixes, too, but...
130  */
131 
132 #include	  <stdio.h>
133 #include	  <time.h>
134 
135 #include	  "make.h"
136 #include	  "hash.h"
137 #include	  "dir.h"
138 
139 static Lst        allTargets;	/* the list of all targets found so far */
140 #ifdef CLEANUP
141 static Lst	  allGNs;	/* List of all the GNodes */
142 #endif
143 static Hash_Table targets;	/* a hash table of same */
144 
145 #define HTSIZE	191		/* initial size of hash table */
146 
147 static int TargPrintOnlySrc(ClientData, ClientData);
148 static int TargPrintName(ClientData, ClientData);
149 #ifdef CLEANUP
150 static void TargFreeGN(ClientData);
151 #endif
152 static int TargPropagateCohort(ClientData, ClientData);
153 static int TargPropagateNode(ClientData, ClientData);
154 
155 /*-
156  *-----------------------------------------------------------------------
157  * Targ_Init --
158  *	Initialize this module
159  *
160  * Results:
161  *	None
162  *
163  * Side Effects:
164  *	The allTargets list and the targets hash table are initialized
165  *-----------------------------------------------------------------------
166  */
167 void
168 Targ_Init(void)
169 {
170     allTargets = Lst_Init(FALSE);
171     Hash_InitTable(&targets, HTSIZE);
172 }
173 
174 /*-
175  *-----------------------------------------------------------------------
176  * Targ_End --
177  *	Finalize this module
178  *
179  * Results:
180  *	None
181  *
182  * Side Effects:
183  *	All lists and gnodes are cleared
184  *-----------------------------------------------------------------------
185  */
186 void
187 Targ_End(void)
188 {
189 #ifdef CLEANUP
190     Lst_Destroy(allTargets, NOFREE);
191     if (allGNs)
192 	Lst_Destroy(allGNs, TargFreeGN);
193     Hash_DeleteTable(&targets);
194 #endif
195 }
196 
197 /*-
198  *-----------------------------------------------------------------------
199  * Targ_List --
200  *	Return the list of all targets
201  *
202  * Results:
203  *	The list of all targets.
204  *
205  * Side Effects:
206  *	None
207  *-----------------------------------------------------------------------
208  */
209 Lst
210 Targ_List(void)
211 {
212     return allTargets;
213 }
214 
215 /*-
216  *-----------------------------------------------------------------------
217  * Targ_NewGN  --
218  *	Create and initialize a new graph node
219  *
220  * Input:
221  *	name		the name to stick in the new node
222  *
223  * Results:
224  *	An initialized graph node with the name field filled with a copy
225  *	of the passed name
226  *
227  * Side Effects:
228  *	The gnode is added to the list of all gnodes.
229  *-----------------------------------------------------------------------
230  */
231 GNode *
232 Targ_NewGN(const char *name)
233 {
234     GNode *gn;
235 
236     gn = emalloc(sizeof(GNode));
237     gn->name = estrdup(name);
238     gn->uname = NULL;
239     gn->path = NULL;
240     if (name[0] == '-' && name[1] == 'l') {
241 	gn->type = OP_LIB;
242     } else {
243 	gn->type = 0;
244     }
245     gn->unmade =    	0;
246     gn->unmade_cohorts = 0;
247     gn->centurion =    	NULL;
248     gn->made = 	    	UNMADE;
249     gn->flags = 	0;
250     gn->order =		0;
251     gn->mtime = gn->cmtime = 0;
252     gn->iParents =  	Lst_Init(FALSE);
253     gn->cohorts =   	Lst_Init(FALSE);
254     gn->parents =   	Lst_Init(FALSE);
255     gn->ancestors =   	Lst_Init(FALSE);
256     gn->children =  	Lst_Init(FALSE);
257     gn->successors = 	Lst_Init(FALSE);
258     gn->preds =     	Lst_Init(FALSE);
259     gn->recpreds =	Lst_Init(FALSE);
260     Hash_InitTable(&gn->context, 0);
261     gn->commands =  	Lst_Init(FALSE);
262     gn->suffix =	NULL;
263     gn->lineno =	0;
264     gn->fname = 	NULL;
265 
266 #ifdef CLEANUP
267     if (allGNs == NULL)
268 	allGNs = Lst_Init(FALSE);
269     Lst_AtEnd(allGNs, (ClientData) gn);
270 #endif
271 
272     return (gn);
273 }
274 
275 #ifdef CLEANUP
276 /*-
277  *-----------------------------------------------------------------------
278  * TargFreeGN  --
279  *	Destroy a GNode
280  *
281  * Results:
282  *	None.
283  *
284  * Side Effects:
285  *	None.
286  *-----------------------------------------------------------------------
287  */
288 static void
289 TargFreeGN(ClientData gnp)
290 {
291     GNode *gn = (GNode *)gnp;
292 
293 
294     free(gn->name);
295     if (gn->uname)
296 	free(gn->uname);
297     if (gn->path)
298 	free(gn->path);
299     if (gn->fname)
300 	free(gn->fname);
301 
302     Lst_Destroy(gn->iParents, NOFREE);
303     Lst_Destroy(gn->cohorts, NOFREE);
304     Lst_Destroy(gn->parents, NOFREE);
305     Lst_Destroy(gn->ancestors, NOFREE);
306     Lst_Destroy(gn->children, NOFREE);
307     Lst_Destroy(gn->successors, NOFREE);
308     Lst_Destroy(gn->preds, NOFREE);
309     Lst_Destroy(gn->recpreds, NOFREE);
310     Hash_DeleteTable(&gn->context);
311     Lst_Destroy(gn->commands, NOFREE);
312     free(gn);
313 }
314 #endif
315 
316 
317 /*-
318  *-----------------------------------------------------------------------
319  * Targ_FindNode  --
320  *	Find a node in the list using the given name for matching
321  *
322  * Input:
323  *	name		the name to find
324  *	flags		flags governing events when target not
325  *			found
326  *
327  * Results:
328  *	The node in the list if it was. If it wasn't, return NILGNODE of
329  *	flags was TARG_NOCREATE or the newly created and initialized node
330  *	if it was TARG_CREATE
331  *
332  * Side Effects:
333  *	Sometimes a node is created and added to the list
334  *-----------------------------------------------------------------------
335  */
336 GNode *
337 Targ_FindNode(const char *name, int flags)
338 {
339     GNode         *gn;	      /* node in that element */
340     Hash_Entry	  *he;	      /* New or used hash entry for node */
341     Boolean	  isNew;      /* Set TRUE if Hash_CreateEntry had to create */
342 			      /* an entry for the node */
343 
344 
345     if (flags & TARG_CREATE) {
346 	he = Hash_CreateEntry(&targets, name, &isNew);
347 	if (isNew) {
348 	    gn = Targ_NewGN(name);
349 	    Hash_SetValue(he, gn);
350 	    Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
351 	    (void)Lst_AtEnd(allTargets, (ClientData)gn);
352 	}
353     } else {
354 	he = Hash_FindEntry(&targets, name);
355     }
356 
357     if (he == NULL) {
358 	return (NILGNODE);
359     } else {
360 	return ((GNode *)Hash_GetValue(he));
361     }
362 }
363 
364 /*-
365  *-----------------------------------------------------------------------
366  * Targ_FindList --
367  *	Make a complete list of GNodes from the given list of names
368  *
369  * Input:
370  *	name		list of names to find
371  *	flags		flags used if no node is found for a given name
372  *
373  * Results:
374  *	A complete list of graph nodes corresponding to all instances of all
375  *	the names in names.
376  *
377  * Side Effects:
378  *	If flags is TARG_CREATE, nodes will be created for all names in
379  *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
380  *	an error message will be printed for each name which can't be found.
381  * -----------------------------------------------------------------------
382  */
383 Lst
384 Targ_FindList(Lst names, int flags)
385 {
386     Lst            nodes;	/* result list */
387     LstNode	   ln;		/* name list element */
388     GNode	   *gn;		/* node in tLn */
389     char    	   *name;
390 
391     nodes = Lst_Init(FALSE);
392 
393     if (Lst_Open(names) == FAILURE) {
394 	return (nodes);
395     }
396     while ((ln = Lst_Next(names)) != NILLNODE) {
397 	name = (char *)Lst_Datum(ln);
398 	gn = Targ_FindNode(name, flags);
399 	if (gn != NILGNODE) {
400 	    /*
401 	     * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
402 	     * are added to the list in the order in which they were
403 	     * encountered in the makefile.
404 	     */
405 	    (void)Lst_AtEnd(nodes, (ClientData)gn);
406 	} else if (flags == TARG_NOCREATE) {
407 	    Error("\"%s\" -- target unknown.", name);
408 	}
409     }
410     Lst_Close(names);
411     return (nodes);
412 }
413 
414 /*-
415  *-----------------------------------------------------------------------
416  * Targ_Ignore  --
417  *	Return true if should ignore errors when creating gn
418  *
419  * Input:
420  *	gn		node to check for
421  *
422  * Results:
423  *	TRUE if should ignore errors
424  *
425  * Side Effects:
426  *	None
427  *-----------------------------------------------------------------------
428  */
429 Boolean
430 Targ_Ignore(GNode *gn)
431 {
432     if (ignoreErrors || gn->type & OP_IGNORE) {
433 	return (TRUE);
434     } else {
435 	return (FALSE);
436     }
437 }
438 
439 /*-
440  *-----------------------------------------------------------------------
441  * Targ_Silent  --
442  *	Return true if be silent when creating gn
443  *
444  * Input:
445  *	gn		node to check for
446  *
447  * Results:
448  *	TRUE if should be silent
449  *
450  * Side Effects:
451  *	None
452  *-----------------------------------------------------------------------
453  */
454 Boolean
455 Targ_Silent(GNode *gn)
456 {
457     if (beSilent || gn->type & OP_SILENT) {
458 	return (TRUE);
459     } else {
460 	return (FALSE);
461     }
462 }
463 
464 /*-
465  *-----------------------------------------------------------------------
466  * Targ_Precious --
467  *	See if the given target is precious
468  *
469  * Input:
470  *	gn		the node to check
471  *
472  * Results:
473  *	TRUE if it is precious. FALSE otherwise
474  *
475  * Side Effects:
476  *	None
477  *-----------------------------------------------------------------------
478  */
479 Boolean
480 Targ_Precious(GNode *gn)
481 {
482     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
483 	return (TRUE);
484     } else {
485 	return (FALSE);
486     }
487 }
488 
489 /******************* DEBUG INFO PRINTING ****************/
490 
491 static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
492 /*-
493  *-----------------------------------------------------------------------
494  * Targ_SetMain --
495  *	Set our idea of the main target we'll be creating. Used for
496  *	debugging output.
497  *
498  * Input:
499  *	gn		The main target we'll create
500  *
501  * Results:
502  *	None.
503  *
504  * Side Effects:
505  *	"mainTarg" is set to the main target's node.
506  *-----------------------------------------------------------------------
507  */
508 void
509 Targ_SetMain(GNode *gn)
510 {
511     mainTarg = gn;
512 }
513 
514 #define PrintWait (ClientData)1
515 #define PrintPath (ClientData)2
516 
517 static int
518 TargPrintName(ClientData gnp, ClientData pflags)
519 {
520     static int last_order;
521     GNode *gn = (GNode *)gnp;
522 
523     if (pflags == PrintWait && gn->order > last_order)
524 	printf(".WAIT ");
525     last_order = gn->order;
526 
527     printf("%s ", gn->name);
528 
529 #ifdef notdef
530     if (pflags == PrintPath) {
531 	if (gn->path) {
532 	    printf("[%s]  ", gn->path);
533 	}
534 	if (gn == mainTarg) {
535 	    printf("(MAIN NAME)  ");
536 	}
537     }
538 #endif /* notdef */
539 
540     return 0;
541 }
542 
543 
544 int
545 Targ_PrintCmd(ClientData cmd, ClientData dummy)
546 {
547     printf("\t%s\n", (char *)cmd);
548     return (dummy ? 0 : 0);
549 }
550 
551 /*-
552  *-----------------------------------------------------------------------
553  * Targ_FmtTime --
554  *	Format a modification time in some reasonable way and return it.
555  *
556  * Results:
557  *	The time reformatted.
558  *
559  * Side Effects:
560  *	The time is placed in a static area, so it is overwritten
561  *	with each call.
562  *
563  *-----------------------------------------------------------------------
564  */
565 char *
566 Targ_FmtTime(time_t tm)
567 {
568     struct tm	  	*parts;
569     static char	  	buf[128];
570 
571     parts = localtime(&tm);
572     (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
573     return(buf);
574 }
575 
576 /*-
577  *-----------------------------------------------------------------------
578  * Targ_PrintType --
579  *	Print out a type field giving only those attributes the user can
580  *	set.
581  *
582  * Results:
583  *
584  * Side Effects:
585  *
586  *-----------------------------------------------------------------------
587  */
588 void
589 Targ_PrintType(int type)
590 {
591     int    tbit;
592 
593 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
594 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))printf("." #attr " "); break
595 
596     type &= ~OP_OPMASK;
597 
598     while (type) {
599 	tbit = 1 << (ffs(type) - 1);
600 	type &= ~tbit;
601 
602 	switch(tbit) {
603 	    PRINTBIT(OPTIONAL);
604 	    PRINTBIT(USE);
605 	    PRINTBIT(EXEC);
606 	    PRINTBIT(IGNORE);
607 	    PRINTBIT(PRECIOUS);
608 	    PRINTBIT(SILENT);
609 	    PRINTBIT(MAKE);
610 	    PRINTBIT(JOIN);
611 	    PRINTBIT(INVISIBLE);
612 	    PRINTBIT(NOTMAIN);
613 	    PRINTDBIT(LIB);
614 	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
615 	    case OP_MEMBER: if (DEBUG(TARG))printf(".MEMBER "); break;
616 	    PRINTDBIT(ARCHV);
617 	    PRINTDBIT(MADE);
618 	    PRINTDBIT(PHONY);
619 	}
620     }
621 }
622 
623 /*-
624  *-----------------------------------------------------------------------
625  * TargPrintNode --
626  *	print the contents of a node
627  *-----------------------------------------------------------------------
628  */
629 int
630 Targ_PrintNode(ClientData gnp, ClientData passp)
631 {
632     GNode         *gn = (GNode *)gnp;
633     int	    	  pass = passp ? *(int *)passp : 0;
634     if (!OP_NOP(gn->type)) {
635 	printf("#\n");
636 	if (gn == mainTarg) {
637 	    printf("# *** MAIN TARGET ***\n");
638 	}
639 	if (pass == 2) {
640 	    if (gn->unmade) {
641 		printf("# %d unmade children\n", gn->unmade);
642 	    } else {
643 		printf("# No unmade children\n");
644 	    }
645 	    if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
646 		if (gn->mtime != 0) {
647 		    printf("# last modified %s: %s\n",
648 			      Targ_FmtTime(gn->mtime),
649 			      (gn->made == UNMADE ? "unmade" :
650 			       (gn->made == MADE ? "made" :
651 				(gn->made == UPTODATE ? "up-to-date" :
652 				 "error when made"))));
653 		} else if (gn->made != UNMADE) {
654 		    printf("# non-existent (maybe): %s\n",
655 			      (gn->made == MADE ? "made" :
656 			       (gn->made == UPTODATE ? "up-to-date" :
657 				(gn->made == ERROR ? "error when made" :
658 				 "aborted"))));
659 		} else {
660 		    printf("# unmade\n");
661 		}
662 	    }
663 	    if (!Lst_IsEmpty (gn->iParents)) {
664 		printf("# implicit parents: ");
665 		Lst_ForEach(gn->iParents, TargPrintName, (ClientData)0);
666 		fputc('\n', stdout);
667 	    }
668 	} else {
669 	    if (gn->unmade)
670 		printf("# %d unmade children\n", gn->unmade);
671 	}
672 	if (!Lst_IsEmpty (gn->parents)) {
673 	    printf("# parents: ");
674 	    Lst_ForEach(gn->parents, TargPrintName, (ClientData)0);
675 	    fputc('\n', stdout);
676 	}
677 	if (!Lst_IsEmpty (gn->children)) {
678 	    printf("# children: ");
679 	    Lst_ForEach(gn->children, TargPrintName, (ClientData)0);
680 	    fputc('\n', stdout);
681 	}
682 	if (!Lst_IsEmpty (gn->preds)) {
683 	    printf("# preds: ");
684 	    Lst_ForEach(gn->preds, TargPrintName, (ClientData)0);
685 	    fputc('\n', stdout);
686 	}
687 	if (!Lst_IsEmpty (gn->recpreds)) {
688 	    printf("# recpreds: ");
689 	    Lst_ForEach(gn->recpreds, TargPrintName, (ClientData)0);
690 	    fputc('\n', stdout);
691 	}
692 	if (!Lst_IsEmpty (gn->successors)) {
693 	    printf("# successors: ");
694 	    Lst_ForEach(gn->successors, TargPrintName, (ClientData)0);
695 	    fputc('\n', stdout);
696 	}
697 
698 	printf("%-16s", gn->name);
699 	switch (gn->type & OP_OPMASK) {
700 	    case OP_DEPENDS:
701 		printf(": "); break;
702 	    case OP_FORCE:
703 		printf("! "); break;
704 	    case OP_DOUBLEDEP:
705 		printf(":: "); break;
706 	}
707 	Targ_PrintType(gn->type);
708 	Lst_ForEach(gn->children, TargPrintName, PrintWait);
709 	fputc('\n', stdout);
710 	Lst_ForEach(gn->commands, Targ_PrintCmd, (ClientData)0);
711 	printf("\n\n");
712 	if (gn->type & OP_DOUBLEDEP) {
713 	    Lst_ForEach(gn->cohorts, Targ_PrintNode, (ClientData)&pass);
714 	}
715     }
716     return (0);
717 }
718 
719 /*-
720  *-----------------------------------------------------------------------
721  * TargPrintOnlySrc --
722  *	Print only those targets that are just a source.
723  *
724  * Results:
725  *	0.
726  *
727  * Side Effects:
728  *	The name of each file is printed preceded by #\t
729  *
730  *-----------------------------------------------------------------------
731  */
732 static int
733 TargPrintOnlySrc(ClientData gnp, ClientData dummy)
734 {
735     GNode   	  *gn = (GNode *)gnp;
736     if (OP_NOP(gn->type))
737 	printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
738 
739     return (dummy ? 0 : 0);
740 }
741 
742 /*-
743  *-----------------------------------------------------------------------
744  * Targ_PrintGraph --
745  *	print the entire graph. heh heh
746  *
747  * Input:
748  *	pass		Which pass this is. 1 => no processing
749  *			2 => processing done
750  *
751  * Results:
752  *	none
753  *
754  * Side Effects:
755  *	lots o' output
756  *-----------------------------------------------------------------------
757  */
758 void
759 Targ_PrintGraph(int pass)
760 {
761     printf("#*** Input graph:\n");
762     Lst_ForEach(allTargets, Targ_PrintNode, (ClientData)&pass);
763     printf("\n\n");
764     printf("#\n#   Files that are only sources:\n");
765     Lst_ForEach(allTargets, TargPrintOnlySrc, (ClientData) 0);
766     printf("#*** Global Variables:\n");
767     Var_Dump(VAR_GLOBAL);
768     printf("#*** Command-line Variables:\n");
769     Var_Dump(VAR_CMD);
770     printf("\n");
771     Dir_PrintDirectories();
772     printf("\n");
773     Suff_PrintAll();
774 }
775 
776 /*-
777  *-----------------------------------------------------------------------
778  * TargAppendAncestor -
779  *	Appends a single ancestor to a node's list of ancestors,
780  *	ignoring duplicates.
781  *
782  * Input:
783  *	ancestorgnp	An ancestor to be added to a list.
784  *	thisgnp		The node whose ancestor list will be changed.
785  *
786  * Results:
787  *	Always returns 0, for the benefit of Lst_ForEach().
788  *
789  * Side Effects:
790  *	May modify the ancestors list of the node we are
791  *	examining.
792  *-----------------------------------------------------------------------
793  */
794 static int
795 TargAppendAncestor(ClientData ancestorgnp, ClientData thisgnp)
796 {
797     GNode	  *ancestorgn = (GNode *)ancestorgnp;
798     GNode	  *thisgn = (GNode *)thisgnp;
799 
800     if (Lst_Member(thisgn->ancestors, ancestorgn) == NILLNODE) {
801 	(void)Lst_AtEnd(thisgn->ancestors, (ClientData)ancestorgn);
802     }
803     return (0);
804 }
805 
806 /*-
807  *-----------------------------------------------------------------------
808  * TargAppendParentAncestors -
809  *	Appends all ancestors of a parent node to the ancestor list of a
810  *	given node, ignoring duplicates.
811  *
812  * Input:
813  *	parentgnp	A parent node whose ancestor list will be
814  *			propagated to another node.
815  *	thisgnp		The node whose ancestor list will be changed.
816  *
817  * Results:
818  *	Always returns 0, for the benefit of Lst_ForEach().
819  *
820  * Side Effects:
821  *	May modify the ancestors list of the node we are
822  *	examining.
823  *-----------------------------------------------------------------------
824  */
825 static int
826 TargAppendParentAncestors(ClientData parentgnp, ClientData thisgnp)
827 {
828     GNode	  *parentgn = (GNode *)parentgnp;
829     GNode	  *thisgn = (GNode *)thisgnp;
830 
831     Lst_ForEach(parentgn->ancestors, TargAppendAncestor, thisgn);
832     return (0);
833 }
834 
835 /*-
836  *-----------------------------------------------------------------------
837  * TargInitAncestors -
838  *	Initialises the ancestor list of a node and all the
839  *	node's ancestors.
840  *
841  * Input:
842  *	thisgnp		The node that we are examining.
843  *
844  * Results:
845  *	Always returns 0, for the benefit of Lst_ForEach().
846  *
847  * Side Effects:
848  *	May initialise the ancestors list of the node we are
849  *	examining and all its ancestors.  Does nothing if the
850  *	list has already been initialised.
851  *-----------------------------------------------------------------------
852  */
853 static int
854 TargInitAncestors(ClientData thisgnp, ClientData junk __unused)
855 {
856     GNode	  *thisgn = (GNode *)thisgnp;
857 
858     if (Lst_IsEmpty (thisgn->ancestors)) {
859 	/*
860 	 * Add our parents to our ancestor list before recursing, to
861 	 * ensure that loops in the dependency graph will not result in
862 	 * infinite recursion.
863 	 */
864 	Lst_ForEach(thisgn->parents, TargAppendAncestor, thisgn);
865 	Lst_ForEach(thisgn->iParents, TargAppendAncestor, thisgn);
866 	/* Recursively initialise our parents' ancestor lists */
867 	Lst_ForEach(thisgn->parents, TargInitAncestors, (ClientData)0);
868 	Lst_ForEach(thisgn->iParents, TargInitAncestors, (ClientData)0);
869 	/* Our parents' ancestors are also our ancestors */
870 	Lst_ForEach(thisgn->parents, TargAppendParentAncestors, thisgn);
871 	Lst_ForEach(thisgn->iParents, TargAppendParentAncestors, thisgn);
872     }
873     return (0);
874 }
875 
876 /*-
877  *-----------------------------------------------------------------------
878  * TargHasAncestor -
879  *	Checks whether one node is an ancestor of another node.
880  *
881  *	If called with both arguments pointing to the
882  *	same node, checks whether the node is part of a cycle
883  *	in the graph.
884  *
885  * Input:
886  *	thisgnp		The node whose ancestor list we are examining.
887  *	seekgnp		The node that we are seeking in the
888  *			ancestor list.
889  *
890  * Results:
891  *	TRUE if seekgn is an ancestor of thisgn; FALSE if not.
892  *
893  * Side Effects:
894  *	Initialises the ancestors list in thisgnp and all its ancestors.
895  *-----------------------------------------------------------------------
896  */
897 static Boolean
898 TargHasAncestor(ClientData thisgnp, ClientData seekgnp)
899 {
900     GNode	  *thisgn = (GNode *)thisgnp;
901     GNode	  *seekgn = (GNode *)seekgnp;
902 
903     TargInitAncestors(thisgn, (ClientData)0);
904     if (Lst_Member(thisgn->ancestors, seekgn) != NILLNODE) {
905 	return (TRUE);
906     }
907     return (FALSE);
908 }
909 
910 /*-
911  *-----------------------------------------------------------------------
912  * TargPropagateRecpredChild --
913  *	Create a new predecessor/successor relationship between a pair
914  *	of nodes, and recursively propagate the relationship to all
915  *	children of the successor node.
916  *
917  *	If there is already a predecessor/successor relationship
918  *	in the opposite direction, or if there is already an
919  *	ancestor/descendent relationship in the oposite direction, then
920  *	we avoid adding the new relationship, because that would cause a
921  *	cycle in the graph.
922  *
923  * Input:
924  *	succgnp		Successor node.
925  *	predgnp		Predecessor node.
926  *
927  * Results:
928  *	Always returns 0, for the benefit of Lst_ForEach().
929  *
930  * Side Effects:
931  *	preds/successors information is modified for predgnp, succgnp,
932  *	and recursively for all children of succgnp.
933  *-----------------------------------------------------------------------
934  */
935 static int
936 TargPropagateRecpredChild(ClientData succgnp, ClientData predgnp)
937 {
938     GNode	  *succgn = (GNode *)succgnp;
939     GNode	  *predgn = (GNode *)predgnp;
940     Boolean	  debugmore = FALSE;	/* how much debugging? */
941 
942     /* Ignore if succgn == predgn */
943     if (succgn == predgn) {
944 	if (DEBUG(TARG) && debugmore) {
945 	    printf("# TargPropagateRecpredChild: not propagating %s - %s (identical)\n",
946 		    predgn->name, succgn->name);
947 	}
948 	return (0);
949     }
950     /* Pre-existing pred/successor relationship
951      * in the opposite direction takes precedence. */
952     if (Lst_Member(succgn->successors, predgn) != NILLNODE) {
953 	if (DEBUG(TARG) && debugmore) {
954 	    printf("# TargPropagateRecpredChild: not propagating %s - %s (opposite)\n",
955 		    predgn->name, succgn->name);
956 	}
957 	return (0);
958     }
959     /* Pre-existing descendent/ancestor relationship in the opposite
960      * direction takes precedence. */
961     if (TargHasAncestor(succgn, predgn)) {
962 	if (DEBUG(TARG) && debugmore) {
963 	    printf("# TargPropagateRecpredChild: not propagating %s - %s (ancestor)\n",
964 		    predgn->name, succgn->name);
965 	}
966 	return (0);
967     }
968     /* Note the new pred/successor relationship. */
969     if (DEBUG(TARG)) {
970 	printf("# TargPropagateRecpredChild: propagating %s - %s\n",
971 		predgn->name, succgn->name);
972     }
973     if (Lst_Member(succgn->preds, predgn) == NILLNODE) {
974 	(void)Lst_AtEnd(succgn->preds, (ClientData)predgn);
975 	(void)Lst_AtEnd(predgn->successors, (ClientData)succgn);
976     }
977     /* Recurse, provided there's not a cycle. */
978     if (! TargHasAncestor(succgn, succgn)) {
979 	Lst_ForEach(succgn->children, TargPropagateRecpredChild, predgn);
980     }
981     return (0);
982 }
983 
984 /*-
985  *-----------------------------------------------------------------------
986  * TargPropagateRecpred --
987  *	Recursively propagate information about a single predecessor
988  *	node, from a single successor node to all children of the
989  *	successor node.
990  *
991  * Input:
992  *	predgnp		Predecessor node.
993  *	succgnp		Successor node.
994  *
995  * Results:
996  *	Always returns 0, for the benefit of Lst_ForEach().
997  *
998  * Side Effects:
999  *	preds/successors information is modified for predgnp, succgnp,
1000  *	and recursively for all children of succgnp.
1001  *
1002  *	The real work is done by TargPropagateRecpredChild(), which
1003  *	will be called for each child of the successor node.
1004  *-----------------------------------------------------------------------
1005  */
1006 static int
1007 TargPropagateRecpred(ClientData predgnp, ClientData succgnp)
1008 {
1009     GNode	  *predgn = (GNode *)predgnp;
1010     GNode	  *succgn = (GNode *)succgnp;
1011 
1012     Lst_ForEach(succgn->children, TargPropagateRecpredChild, predgn);
1013     return (0);
1014 }
1015 
1016 /*-
1017  *-----------------------------------------------------------------------
1018  * TargPropagateNode --
1019  *	Propagate information from a single node to related nodes if
1020  *	appropriate.
1021  *
1022  * Input:
1023  *	gnp		The node that we are processing.
1024  *
1025  * Results:
1026  *	Always returns 0, for the benefit of Lst_ForEach().
1027  *
1028  * Side Effects:
1029  *	Information is propagated from this node to cohort or child
1030  *	nodes.
1031  *
1032  *	If the node was defined with "::", then TargPropagateCohort()
1033  *	will be called for each cohort node.
1034  *
1035  *	If the node has recursive predecessors, then
1036  *	TargPropagateRecpred() will be called for each recursive
1037  *	predecessor.
1038  *-----------------------------------------------------------------------
1039  */
1040 static int
1041 TargPropagateNode(ClientData gnp, ClientData junk __unused)
1042 {
1043     GNode	  *gn = (GNode *)gnp;
1044     if (gn->type & OP_DOUBLEDEP)
1045 	Lst_ForEach(gn->cohorts, TargPropagateCohort, gnp);
1046     Lst_ForEach(gn->recpreds, TargPropagateRecpred, gnp);
1047     return (0);
1048 }
1049 
1050 /*-
1051  *-----------------------------------------------------------------------
1052  * TargPropagateCohort --
1053  *	Propagate some bits in the type mask from a node to
1054  *	a related cohort node.
1055  *
1056  * Input:
1057  *	cnp		The node that we are processing.
1058  *	gnp		Another node that has cnp as a cohort.
1059  *
1060  * Results:
1061  *	Always returns 0, for the benefit of Lst_ForEach().
1062  *
1063  * Side Effects:
1064  *	cnp's type bitmask is modified to incorporate some of the
1065  *	bits from gnp's type bitmask.  (XXX need a better explanation.)
1066  *-----------------------------------------------------------------------
1067  */
1068 static int
1069 TargPropagateCohort(ClientData cgnp, ClientData pgnp)
1070 {
1071     GNode	  *cgn = (GNode *)cgnp;
1072     GNode	  *pgn = (GNode *)pgnp;
1073 
1074     cgn->type |= pgn->type & ~OP_OPMASK;
1075     return (0);
1076 }
1077 
1078 /*-
1079  *-----------------------------------------------------------------------
1080  * Targ_Propagate --
1081  *	Propagate information between related nodes.  Should be called
1082  *	after the makefiles are parsed but before any action is taken.
1083  *
1084  * Results:
1085  *	none
1086  *
1087  * Side Effects:
1088  *	Information is propagated between related nodes throughout the
1089  *	graph.
1090  *-----------------------------------------------------------------------
1091  */
1092 void
1093 Targ_Propagate(void)
1094 {
1095     Lst_ForEach(allTargets, TargPropagateNode, (ClientData)0);
1096 }
1097