xref: /freebsd/contrib/bmake/targ.c (revision 9f45a3c8c82ffead7044ae836d9257113c630d3b)
1*9f45a3c8SSimon J. Gerraty /*	$NetBSD: targ.c,v 1.176 2022/01/07 20:50:35 rillig Exp $	*/
23955d011SMarcel Moolenaar 
33955d011SMarcel Moolenaar /*
43955d011SMarcel Moolenaar  * Copyright (c) 1988, 1989, 1990, 1993
53955d011SMarcel Moolenaar  *	The Regents of the University of California.  All rights reserved.
63955d011SMarcel Moolenaar  *
73955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
83955d011SMarcel Moolenaar  * Adam de Boor.
93955d011SMarcel Moolenaar  *
103955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
113955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
123955d011SMarcel Moolenaar  * are met:
133955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
143955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
153955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
163955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
173955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
183955d011SMarcel Moolenaar  * 3. Neither the name of the University nor the names of its contributors
193955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
203955d011SMarcel Moolenaar  *    without specific prior written permission.
213955d011SMarcel Moolenaar  *
223955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
233955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
253955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
263955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
273955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
283955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
293955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
303955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
313955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323955d011SMarcel Moolenaar  * SUCH DAMAGE.
333955d011SMarcel Moolenaar  */
343955d011SMarcel Moolenaar 
353955d011SMarcel Moolenaar /*
363955d011SMarcel Moolenaar  * Copyright (c) 1989 by Berkeley Softworks
373955d011SMarcel Moolenaar  * All rights reserved.
383955d011SMarcel Moolenaar  *
393955d011SMarcel Moolenaar  * This code is derived from software contributed to Berkeley by
403955d011SMarcel Moolenaar  * Adam de Boor.
413955d011SMarcel Moolenaar  *
423955d011SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
433955d011SMarcel Moolenaar  * modification, are permitted provided that the following conditions
443955d011SMarcel Moolenaar  * are met:
453955d011SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
463955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
473955d011SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
483955d011SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
493955d011SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
503955d011SMarcel Moolenaar  * 3. All advertising materials mentioning features or use of this software
513955d011SMarcel Moolenaar  *    must display the following acknowledgement:
523955d011SMarcel Moolenaar  *	This product includes software developed by the University of
533955d011SMarcel Moolenaar  *	California, Berkeley and its contributors.
543955d011SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
553955d011SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
563955d011SMarcel Moolenaar  *    without specific prior written permission.
573955d011SMarcel Moolenaar  *
583955d011SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
593955d011SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603955d011SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
613955d011SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
623955d011SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
633955d011SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
643955d011SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
653955d011SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
663955d011SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
673955d011SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
683955d011SMarcel Moolenaar  * SUCH DAMAGE.
693955d011SMarcel Moolenaar  */
703955d011SMarcel Moolenaar 
71e2eeea75SSimon J. Gerraty /*
72e2eeea75SSimon J. Gerraty  * Maintaining the targets and sources, which are both implemented as GNode.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Interface:
75e2eeea75SSimon J. Gerraty  *	Targ_Init	Initialize the module.
763955d011SMarcel Moolenaar  *
77e2eeea75SSimon J. Gerraty  *	Targ_End	Clean up the module.
783955d011SMarcel Moolenaar  *
793955d011SMarcel Moolenaar  *	Targ_List	Return the list of all targets so far.
803955d011SMarcel Moolenaar  *
81*9f45a3c8SSimon J. Gerraty  *	GNode_New	Create a new GNode with the given name, don't add it
82*9f45a3c8SSimon J. Gerraty  *			to allNodes.
833955d011SMarcel Moolenaar  *
84956e45f6SSimon J. Gerraty  *	Targ_FindNode	Find the node, or return NULL.
85956e45f6SSimon J. Gerraty  *
86956e45f6SSimon J. Gerraty  *	Targ_GetNode	Find the node, or create it.
87956e45f6SSimon J. Gerraty  *
88956e45f6SSimon J. Gerraty  *	Targ_NewInternalNode
89956e45f6SSimon J. Gerraty  *			Create an internal node.
903955d011SMarcel Moolenaar  *
913955d011SMarcel Moolenaar  *	Targ_FindList	Given a list of names, find nodes for all
92956e45f6SSimon J. Gerraty  *			of them, creating them as necessary.
933955d011SMarcel Moolenaar  *
94956e45f6SSimon J. Gerraty  *	Targ_Propagate	Propagate information between related nodes.
95956e45f6SSimon J. Gerraty  *			Should be called after the makefiles are parsed
96956e45f6SSimon J. Gerraty  *			but before any action is taken.
973955d011SMarcel Moolenaar  *
983955d011SMarcel Moolenaar  * Debugging:
99956e45f6SSimon J. Gerraty  *	Targ_PrintGraph
10006b9b3e0SSimon J. Gerraty  *			Print out the entire graph, all variables and
101*9f45a3c8SSimon J. Gerraty  *			statistics for the directory cache.
1023955d011SMarcel Moolenaar  */
1033955d011SMarcel Moolenaar 
1043955d011SMarcel Moolenaar #include <time.h>
1053955d011SMarcel Moolenaar 
1063955d011SMarcel Moolenaar #include "make.h"
1073955d011SMarcel Moolenaar #include "dir.h"
1083955d011SMarcel Moolenaar 
109956e45f6SSimon J. Gerraty /*	"@(#)targ.c	8.2 (Berkeley) 3/19/94"	*/
110*9f45a3c8SSimon J. Gerraty MAKE_RCSID("$NetBSD: targ.c,v 1.176 2022/01/07 20:50:35 rillig Exp $");
1113955d011SMarcel Moolenaar 
11206b9b3e0SSimon J. Gerraty /*
11306b9b3e0SSimon J. Gerraty  * All target nodes that appeared on the left-hand side of one of the
11406b9b3e0SSimon J. Gerraty  * dependency operators ':', '::', '!'.
11506b9b3e0SSimon J. Gerraty  */
11606b9b3e0SSimon J. Gerraty static GNodeList allTargets = LST_INIT;
117e2eeea75SSimon J. Gerraty static HashTable allTargetsByName;
118956e45f6SSimon J. Gerraty 
1193955d011SMarcel Moolenaar #ifdef CLEANUP
12006b9b3e0SSimon J. Gerraty static GNodeList allNodes = LST_INIT;
121e2eeea75SSimon J. Gerraty 
122e2eeea75SSimon J. Gerraty static void GNode_Free(void *);
1233955d011SMarcel Moolenaar #endif
1243955d011SMarcel Moolenaar 
1253955d011SMarcel Moolenaar void
1263955d011SMarcel Moolenaar Targ_Init(void)
1273955d011SMarcel Moolenaar {
128e2eeea75SSimon J. Gerraty 	HashTable_Init(&allTargetsByName);
1293955d011SMarcel Moolenaar }
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar void
1323955d011SMarcel Moolenaar Targ_End(void)
1333955d011SMarcel Moolenaar {
1342c3632d1SSimon J. Gerraty 	Targ_Stats();
1353955d011SMarcel Moolenaar #ifdef CLEANUP
13606b9b3e0SSimon J. Gerraty 	Lst_Done(&allTargets);
137e2eeea75SSimon J. Gerraty 	HashTable_Done(&allTargetsByName);
13806b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&allNodes, GNode_Free);
1393955d011SMarcel Moolenaar #endif
1403955d011SMarcel Moolenaar }
1413955d011SMarcel Moolenaar 
1422c3632d1SSimon J. Gerraty void
1432c3632d1SSimon J. Gerraty Targ_Stats(void)
1442c3632d1SSimon J. Gerraty {
145e2eeea75SSimon J. Gerraty 	HashTable_DebugStats(&allTargetsByName, "targets");
1462c3632d1SSimon J. Gerraty }
1472c3632d1SSimon J. Gerraty 
148e2eeea75SSimon J. Gerraty /*
149e2eeea75SSimon J. Gerraty  * Return the list of all targets, which are all nodes that appear on the
150e2eeea75SSimon J. Gerraty  * left-hand side of a dependency declaration such as "target: source".
151e2eeea75SSimon J. Gerraty  * The returned list does not contain pure sources.
152e2eeea75SSimon J. Gerraty  */
153956e45f6SSimon J. Gerraty GNodeList *
1543955d011SMarcel Moolenaar Targ_List(void)
1553955d011SMarcel Moolenaar {
15606b9b3e0SSimon J. Gerraty 	return &allTargets;
1573955d011SMarcel Moolenaar }
1583955d011SMarcel Moolenaar 
15906b9b3e0SSimon J. Gerraty /*
16006b9b3e0SSimon J. Gerraty  * Create a new graph node, but don't register it anywhere.
1613955d011SMarcel Moolenaar  *
162e2eeea75SSimon J. Gerraty  * Graph nodes that appear on the left-hand side of a dependency line such
163e2eeea75SSimon J. Gerraty  * as "target: source" are called targets.  XXX: In some cases (like the
164e2eeea75SSimon J. Gerraty  * .ALLTARGETS variable), all nodes are called targets as well, even if they
165e2eeea75SSimon J. Gerraty  * never appear on the left-hand side.  This is a mistake.
166e2eeea75SSimon J. Gerraty  *
167e2eeea75SSimon J. Gerraty  * Typical names for graph nodes are:
168e2eeea75SSimon J. Gerraty  *	"src.c" (an ordinary file)
169e2eeea75SSimon J. Gerraty  *	"clean" (a .PHONY target)
170e2eeea75SSimon J. Gerraty  *	".END" (a special hook target)
171e2eeea75SSimon J. Gerraty  *	"-lm" (a library)
172e2eeea75SSimon J. Gerraty  *	"libc.a(isspace.o)" (an archive member)
1733955d011SMarcel Moolenaar  */
1743955d011SMarcel Moolenaar GNode *
175e2eeea75SSimon J. Gerraty GNode_New(const char *name)
1763955d011SMarcel Moolenaar {
1773955d011SMarcel Moolenaar 	GNode *gn;
1783955d011SMarcel Moolenaar 
179e2eeea75SSimon J. Gerraty 	gn = bmake_malloc(sizeof *gn);
1803955d011SMarcel Moolenaar 	gn->name = bmake_strdup(name);
1813955d011SMarcel Moolenaar 	gn->uname = NULL;
1823955d011SMarcel Moolenaar 	gn->path = NULL;
18306b9b3e0SSimon J. Gerraty 	gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : OP_NONE;
18412904384SSimon J. Gerraty 	memset(&gn->flags, 0, sizeof(gn->flags));
185e2eeea75SSimon J. Gerraty 	gn->made = UNMADE;
186e2eeea75SSimon J. Gerraty 	gn->unmade = 0;
1873955d011SMarcel Moolenaar 	gn->mtime = 0;
188956e45f6SSimon J. Gerraty 	gn->youngestChild = NULL;
18906b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->implicitParents);
19006b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->parents);
19106b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->children);
19206b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->order_pred);
19306b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->order_succ);
19406b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->cohorts);
195e2eeea75SSimon J. Gerraty 	gn->cohort_num[0] = '\0';
196e2eeea75SSimon J. Gerraty 	gn->unmade_cohorts = 0;
197e2eeea75SSimon J. Gerraty 	gn->centurion = NULL;
198e2eeea75SSimon J. Gerraty 	gn->checked_seqno = 0;
19906b9b3e0SSimon J. Gerraty 	HashTable_Init(&gn->vars);
20006b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->commands);
2013955d011SMarcel Moolenaar 	gn->suffix = NULL;
2023955d011SMarcel Moolenaar 	gn->fname = NULL;
2032c3632d1SSimon J. Gerraty 	gn->lineno = 0;
2043955d011SMarcel Moolenaar 
2053955d011SMarcel Moolenaar #ifdef CLEANUP
20606b9b3e0SSimon J. Gerraty 	Lst_Append(&allNodes, gn);
2073955d011SMarcel Moolenaar #endif
2083955d011SMarcel Moolenaar 
2093841c287SSimon J. Gerraty 	return gn;
2103955d011SMarcel Moolenaar }
2113955d011SMarcel Moolenaar 
2123955d011SMarcel Moolenaar #ifdef CLEANUP
2133955d011SMarcel Moolenaar static void
214e2eeea75SSimon J. Gerraty GNode_Free(void *gnp)
2153955d011SMarcel Moolenaar {
216956e45f6SSimon J. Gerraty 	GNode *gn = gnp;
2173955d011SMarcel Moolenaar 
2183955d011SMarcel Moolenaar 	free(gn->name);
2193955d011SMarcel Moolenaar 	free(gn->uname);
2203955d011SMarcel Moolenaar 	free(gn->path);
22106b9b3e0SSimon J. Gerraty 
22206b9b3e0SSimon J. Gerraty 	/* Don't free gn->youngestChild since it is not owned by this node. */
22306b9b3e0SSimon J. Gerraty 
22406b9b3e0SSimon J. Gerraty 	/*
22506b9b3e0SSimon J. Gerraty 	 * In the following lists, only free the list nodes, but not the
22606b9b3e0SSimon J. Gerraty 	 * GNodes in them since these are not owned by this node.
22706b9b3e0SSimon J. Gerraty 	 */
22806b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->implicitParents);
22906b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->parents);
23006b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->children);
23106b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->order_pred);
23206b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->order_succ);
23306b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->cohorts);
23406b9b3e0SSimon J. Gerraty 
23506b9b3e0SSimon J. Gerraty 	/*
23606b9b3e0SSimon J. Gerraty 	 * Do not free the variables themselves, even though they are owned
23706b9b3e0SSimon J. Gerraty 	 * by this node.
23806b9b3e0SSimon J. Gerraty 	 *
23906b9b3e0SSimon J. Gerraty 	 * XXX: For the nodes that represent targets or sources (and not
240dba7b0efSSimon J. Gerraty 	 * SCOPE_GLOBAL), it should be safe to free the variables as well,
24106b9b3e0SSimon J. Gerraty 	 * since each node manages the memory for all its variables itself.
24206b9b3e0SSimon J. Gerraty 	 *
243b0c40a00SSimon J. Gerraty 	 * XXX: The GNodes that are only used as variable scopes (SCOPE_CMD,
244dba7b0efSSimon J. Gerraty 	 * SCOPE_GLOBAL, SCOPE_INTERNAL) are not freed at all (see Var_End,
245dba7b0efSSimon J. Gerraty 	 * where they are not mentioned).  These might be freed at all, if
246dba7b0efSSimon J. Gerraty 	 * their variable values are indeed not used anywhere else (see
247dba7b0efSSimon J. Gerraty 	 * Trace_Init for the only suspicious use).
24806b9b3e0SSimon J. Gerraty 	 */
24906b9b3e0SSimon J. Gerraty 	HashTable_Done(&gn->vars);
25006b9b3e0SSimon J. Gerraty 
25106b9b3e0SSimon J. Gerraty 	/*
25206b9b3e0SSimon J. Gerraty 	 * Do not free the commands themselves, as they may be shared with
25306b9b3e0SSimon J. Gerraty 	 * other nodes.
25406b9b3e0SSimon J. Gerraty 	 */
25506b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->commands);
25606b9b3e0SSimon J. Gerraty 
25706b9b3e0SSimon J. Gerraty 	/*
25806b9b3e0SSimon J. Gerraty 	 * gn->suffix is not owned by this node.
25906b9b3e0SSimon J. Gerraty 	 *
26006b9b3e0SSimon J. Gerraty 	 * XXX: gn->suffix should be unreferenced here.  This requires a
26106b9b3e0SSimon J. Gerraty 	 * thorough check that the reference counting is done correctly in
26206b9b3e0SSimon J. Gerraty 	 * all places, otherwise a suffix might be freed too early.
26306b9b3e0SSimon J. Gerraty 	 */
2643955d011SMarcel Moolenaar 
2653955d011SMarcel Moolenaar 	free(gn);
2663955d011SMarcel Moolenaar }
2673955d011SMarcel Moolenaar #endif
2683955d011SMarcel Moolenaar 
269956e45f6SSimon J. Gerraty /* Get the existing global node, or return NULL. */
2703955d011SMarcel Moolenaar GNode *
271956e45f6SSimon J. Gerraty Targ_FindNode(const char *name)
2723955d011SMarcel Moolenaar {
273e2eeea75SSimon J. Gerraty 	return HashTable_FindValue(&allTargetsByName, name);
2743955d011SMarcel Moolenaar }
2753955d011SMarcel Moolenaar 
276956e45f6SSimon J. Gerraty /* Get the existing global node, or create it. */
277956e45f6SSimon J. Gerraty GNode *
278956e45f6SSimon J. Gerraty Targ_GetNode(const char *name)
279956e45f6SSimon J. Gerraty {
280b0c40a00SSimon J. Gerraty 	bool isNew;
281e2eeea75SSimon J. Gerraty 	HashEntry *he = HashTable_CreateEntry(&allTargetsByName, name, &isNew);
2823955d011SMarcel Moolenaar 	if (!isNew)
283956e45f6SSimon J. Gerraty 		return HashEntry_Get(he);
284956e45f6SSimon J. Gerraty 
285956e45f6SSimon J. Gerraty 	{
286956e45f6SSimon J. Gerraty 		GNode *gn = Targ_NewInternalNode(name);
287956e45f6SSimon J. Gerraty 		HashEntry_Set(he, gn);
288956e45f6SSimon J. Gerraty 		return gn;
289956e45f6SSimon J. Gerraty 	}
2903955d011SMarcel Moolenaar }
2913955d011SMarcel Moolenaar 
292e2eeea75SSimon J. Gerraty /*
293e2eeea75SSimon J. Gerraty  * Create a node, register it in .ALLTARGETS but don't store it in the
294956e45f6SSimon J. Gerraty  * table of global nodes.  This means it cannot be found by name.
295956e45f6SSimon J. Gerraty  *
296e2eeea75SSimon J. Gerraty  * This is used for internal nodes, such as cohorts or .WAIT nodes.
297e2eeea75SSimon J. Gerraty  */
298956e45f6SSimon J. Gerraty GNode *
299956e45f6SSimon J. Gerraty Targ_NewInternalNode(const char *name)
300956e45f6SSimon J. Gerraty {
301e2eeea75SSimon J. Gerraty 	GNode *gn = GNode_New(name);
302dba7b0efSSimon J. Gerraty 	Global_Append(".ALLTARGETS", name);
30306b9b3e0SSimon J. Gerraty 	Lst_Append(&allTargets, gn);
30406b9b3e0SSimon J. Gerraty 	DEBUG1(TARG, "Adding \"%s\" to all targets.\n", gn->name);
3053955d011SMarcel Moolenaar 	if (doing_depend)
30612904384SSimon J. Gerraty 		gn->flags.fromDepend = true;
3073955d011SMarcel Moolenaar 	return gn;
3083955d011SMarcel Moolenaar }
3093955d011SMarcel Moolenaar 
310e2eeea75SSimon J. Gerraty /*
311e2eeea75SSimon J. Gerraty  * Return the .END node, which contains the commands to be run when
312e2eeea75SSimon J. Gerraty  * everything else has been made.
313e2eeea75SSimon J. Gerraty  */
31406b9b3e0SSimon J. Gerraty GNode *
31506b9b3e0SSimon J. Gerraty Targ_GetEndNode(void)
3163955d011SMarcel Moolenaar {
31706b9b3e0SSimon J. Gerraty 	/*
31806b9b3e0SSimon J. Gerraty 	 * Save the node locally to avoid having to search for it all
31906b9b3e0SSimon J. Gerraty 	 * the time.
32006b9b3e0SSimon J. Gerraty 	 */
321956e45f6SSimon J. Gerraty 	static GNode *endNode = NULL;
32206b9b3e0SSimon J. Gerraty 
323956e45f6SSimon J. Gerraty 	if (endNode == NULL) {
324956e45f6SSimon J. Gerraty 		endNode = Targ_GetNode(".END");
325956e45f6SSimon J. Gerraty 		endNode->type = OP_SPECIAL;
326956e45f6SSimon J. Gerraty 	}
327956e45f6SSimon J. Gerraty 	return endNode;
328956e45f6SSimon J. Gerraty }
3293955d011SMarcel Moolenaar 
33006b9b3e0SSimon J. Gerraty /* Add the named nodes to the list, creating them as necessary. */
33106b9b3e0SSimon J. Gerraty void
33206b9b3e0SSimon J. Gerraty Targ_FindList(GNodeList *gns, StringList *names)
333956e45f6SSimon J. Gerraty {
334956e45f6SSimon J. Gerraty 	StringListNode *ln;
33506b9b3e0SSimon J. Gerraty 
336956e45f6SSimon J. Gerraty 	for (ln = names->first; ln != NULL; ln = ln->next) {
337956e45f6SSimon J. Gerraty 		const char *name = ln->datum;
338956e45f6SSimon J. Gerraty 		GNode *gn = Targ_GetNode(name);
33906b9b3e0SSimon J. Gerraty 		Lst_Append(gns, gn);
3403955d011SMarcel Moolenaar 	}
3413955d011SMarcel Moolenaar }
3423955d011SMarcel Moolenaar 
343956e45f6SSimon J. Gerraty static void
344956e45f6SSimon J. Gerraty PrintNodeNames(GNodeList *gnodes)
3453955d011SMarcel Moolenaar {
34606b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
3473955d011SMarcel Moolenaar 
34806b9b3e0SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next) {
34906b9b3e0SSimon J. Gerraty 		GNode *gn = ln->datum;
350956e45f6SSimon J. Gerraty 		debug_printf(" %s%s", gn->name, gn->cohort_num);
351956e45f6SSimon J. Gerraty 	}
3523955d011SMarcel Moolenaar }
3533955d011SMarcel Moolenaar 
354956e45f6SSimon J. Gerraty static void
355956e45f6SSimon J. Gerraty PrintNodeNamesLine(const char *label, GNodeList *gnodes)
3563955d011SMarcel Moolenaar {
357956e45f6SSimon J. Gerraty 	if (Lst_IsEmpty(gnodes))
358956e45f6SSimon J. Gerraty 		return;
359956e45f6SSimon J. Gerraty 	debug_printf("# %s:", label);
360956e45f6SSimon J. Gerraty 	PrintNodeNames(gnodes);
361956e45f6SSimon J. Gerraty 	debug_printf("\n");
362956e45f6SSimon J. Gerraty }
363956e45f6SSimon J. Gerraty 
364956e45f6SSimon J. Gerraty void
365956e45f6SSimon J. Gerraty Targ_PrintCmds(GNode *gn)
366956e45f6SSimon J. Gerraty {
367956e45f6SSimon J. Gerraty 	StringListNode *ln;
36806b9b3e0SSimon J. Gerraty 
36906b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
370956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
371956e45f6SSimon J. Gerraty 		debug_printf("\t%s\n", cmd);
372956e45f6SSimon J. Gerraty 	}
3733955d011SMarcel Moolenaar }
3743955d011SMarcel Moolenaar 
37506b9b3e0SSimon J. Gerraty /*
37606b9b3e0SSimon J. Gerraty  * Format a modification time in some reasonable way and return it.
37706b9b3e0SSimon J. Gerraty  * The formatted time is placed in a static area, so it is overwritten
37806b9b3e0SSimon J. Gerraty  * with each call.
37906b9b3e0SSimon J. Gerraty  */
38006b9b3e0SSimon J. Gerraty const char *
3813955d011SMarcel Moolenaar Targ_FmtTime(time_t tm)
3823955d011SMarcel Moolenaar {
3833955d011SMarcel Moolenaar 	static char buf[128];
3843955d011SMarcel Moolenaar 
38506b9b3e0SSimon J. Gerraty 	struct tm *parts = localtime(&tm);
386b0c40a00SSimon J. Gerraty 	(void)strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
3873841c287SSimon J. Gerraty 	return buf;
3883955d011SMarcel Moolenaar }
3893955d011SMarcel Moolenaar 
3902c3632d1SSimon J. Gerraty /* Print out a type field giving only those attributes the user can set. */
3913955d011SMarcel Moolenaar void
39212904384SSimon J. Gerraty Targ_PrintType(GNodeType type)
3933955d011SMarcel Moolenaar {
39412904384SSimon J. Gerraty 	static const struct {
39512904384SSimon J. Gerraty 		GNodeType bit;
39612904384SSimon J. Gerraty 		bool internal;
39712904384SSimon J. Gerraty 		const char name[10];
39812904384SSimon J. Gerraty 	} names[] = {
39912904384SSimon J. Gerraty 		{ OP_MEMBER,	true,	"MEMBER"	},
40012904384SSimon J. Gerraty 		{ OP_LIB,	true,	"LIB"		},
40112904384SSimon J. Gerraty 		{ OP_ARCHV,	true,	"ARCHV"		},
40212904384SSimon J. Gerraty 		{ OP_PHONY,	true,	"PHONY"		},
40312904384SSimon J. Gerraty 		{ OP_NOTMAIN,	false,	"NOTMAIN"	},
40412904384SSimon J. Gerraty 		{ OP_INVISIBLE,	false,	"INVISIBLE"	},
40512904384SSimon J. Gerraty 		{ OP_MADE,	true,	"MADE"		},
40612904384SSimon J. Gerraty 		{ OP_JOIN,	false,	"JOIN"		},
40712904384SSimon J. Gerraty 		{ OP_MAKE,	false,	"MAKE"		},
40812904384SSimon J. Gerraty 		{ OP_SILENT,	false,	"SILENT"	},
40912904384SSimon J. Gerraty 		{ OP_PRECIOUS,	false,	"PRECIOUS"	},
41012904384SSimon J. Gerraty 		{ OP_IGNORE,	false,	"IGNORE"	},
41112904384SSimon J. Gerraty 		{ OP_EXEC,	false,	"EXEC"		},
41212904384SSimon J. Gerraty 		{ OP_USE,	false,	"USE"		},
41312904384SSimon J. Gerraty 		{ OP_OPTIONAL,	false,	"OPTIONAL"	},
41412904384SSimon J. Gerraty 	};
41512904384SSimon J. Gerraty 	size_t i;
4163955d011SMarcel Moolenaar 
41712904384SSimon J. Gerraty 	for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
41812904384SSimon J. Gerraty 		if (type & names[i].bit) {
41912904384SSimon J. Gerraty 			if (names[i].internal)
42012904384SSimon J. Gerraty 				DEBUG1(TARG, " .%s", names[i].name);
42112904384SSimon J. Gerraty 			else
42212904384SSimon J. Gerraty 				debug_printf(" .%s", names[i].name);
4233955d011SMarcel Moolenaar 		}
4243955d011SMarcel Moolenaar 	}
4253955d011SMarcel Moolenaar }
4263955d011SMarcel Moolenaar 
427dba7b0efSSimon J. Gerraty const char *
428dba7b0efSSimon J. Gerraty GNodeMade_Name(GNodeMade made)
4293955d011SMarcel Moolenaar {
4303955d011SMarcel Moolenaar 	switch (made) {
4313955d011SMarcel Moolenaar 	case UNMADE:    return "unmade";
4323955d011SMarcel Moolenaar 	case DEFERRED:  return "deferred";
4333955d011SMarcel Moolenaar 	case REQUESTED: return "requested";
4343955d011SMarcel Moolenaar 	case BEINGMADE: return "being made";
4353955d011SMarcel Moolenaar 	case MADE:      return "made";
4363955d011SMarcel Moolenaar 	case UPTODATE:  return "up-to-date";
4373955d011SMarcel Moolenaar 	case ERROR:     return "error when made";
4383955d011SMarcel Moolenaar 	case ABORTED:   return "aborted";
4393955d011SMarcel Moolenaar 	default:        return "unknown enum_made value";
4403955d011SMarcel Moolenaar 	}
4413955d011SMarcel Moolenaar }
4423955d011SMarcel Moolenaar 
443956e45f6SSimon J. Gerraty static const char *
444956e45f6SSimon J. Gerraty GNode_OpName(const GNode *gn)
4453955d011SMarcel Moolenaar {
446956e45f6SSimon J. Gerraty 	switch (gn->type & OP_OPMASK) {
447956e45f6SSimon J. Gerraty 	case OP_DEPENDS:
448956e45f6SSimon J. Gerraty 		return ":";
449956e45f6SSimon J. Gerraty 	case OP_FORCE:
450956e45f6SSimon J. Gerraty 		return "!";
451956e45f6SSimon J. Gerraty 	case OP_DOUBLEDEP:
452956e45f6SSimon J. Gerraty 		return "::";
453956e45f6SSimon J. Gerraty 	}
454956e45f6SSimon J. Gerraty 	return "";
455956e45f6SSimon J. Gerraty }
4563955d011SMarcel Moolenaar 
45712904384SSimon J. Gerraty static bool
45812904384SSimon J. Gerraty GNodeFlags_IsNone(GNodeFlags flags)
45912904384SSimon J. Gerraty {
46012904384SSimon J. Gerraty 	return !flags.remake
46112904384SSimon J. Gerraty 	       && !flags.childMade
46212904384SSimon J. Gerraty 	       && !flags.force
46312904384SSimon J. Gerraty 	       && !flags.doneWait
46412904384SSimon J. Gerraty 	       && !flags.doneOrder
46512904384SSimon J. Gerraty 	       && !flags.fromDepend
46612904384SSimon J. Gerraty 	       && !flags.doneAllsrc
46712904384SSimon J. Gerraty 	       && !flags.cycle
46812904384SSimon J. Gerraty 	       && !flags.doneCycle;
46912904384SSimon J. Gerraty }
47012904384SSimon J. Gerraty 
471956e45f6SSimon J. Gerraty /* Print the contents of a node. */
472956e45f6SSimon J. Gerraty void
473956e45f6SSimon J. Gerraty Targ_PrintNode(GNode *gn, int pass)
474956e45f6SSimon J. Gerraty {
475956e45f6SSimon J. Gerraty 	debug_printf("# %s%s", gn->name, gn->cohort_num);
476956e45f6SSimon J. Gerraty 	GNode_FprintDetails(opts.debug_file, ", ", gn, "\n");
47712904384SSimon J. Gerraty 	if (GNodeFlags_IsNone(gn->flags))
478956e45f6SSimon J. Gerraty 		return;
4793955d011SMarcel Moolenaar 
48006b9b3e0SSimon J. Gerraty 	if (!GNode_IsTarget(gn))
48106b9b3e0SSimon J. Gerraty 		return;
48206b9b3e0SSimon J. Gerraty 
483956e45f6SSimon J. Gerraty 	debug_printf("#\n");
484*9f45a3c8SSimon J. Gerraty 	if (gn == mainNode)
485956e45f6SSimon J. Gerraty 		debug_printf("# *** MAIN TARGET ***\n");
48606b9b3e0SSimon J. Gerraty 
4873955d011SMarcel Moolenaar 	if (pass >= 2) {
48806b9b3e0SSimon J. Gerraty 		if (gn->unmade > 0)
489956e45f6SSimon J. Gerraty 			debug_printf("# %d unmade children\n", gn->unmade);
49006b9b3e0SSimon J. Gerraty 		else
491956e45f6SSimon J. Gerraty 			debug_printf("# No unmade children\n");
4923955d011SMarcel Moolenaar 		if (!(gn->type & (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC))) {
4933955d011SMarcel Moolenaar 			if (gn->mtime != 0) {
494956e45f6SSimon J. Gerraty 				debug_printf("# last modified %s: %s\n",
4953955d011SMarcel Moolenaar 				    Targ_FmtTime(gn->mtime),
496dba7b0efSSimon J. Gerraty 				    GNodeMade_Name(gn->made));
4973955d011SMarcel Moolenaar 			} else if (gn->made != UNMADE) {
49806b9b3e0SSimon J. Gerraty 				debug_printf("# nonexistent (maybe): %s\n",
499dba7b0efSSimon J. Gerraty 				    GNodeMade_Name(gn->made));
50006b9b3e0SSimon J. Gerraty 			} else
501956e45f6SSimon J. Gerraty 				debug_printf("# unmade\n");
5023955d011SMarcel Moolenaar 		}
50306b9b3e0SSimon J. Gerraty 		PrintNodeNamesLine("implicit parents", &gn->implicitParents);
5043955d011SMarcel Moolenaar 	} else {
50506b9b3e0SSimon J. Gerraty 		if (gn->unmade != 0)
506956e45f6SSimon J. Gerraty 			debug_printf("# %d unmade children\n", gn->unmade);
5073955d011SMarcel Moolenaar 	}
50806b9b3e0SSimon J. Gerraty 
50906b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("parents", &gn->parents);
51006b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("order_pred", &gn->order_pred);
51106b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("order_succ", &gn->order_succ);
5123955d011SMarcel Moolenaar 
513956e45f6SSimon J. Gerraty 	debug_printf("%-16s%s", gn->name, GNode_OpName(gn));
5143955d011SMarcel Moolenaar 	Targ_PrintType(gn->type);
51506b9b3e0SSimon J. Gerraty 	PrintNodeNames(&gn->children);
516956e45f6SSimon J. Gerraty 	debug_printf("\n");
517956e45f6SSimon J. Gerraty 	Targ_PrintCmds(gn);
518956e45f6SSimon J. Gerraty 	debug_printf("\n\n");
51906b9b3e0SSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP)
52006b9b3e0SSimon J. Gerraty 		Targ_PrintNodes(&gn->cohorts, pass);
5213955d011SMarcel Moolenaar }
5223955d011SMarcel Moolenaar 
523956e45f6SSimon J. Gerraty void
524956e45f6SSimon J. Gerraty Targ_PrintNodes(GNodeList *gnodes, int pass)
5253955d011SMarcel Moolenaar {
526956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
52706b9b3e0SSimon J. Gerraty 
528956e45f6SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
529956e45f6SSimon J. Gerraty 		Targ_PrintNode(ln->datum, pass);
530956e45f6SSimon J. Gerraty }
5313955d011SMarcel Moolenaar 
532956e45f6SSimon J. Gerraty static void
533956e45f6SSimon J. Gerraty PrintOnlySources(void)
534956e45f6SSimon J. Gerraty {
535956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
536956e45f6SSimon J. Gerraty 
53706b9b3e0SSimon J. Gerraty 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
538956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
539956e45f6SSimon J. Gerraty 		if (GNode_IsTarget(gn))
540956e45f6SSimon J. Gerraty 			continue;
541956e45f6SSimon J. Gerraty 
542956e45f6SSimon J. Gerraty 		debug_printf("#\t%s [%s]", gn->name, GNode_Path(gn));
5433955d011SMarcel Moolenaar 		Targ_PrintType(gn->type);
544956e45f6SSimon J. Gerraty 		debug_printf("\n");
545956e45f6SSimon J. Gerraty 	}
5463955d011SMarcel Moolenaar }
5473955d011SMarcel Moolenaar 
54806b9b3e0SSimon J. Gerraty /*
54906b9b3e0SSimon J. Gerraty  * Input:
5502c3632d1SSimon J. Gerraty  *	pass		1 => before processing
5512c3632d1SSimon J. Gerraty  *			2 => after processing
5522c3632d1SSimon J. Gerraty  *			3 => after processing, an error occurred
5533955d011SMarcel Moolenaar  */
5543955d011SMarcel Moolenaar void
5553955d011SMarcel Moolenaar Targ_PrintGraph(int pass)
5563955d011SMarcel Moolenaar {
557956e45f6SSimon J. Gerraty 	debug_printf("#*** Input graph:\n");
55806b9b3e0SSimon J. Gerraty 	Targ_PrintNodes(&allTargets, pass);
559e2eeea75SSimon J. Gerraty 	debug_printf("\n");
560e2eeea75SSimon J. Gerraty 	debug_printf("\n");
561e2eeea75SSimon J. Gerraty 
562e2eeea75SSimon J. Gerraty 	debug_printf("#\n");
563e2eeea75SSimon J. Gerraty 	debug_printf("#   Files that are only sources:\n");
564956e45f6SSimon J. Gerraty 	PrintOnlySources();
565e2eeea75SSimon J. Gerraty 
566956e45f6SSimon J. Gerraty 	debug_printf("#*** Global Variables:\n");
567dba7b0efSSimon J. Gerraty 	Var_Dump(SCOPE_GLOBAL);
568e2eeea75SSimon J. Gerraty 
569956e45f6SSimon J. Gerraty 	debug_printf("#*** Command-line Variables:\n");
570dba7b0efSSimon J. Gerraty 	Var_Dump(SCOPE_CMDLINE);
571e2eeea75SSimon J. Gerraty 
572956e45f6SSimon J. Gerraty 	debug_printf("\n");
5733955d011SMarcel Moolenaar 	Dir_PrintDirectories();
574956e45f6SSimon J. Gerraty 	debug_printf("\n");
575e2eeea75SSimon J. Gerraty 
5763955d011SMarcel Moolenaar 	Suff_PrintAll();
5773955d011SMarcel Moolenaar }
5783955d011SMarcel Moolenaar 
57906b9b3e0SSimon J. Gerraty /*
58006b9b3e0SSimon J. Gerraty  * Propagate some type information to cohort nodes (those from the '::'
5812c3632d1SSimon J. Gerraty  * dependency operator).
5823955d011SMarcel Moolenaar  *
5832c3632d1SSimon J. Gerraty  * Should be called after the makefiles are parsed but before any action is
58406b9b3e0SSimon J. Gerraty  * taken.
58506b9b3e0SSimon J. Gerraty  */
5863955d011SMarcel Moolenaar void
5873955d011SMarcel Moolenaar Targ_Propagate(void)
5883955d011SMarcel Moolenaar {
589956e45f6SSimon J. Gerraty 	GNodeListNode *ln, *cln;
5902c3632d1SSimon J. Gerraty 
59106b9b3e0SSimon J. Gerraty 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
592956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
593956e45f6SSimon J. Gerraty 		GNodeType type = gn->type;
5942c3632d1SSimon J. Gerraty 
595956e45f6SSimon J. Gerraty 		if (!(type & OP_DOUBLEDEP))
5962c3632d1SSimon J. Gerraty 			continue;
5972c3632d1SSimon J. Gerraty 
59806b9b3e0SSimon J. Gerraty 		for (cln = gn->cohorts.first; cln != NULL; cln = cln->next) {
599956e45f6SSimon J. Gerraty 			GNode *cohort = cln->datum;
6002c3632d1SSimon J. Gerraty 
601956e45f6SSimon J. Gerraty 			cohort->type |= type & ~OP_OPMASK;
6022c3632d1SSimon J. Gerraty 		}
6032c3632d1SSimon J. Gerraty 	}
6043955d011SMarcel Moolenaar }
605