xref: /freebsd/contrib/bmake/targ.c (revision dba7b0ef928af88caa38728a73657b837aeeac93)
1*dba7b0efSSimon J. Gerraty /*	$NetBSD: targ.c,v 1.165 2021/02/04 21:42:46 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  *
81e2eeea75SSimon J. Gerraty  *	GNode_New	Create a new GNode for the passed target
823955d011SMarcel Moolenaar  *			(string). The node is *not* placed in the
833955d011SMarcel Moolenaar  *			hash table, though all its fields are
843955d011SMarcel Moolenaar  *			initialized.
853955d011SMarcel Moolenaar  *
86956e45f6SSimon J. Gerraty  *	Targ_FindNode	Find the node, or return NULL.
87956e45f6SSimon J. Gerraty  *
88956e45f6SSimon J. Gerraty  *	Targ_GetNode	Find the node, or create it.
89956e45f6SSimon J. Gerraty  *
90956e45f6SSimon J. Gerraty  *	Targ_NewInternalNode
91956e45f6SSimon J. Gerraty  *			Create an internal node.
923955d011SMarcel Moolenaar  *
933955d011SMarcel Moolenaar  *	Targ_FindList	Given a list of names, find nodes for all
94956e45f6SSimon J. Gerraty  *			of them, creating them as necessary.
953955d011SMarcel Moolenaar  *
963955d011SMarcel Moolenaar  *	Targ_Precious	Return TRUE if the target is precious and
973955d011SMarcel Moolenaar  *			should not be removed if we are interrupted.
983955d011SMarcel Moolenaar  *
99956e45f6SSimon J. Gerraty  *	Targ_Propagate	Propagate information between related nodes.
100956e45f6SSimon J. Gerraty  *			Should be called after the makefiles are parsed
101956e45f6SSimon J. Gerraty  *			but before any action is taken.
1023955d011SMarcel Moolenaar  *
1033955d011SMarcel Moolenaar  * Debugging:
104956e45f6SSimon J. Gerraty  *	Targ_PrintGraph
10506b9b3e0SSimon J. Gerraty  *			Print out the entire graph, all variables and
106956e45f6SSimon J. Gerraty  *			statistics for the directory cache. Should print
107956e45f6SSimon J. Gerraty  *			something for suffixes, too, but...
1083955d011SMarcel Moolenaar  */
1093955d011SMarcel Moolenaar 
1103955d011SMarcel Moolenaar #include <time.h>
1113955d011SMarcel Moolenaar 
1123955d011SMarcel Moolenaar #include "make.h"
1133955d011SMarcel Moolenaar #include "dir.h"
1143955d011SMarcel Moolenaar 
115956e45f6SSimon J. Gerraty /*	"@(#)targ.c	8.2 (Berkeley) 3/19/94"	*/
116*dba7b0efSSimon J. Gerraty MAKE_RCSID("$NetBSD: targ.c,v 1.165 2021/02/04 21:42:46 rillig Exp $");
1173955d011SMarcel Moolenaar 
11806b9b3e0SSimon J. Gerraty /*
11906b9b3e0SSimon J. Gerraty  * All target nodes that appeared on the left-hand side of one of the
12006b9b3e0SSimon J. Gerraty  * dependency operators ':', '::', '!'.
12106b9b3e0SSimon J. Gerraty  */
12206b9b3e0SSimon J. Gerraty static GNodeList allTargets = LST_INIT;
123e2eeea75SSimon J. Gerraty static HashTable allTargetsByName;
124956e45f6SSimon J. Gerraty 
1253955d011SMarcel Moolenaar #ifdef CLEANUP
12606b9b3e0SSimon J. Gerraty static GNodeList allNodes = LST_INIT;
127e2eeea75SSimon J. Gerraty 
128e2eeea75SSimon J. Gerraty static void GNode_Free(void *);
1293955d011SMarcel Moolenaar #endif
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar void
1323955d011SMarcel Moolenaar Targ_Init(void)
1333955d011SMarcel Moolenaar {
134e2eeea75SSimon J. Gerraty 	HashTable_Init(&allTargetsByName);
1353955d011SMarcel Moolenaar }
1363955d011SMarcel Moolenaar 
1373955d011SMarcel Moolenaar void
1383955d011SMarcel Moolenaar Targ_End(void)
1393955d011SMarcel Moolenaar {
1402c3632d1SSimon J. Gerraty 	Targ_Stats();
1413955d011SMarcel Moolenaar #ifdef CLEANUP
14206b9b3e0SSimon J. Gerraty 	Lst_Done(&allTargets);
143e2eeea75SSimon J. Gerraty 	HashTable_Done(&allTargetsByName);
14406b9b3e0SSimon J. Gerraty 	Lst_DoneCall(&allNodes, GNode_Free);
1453955d011SMarcel Moolenaar #endif
1463955d011SMarcel Moolenaar }
1473955d011SMarcel Moolenaar 
1482c3632d1SSimon J. Gerraty void
1492c3632d1SSimon J. Gerraty Targ_Stats(void)
1502c3632d1SSimon J. Gerraty {
151e2eeea75SSimon J. Gerraty 	HashTable_DebugStats(&allTargetsByName, "targets");
1522c3632d1SSimon J. Gerraty }
1532c3632d1SSimon J. Gerraty 
154e2eeea75SSimon J. Gerraty /*
155e2eeea75SSimon J. Gerraty  * Return the list of all targets, which are all nodes that appear on the
156e2eeea75SSimon J. Gerraty  * left-hand side of a dependency declaration such as "target: source".
157e2eeea75SSimon J. Gerraty  * The returned list does not contain pure sources.
158e2eeea75SSimon J. Gerraty  */
159956e45f6SSimon J. Gerraty GNodeList *
1603955d011SMarcel Moolenaar Targ_List(void)
1613955d011SMarcel Moolenaar {
16206b9b3e0SSimon J. Gerraty 	return &allTargets;
1633955d011SMarcel Moolenaar }
1643955d011SMarcel Moolenaar 
16506b9b3e0SSimon J. Gerraty /*
16606b9b3e0SSimon J. Gerraty  * Create a new graph node, but don't register it anywhere.
1673955d011SMarcel Moolenaar  *
168e2eeea75SSimon J. Gerraty  * Graph nodes that appear on the left-hand side of a dependency line such
169e2eeea75SSimon J. Gerraty  * as "target: source" are called targets.  XXX: In some cases (like the
170e2eeea75SSimon J. Gerraty  * .ALLTARGETS variable), all nodes are called targets as well, even if they
171e2eeea75SSimon J. Gerraty  * never appear on the left-hand side.  This is a mistake.
172e2eeea75SSimon J. Gerraty  *
173e2eeea75SSimon J. Gerraty  * Typical names for graph nodes are:
174e2eeea75SSimon J. Gerraty  *	"src.c" (an ordinary file)
175e2eeea75SSimon J. Gerraty  *	"clean" (a .PHONY target)
176e2eeea75SSimon J. Gerraty  *	".END" (a special hook target)
177e2eeea75SSimon J. Gerraty  *	"-lm" (a library)
178e2eeea75SSimon J. Gerraty  *	"libc.a(isspace.o)" (an archive member)
1793955d011SMarcel Moolenaar  */
1803955d011SMarcel Moolenaar GNode *
181e2eeea75SSimon J. Gerraty GNode_New(const char *name)
1823955d011SMarcel Moolenaar {
1833955d011SMarcel Moolenaar 	GNode *gn;
1843955d011SMarcel Moolenaar 
185e2eeea75SSimon J. Gerraty 	gn = bmake_malloc(sizeof *gn);
1863955d011SMarcel Moolenaar 	gn->name = bmake_strdup(name);
1873955d011SMarcel Moolenaar 	gn->uname = NULL;
1883955d011SMarcel Moolenaar 	gn->path = NULL;
18906b9b3e0SSimon J. Gerraty 	gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : OP_NONE;
19006b9b3e0SSimon J. Gerraty 	gn->flags = GNF_NONE;
191e2eeea75SSimon J. Gerraty 	gn->made = UNMADE;
192e2eeea75SSimon J. Gerraty 	gn->unmade = 0;
1933955d011SMarcel Moolenaar 	gn->mtime = 0;
194956e45f6SSimon J. Gerraty 	gn->youngestChild = NULL;
19506b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->implicitParents);
19606b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->parents);
19706b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->children);
19806b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->order_pred);
19906b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->order_succ);
20006b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->cohorts);
201e2eeea75SSimon J. Gerraty 	gn->cohort_num[0] = '\0';
202e2eeea75SSimon J. Gerraty 	gn->unmade_cohorts = 0;
203e2eeea75SSimon J. Gerraty 	gn->centurion = NULL;
204e2eeea75SSimon J. Gerraty 	gn->checked_seqno = 0;
20506b9b3e0SSimon J. Gerraty 	HashTable_Init(&gn->vars);
20606b9b3e0SSimon J. Gerraty 	Lst_Init(&gn->commands);
2073955d011SMarcel Moolenaar 	gn->suffix = NULL;
2083955d011SMarcel Moolenaar 	gn->fname = NULL;
2092c3632d1SSimon J. Gerraty 	gn->lineno = 0;
2103955d011SMarcel Moolenaar 
2113955d011SMarcel Moolenaar #ifdef CLEANUP
21206b9b3e0SSimon J. Gerraty 	Lst_Append(&allNodes, gn);
2133955d011SMarcel Moolenaar #endif
2143955d011SMarcel Moolenaar 
2153841c287SSimon J. Gerraty 	return gn;
2163955d011SMarcel Moolenaar }
2173955d011SMarcel Moolenaar 
2183955d011SMarcel Moolenaar #ifdef CLEANUP
2193955d011SMarcel Moolenaar static void
220e2eeea75SSimon J. Gerraty GNode_Free(void *gnp)
2213955d011SMarcel Moolenaar {
222956e45f6SSimon J. Gerraty 	GNode *gn = gnp;
2233955d011SMarcel Moolenaar 
2243955d011SMarcel Moolenaar 	free(gn->name);
2253955d011SMarcel Moolenaar 	free(gn->uname);
2263955d011SMarcel Moolenaar 	free(gn->path);
22706b9b3e0SSimon J. Gerraty 
22806b9b3e0SSimon J. Gerraty 	/* Don't free gn->youngestChild since it is not owned by this node. */
22906b9b3e0SSimon J. Gerraty 
23006b9b3e0SSimon J. Gerraty 	/*
23106b9b3e0SSimon J. Gerraty 	 * In the following lists, only free the list nodes, but not the
23206b9b3e0SSimon J. Gerraty 	 * GNodes in them since these are not owned by this node.
23306b9b3e0SSimon J. Gerraty 	 */
23406b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->implicitParents);
23506b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->parents);
23606b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->children);
23706b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->order_pred);
23806b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->order_succ);
23906b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->cohorts);
24006b9b3e0SSimon J. Gerraty 
24106b9b3e0SSimon J. Gerraty 	/*
24206b9b3e0SSimon J. Gerraty 	 * Do not free the variables themselves, even though they are owned
24306b9b3e0SSimon J. Gerraty 	 * by this node.
24406b9b3e0SSimon J. Gerraty 	 *
24506b9b3e0SSimon J. Gerraty 	 * XXX: For the nodes that represent targets or sources (and not
246*dba7b0efSSimon J. Gerraty 	 * SCOPE_GLOBAL), it should be safe to free the variables as well,
24706b9b3e0SSimon J. Gerraty 	 * since each node manages the memory for all its variables itself.
24806b9b3e0SSimon J. Gerraty 	 *
249*dba7b0efSSimon J. Gerraty 	 * XXX: The GNodes that are only used as variable scopes (VAR_CMD,
250*dba7b0efSSimon J. Gerraty 	 * SCOPE_GLOBAL, SCOPE_INTERNAL) are not freed at all (see Var_End,
251*dba7b0efSSimon J. Gerraty 	 * where they are not mentioned).  These might be freed at all, if
252*dba7b0efSSimon J. Gerraty 	 * their variable values are indeed not used anywhere else (see
253*dba7b0efSSimon J. Gerraty 	 * Trace_Init for the only suspicious use).
25406b9b3e0SSimon J. Gerraty 	 */
25506b9b3e0SSimon J. Gerraty 	HashTable_Done(&gn->vars);
25606b9b3e0SSimon J. Gerraty 
25706b9b3e0SSimon J. Gerraty 	/*
25806b9b3e0SSimon J. Gerraty 	 * Do not free the commands themselves, as they may be shared with
25906b9b3e0SSimon J. Gerraty 	 * other nodes.
26006b9b3e0SSimon J. Gerraty 	 */
26106b9b3e0SSimon J. Gerraty 	Lst_Done(&gn->commands);
26206b9b3e0SSimon J. Gerraty 
26306b9b3e0SSimon J. Gerraty 	/*
26406b9b3e0SSimon J. Gerraty 	 * gn->suffix is not owned by this node.
26506b9b3e0SSimon J. Gerraty 	 *
26606b9b3e0SSimon J. Gerraty 	 * XXX: gn->suffix should be unreferenced here.  This requires a
26706b9b3e0SSimon J. Gerraty 	 * thorough check that the reference counting is done correctly in
26806b9b3e0SSimon J. Gerraty 	 * all places, otherwise a suffix might be freed too early.
26906b9b3e0SSimon J. Gerraty 	 */
2703955d011SMarcel Moolenaar 
2713955d011SMarcel Moolenaar 	free(gn);
2723955d011SMarcel Moolenaar }
2733955d011SMarcel Moolenaar #endif
2743955d011SMarcel Moolenaar 
275956e45f6SSimon J. Gerraty /* Get the existing global node, or return NULL. */
2763955d011SMarcel Moolenaar GNode *
277956e45f6SSimon J. Gerraty Targ_FindNode(const char *name)
2783955d011SMarcel Moolenaar {
279e2eeea75SSimon J. Gerraty 	return HashTable_FindValue(&allTargetsByName, name);
2803955d011SMarcel Moolenaar }
2813955d011SMarcel Moolenaar 
282956e45f6SSimon J. Gerraty /* Get the existing global node, or create it. */
283956e45f6SSimon J. Gerraty GNode *
284956e45f6SSimon J. Gerraty Targ_GetNode(const char *name)
285956e45f6SSimon J. Gerraty {
286956e45f6SSimon J. Gerraty 	Boolean isNew;
287e2eeea75SSimon J. Gerraty 	HashEntry *he = HashTable_CreateEntry(&allTargetsByName, name, &isNew);
2883955d011SMarcel Moolenaar 	if (!isNew)
289956e45f6SSimon J. Gerraty 		return HashEntry_Get(he);
290956e45f6SSimon J. Gerraty 
291956e45f6SSimon J. Gerraty 	{
292956e45f6SSimon J. Gerraty 		GNode *gn = Targ_NewInternalNode(name);
293956e45f6SSimon J. Gerraty 		HashEntry_Set(he, gn);
294956e45f6SSimon J. Gerraty 		return gn;
295956e45f6SSimon J. Gerraty 	}
2963955d011SMarcel Moolenaar }
2973955d011SMarcel Moolenaar 
298e2eeea75SSimon J. Gerraty /*
299e2eeea75SSimon J. Gerraty  * Create a node, register it in .ALLTARGETS but don't store it in the
300956e45f6SSimon J. Gerraty  * table of global nodes.  This means it cannot be found by name.
301956e45f6SSimon J. Gerraty  *
302e2eeea75SSimon J. Gerraty  * This is used for internal nodes, such as cohorts or .WAIT nodes.
303e2eeea75SSimon J. Gerraty  */
304956e45f6SSimon J. Gerraty GNode *
305956e45f6SSimon J. Gerraty Targ_NewInternalNode(const char *name)
306956e45f6SSimon J. Gerraty {
307e2eeea75SSimon J. Gerraty 	GNode *gn = GNode_New(name);
308*dba7b0efSSimon J. Gerraty 	Global_Append(".ALLTARGETS", name);
30906b9b3e0SSimon J. Gerraty 	Lst_Append(&allTargets, gn);
31006b9b3e0SSimon J. Gerraty 	DEBUG1(TARG, "Adding \"%s\" to all targets.\n", gn->name);
3113955d011SMarcel Moolenaar 	if (doing_depend)
3123955d011SMarcel Moolenaar 		gn->flags |= FROM_DEPEND;
3133955d011SMarcel Moolenaar 	return gn;
3143955d011SMarcel Moolenaar }
3153955d011SMarcel Moolenaar 
316e2eeea75SSimon J. Gerraty /*
317e2eeea75SSimon J. Gerraty  * Return the .END node, which contains the commands to be run when
318e2eeea75SSimon J. Gerraty  * everything else has been made.
319e2eeea75SSimon J. Gerraty  */
32006b9b3e0SSimon J. Gerraty GNode *
32106b9b3e0SSimon J. Gerraty Targ_GetEndNode(void)
3223955d011SMarcel Moolenaar {
32306b9b3e0SSimon J. Gerraty 	/*
32406b9b3e0SSimon J. Gerraty 	 * Save the node locally to avoid having to search for it all
32506b9b3e0SSimon J. Gerraty 	 * the time.
32606b9b3e0SSimon J. Gerraty 	 */
327956e45f6SSimon J. Gerraty 	static GNode *endNode = NULL;
32806b9b3e0SSimon J. Gerraty 
329956e45f6SSimon J. Gerraty 	if (endNode == NULL) {
330956e45f6SSimon J. Gerraty 		endNode = Targ_GetNode(".END");
331956e45f6SSimon J. Gerraty 		endNode->type = OP_SPECIAL;
332956e45f6SSimon J. Gerraty 	}
333956e45f6SSimon J. Gerraty 	return endNode;
334956e45f6SSimon J. Gerraty }
3353955d011SMarcel Moolenaar 
33606b9b3e0SSimon J. Gerraty /* Add the named nodes to the list, creating them as necessary. */
33706b9b3e0SSimon J. Gerraty void
33806b9b3e0SSimon J. Gerraty Targ_FindList(GNodeList *gns, StringList *names)
339956e45f6SSimon J. Gerraty {
340956e45f6SSimon J. Gerraty 	StringListNode *ln;
34106b9b3e0SSimon J. Gerraty 
342956e45f6SSimon J. Gerraty 	for (ln = names->first; ln != NULL; ln = ln->next) {
343956e45f6SSimon J. Gerraty 		const char *name = ln->datum;
344956e45f6SSimon J. Gerraty 		GNode *gn = Targ_GetNode(name);
34506b9b3e0SSimon J. Gerraty 		Lst_Append(gns, gn);
3463955d011SMarcel Moolenaar 	}
3473955d011SMarcel Moolenaar }
3483955d011SMarcel Moolenaar 
3492c3632d1SSimon J. Gerraty /* See if the given target is precious. */
3503955d011SMarcel Moolenaar Boolean
351e2eeea75SSimon J. Gerraty Targ_Precious(const GNode *gn)
3523955d011SMarcel Moolenaar {
353e2eeea75SSimon J. Gerraty 	/* XXX: Why are '::' targets precious? */
3542c3632d1SSimon J. Gerraty 	return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
3553955d011SMarcel Moolenaar }
3563955d011SMarcel Moolenaar 
357e2eeea75SSimon J. Gerraty /*
358e2eeea75SSimon J. Gerraty  * The main target to be made; only for debugging output.
359e2eeea75SSimon J. Gerraty  * See mainNode in parse.c for the definitive source.
360e2eeea75SSimon J. Gerraty  */
361e2eeea75SSimon J. Gerraty static GNode *mainTarg;
3623955d011SMarcel Moolenaar 
363e2eeea75SSimon J. Gerraty /* Remember the main target to make; only used for debugging. */
3643955d011SMarcel Moolenaar void
3653955d011SMarcel Moolenaar Targ_SetMain(GNode *gn)
3663955d011SMarcel Moolenaar {
3673955d011SMarcel Moolenaar 	mainTarg = gn;
3683955d011SMarcel Moolenaar }
3693955d011SMarcel Moolenaar 
370956e45f6SSimon J. Gerraty static void
371956e45f6SSimon J. Gerraty PrintNodeNames(GNodeList *gnodes)
3723955d011SMarcel Moolenaar {
37306b9b3e0SSimon J. Gerraty 	GNodeListNode *ln;
3743955d011SMarcel Moolenaar 
37506b9b3e0SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next) {
37606b9b3e0SSimon J. Gerraty 		GNode *gn = ln->datum;
377956e45f6SSimon J. Gerraty 		debug_printf(" %s%s", gn->name, gn->cohort_num);
378956e45f6SSimon J. Gerraty 	}
3793955d011SMarcel Moolenaar }
3803955d011SMarcel Moolenaar 
381956e45f6SSimon J. Gerraty static void
382956e45f6SSimon J. Gerraty PrintNodeNamesLine(const char *label, GNodeList *gnodes)
3833955d011SMarcel Moolenaar {
384956e45f6SSimon J. Gerraty 	if (Lst_IsEmpty(gnodes))
385956e45f6SSimon J. Gerraty 		return;
386956e45f6SSimon J. Gerraty 	debug_printf("# %s:", label);
387956e45f6SSimon J. Gerraty 	PrintNodeNames(gnodes);
388956e45f6SSimon J. Gerraty 	debug_printf("\n");
389956e45f6SSimon J. Gerraty }
390956e45f6SSimon J. Gerraty 
391956e45f6SSimon J. Gerraty void
392956e45f6SSimon J. Gerraty Targ_PrintCmds(GNode *gn)
393956e45f6SSimon J. Gerraty {
394956e45f6SSimon J. Gerraty 	StringListNode *ln;
39506b9b3e0SSimon J. Gerraty 
39606b9b3e0SSimon J. Gerraty 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
397956e45f6SSimon J. Gerraty 		const char *cmd = ln->datum;
398956e45f6SSimon J. Gerraty 		debug_printf("\t%s\n", cmd);
399956e45f6SSimon J. Gerraty 	}
4003955d011SMarcel Moolenaar }
4013955d011SMarcel Moolenaar 
40206b9b3e0SSimon J. Gerraty /*
40306b9b3e0SSimon J. Gerraty  * Format a modification time in some reasonable way and return it.
40406b9b3e0SSimon J. Gerraty  * The formatted time is placed in a static area, so it is overwritten
40506b9b3e0SSimon J. Gerraty  * with each call.
40606b9b3e0SSimon J. Gerraty  */
40706b9b3e0SSimon J. Gerraty const char *
4083955d011SMarcel Moolenaar Targ_FmtTime(time_t tm)
4093955d011SMarcel Moolenaar {
4103955d011SMarcel Moolenaar 	static char buf[128];
4113955d011SMarcel Moolenaar 
41206b9b3e0SSimon J. Gerraty 	struct tm *parts = localtime(&tm);
4133955d011SMarcel Moolenaar 	(void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
4143841c287SSimon J. Gerraty 	return buf;
4153955d011SMarcel Moolenaar }
4163955d011SMarcel Moolenaar 
4172c3632d1SSimon J. Gerraty /* Print out a type field giving only those attributes the user can set. */
4183955d011SMarcel Moolenaar void
4193955d011SMarcel Moolenaar Targ_PrintType(int type)
4203955d011SMarcel Moolenaar {
4213955d011SMarcel Moolenaar 	int tbit;
4223955d011SMarcel Moolenaar 
4233955d011SMarcel Moolenaar 	type &= ~OP_OPMASK;
4243955d011SMarcel Moolenaar 
42506b9b3e0SSimon J. Gerraty 	while (type != 0) {
4263955d011SMarcel Moolenaar 		tbit = 1 << (ffs(type) - 1);
4273955d011SMarcel Moolenaar 		type &= ~tbit;
4283955d011SMarcel Moolenaar 
4293955d011SMarcel Moolenaar 		switch (tbit) {
43006b9b3e0SSimon J. Gerraty #define PRINTBIT(bit, attr) case bit: debug_printf(" " attr); break
43106b9b3e0SSimon J. Gerraty #define PRINTDBIT(bit, attr) case bit: DEBUG0(TARG, " " attr); break
43206b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_OPTIONAL, ".OPTIONAL");
43306b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_USE, ".USE");
43406b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_EXEC, ".EXEC");
43506b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_IGNORE, ".IGNORE");
43606b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_PRECIOUS, ".PRECIOUS");
43706b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_SILENT, ".SILENT");
43806b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_MAKE, ".MAKE");
43906b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_JOIN, ".JOIN");
44006b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_INVISIBLE, ".INVISIBLE");
44106b9b3e0SSimon J. Gerraty 		PRINTBIT(OP_NOTMAIN, ".NOTMAIN");
44206b9b3e0SSimon J. Gerraty 		PRINTDBIT(OP_LIB, ".LIB");
44306b9b3e0SSimon J. Gerraty 		PRINTDBIT(OP_MEMBER, ".MEMBER");
44406b9b3e0SSimon J. Gerraty 		PRINTDBIT(OP_ARCHV, ".ARCHV");
44506b9b3e0SSimon J. Gerraty 		PRINTDBIT(OP_MADE, ".MADE");
44606b9b3e0SSimon J. Gerraty 		PRINTDBIT(OP_PHONY, ".PHONY");
44706b9b3e0SSimon J. Gerraty #undef PRINTBIT
44806b9b3e0SSimon J. Gerraty #undef PRINTDBIT
4493955d011SMarcel Moolenaar 		}
4503955d011SMarcel Moolenaar 	}
4513955d011SMarcel Moolenaar }
4523955d011SMarcel Moolenaar 
453*dba7b0efSSimon J. Gerraty const char *
454*dba7b0efSSimon J. Gerraty GNodeMade_Name(GNodeMade made)
4553955d011SMarcel Moolenaar {
4563955d011SMarcel Moolenaar 	switch (made) {
4573955d011SMarcel Moolenaar 	case UNMADE:    return "unmade";
4583955d011SMarcel Moolenaar 	case DEFERRED:  return "deferred";
4593955d011SMarcel Moolenaar 	case REQUESTED: return "requested";
4603955d011SMarcel Moolenaar 	case BEINGMADE: return "being made";
4613955d011SMarcel Moolenaar 	case MADE:      return "made";
4623955d011SMarcel Moolenaar 	case UPTODATE:  return "up-to-date";
4633955d011SMarcel Moolenaar 	case ERROR:     return "error when made";
4643955d011SMarcel Moolenaar 	case ABORTED:   return "aborted";
4653955d011SMarcel Moolenaar 	default:        return "unknown enum_made value";
4663955d011SMarcel Moolenaar 	}
4673955d011SMarcel Moolenaar }
4683955d011SMarcel Moolenaar 
469956e45f6SSimon J. Gerraty static const char *
470956e45f6SSimon J. Gerraty GNode_OpName(const GNode *gn)
4713955d011SMarcel Moolenaar {
472956e45f6SSimon J. Gerraty 	switch (gn->type & OP_OPMASK) {
473956e45f6SSimon J. Gerraty 	case OP_DEPENDS:
474956e45f6SSimon J. Gerraty 		return ":";
475956e45f6SSimon J. Gerraty 	case OP_FORCE:
476956e45f6SSimon J. Gerraty 		return "!";
477956e45f6SSimon J. Gerraty 	case OP_DOUBLEDEP:
478956e45f6SSimon J. Gerraty 		return "::";
479956e45f6SSimon J. Gerraty 	}
480956e45f6SSimon J. Gerraty 	return "";
481956e45f6SSimon J. Gerraty }
4823955d011SMarcel Moolenaar 
483956e45f6SSimon J. Gerraty /* Print the contents of a node. */
484956e45f6SSimon J. Gerraty void
485956e45f6SSimon J. Gerraty Targ_PrintNode(GNode *gn, int pass)
486956e45f6SSimon J. Gerraty {
487956e45f6SSimon J. Gerraty 	debug_printf("# %s%s", gn->name, gn->cohort_num);
488956e45f6SSimon J. Gerraty 	GNode_FprintDetails(opts.debug_file, ", ", gn, "\n");
4893955d011SMarcel Moolenaar 	if (gn->flags == 0)
490956e45f6SSimon J. Gerraty 		return;
4913955d011SMarcel Moolenaar 
49206b9b3e0SSimon J. Gerraty 	if (!GNode_IsTarget(gn))
49306b9b3e0SSimon J. Gerraty 		return;
49406b9b3e0SSimon J. Gerraty 
495956e45f6SSimon J. Gerraty 	debug_printf("#\n");
49606b9b3e0SSimon J. Gerraty 	if (gn == mainTarg)
497956e45f6SSimon J. Gerraty 		debug_printf("# *** MAIN TARGET ***\n");
49806b9b3e0SSimon J. Gerraty 
4993955d011SMarcel Moolenaar 	if (pass >= 2) {
50006b9b3e0SSimon J. Gerraty 		if (gn->unmade > 0)
501956e45f6SSimon J. Gerraty 			debug_printf("# %d unmade children\n", gn->unmade);
50206b9b3e0SSimon J. Gerraty 		else
503956e45f6SSimon J. Gerraty 			debug_printf("# No unmade children\n");
5043955d011SMarcel Moolenaar 		if (!(gn->type & (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC))) {
5053955d011SMarcel Moolenaar 			if (gn->mtime != 0) {
506956e45f6SSimon J. Gerraty 				debug_printf("# last modified %s: %s\n",
5073955d011SMarcel Moolenaar 				    Targ_FmtTime(gn->mtime),
508*dba7b0efSSimon J. Gerraty 				    GNodeMade_Name(gn->made));
5093955d011SMarcel Moolenaar 			} else if (gn->made != UNMADE) {
51006b9b3e0SSimon J. Gerraty 				debug_printf("# nonexistent (maybe): %s\n",
511*dba7b0efSSimon J. Gerraty 				    GNodeMade_Name(gn->made));
51206b9b3e0SSimon J. Gerraty 			} else
513956e45f6SSimon J. Gerraty 				debug_printf("# unmade\n");
5143955d011SMarcel Moolenaar 		}
51506b9b3e0SSimon J. Gerraty 		PrintNodeNamesLine("implicit parents", &gn->implicitParents);
5163955d011SMarcel Moolenaar 	} else {
51706b9b3e0SSimon J. Gerraty 		if (gn->unmade != 0)
518956e45f6SSimon J. Gerraty 			debug_printf("# %d unmade children\n", gn->unmade);
5193955d011SMarcel Moolenaar 	}
52006b9b3e0SSimon J. Gerraty 
52106b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("parents", &gn->parents);
52206b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("order_pred", &gn->order_pred);
52306b9b3e0SSimon J. Gerraty 	PrintNodeNamesLine("order_succ", &gn->order_succ);
5243955d011SMarcel Moolenaar 
525956e45f6SSimon J. Gerraty 	debug_printf("%-16s%s", gn->name, GNode_OpName(gn));
5263955d011SMarcel Moolenaar 	Targ_PrintType(gn->type);
52706b9b3e0SSimon J. Gerraty 	PrintNodeNames(&gn->children);
528956e45f6SSimon J. Gerraty 	debug_printf("\n");
529956e45f6SSimon J. Gerraty 	Targ_PrintCmds(gn);
530956e45f6SSimon J. Gerraty 	debug_printf("\n\n");
53106b9b3e0SSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP)
53206b9b3e0SSimon J. Gerraty 		Targ_PrintNodes(&gn->cohorts, pass);
5333955d011SMarcel Moolenaar }
5343955d011SMarcel Moolenaar 
535956e45f6SSimon J. Gerraty void
536956e45f6SSimon J. Gerraty Targ_PrintNodes(GNodeList *gnodes, int pass)
5373955d011SMarcel Moolenaar {
538956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
53906b9b3e0SSimon J. Gerraty 
540956e45f6SSimon J. Gerraty 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
541956e45f6SSimon J. Gerraty 		Targ_PrintNode(ln->datum, pass);
542956e45f6SSimon J. Gerraty }
5433955d011SMarcel Moolenaar 
544956e45f6SSimon J. Gerraty /* Print only those targets that are just a source. */
545956e45f6SSimon J. Gerraty static void
546956e45f6SSimon J. Gerraty PrintOnlySources(void)
547956e45f6SSimon J. Gerraty {
548956e45f6SSimon J. Gerraty 	GNodeListNode *ln;
549956e45f6SSimon J. Gerraty 
55006b9b3e0SSimon J. Gerraty 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
551956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
552956e45f6SSimon J. Gerraty 		if (GNode_IsTarget(gn))
553956e45f6SSimon J. Gerraty 			continue;
554956e45f6SSimon J. Gerraty 
555956e45f6SSimon J. Gerraty 		debug_printf("#\t%s [%s]", gn->name, GNode_Path(gn));
5563955d011SMarcel Moolenaar 		Targ_PrintType(gn->type);
557956e45f6SSimon J. Gerraty 		debug_printf("\n");
558956e45f6SSimon J. Gerraty 	}
5593955d011SMarcel Moolenaar }
5603955d011SMarcel Moolenaar 
56106b9b3e0SSimon J. Gerraty /*
56206b9b3e0SSimon J. Gerraty  * Input:
5632c3632d1SSimon J. Gerraty  *	pass		1 => before processing
5642c3632d1SSimon J. Gerraty  *			2 => after processing
5652c3632d1SSimon J. Gerraty  *			3 => after processing, an error occurred
5663955d011SMarcel Moolenaar  */
5673955d011SMarcel Moolenaar void
5683955d011SMarcel Moolenaar Targ_PrintGraph(int pass)
5693955d011SMarcel Moolenaar {
570956e45f6SSimon J. Gerraty 	debug_printf("#*** Input graph:\n");
57106b9b3e0SSimon J. Gerraty 	Targ_PrintNodes(&allTargets, pass);
572e2eeea75SSimon J. Gerraty 	debug_printf("\n");
573e2eeea75SSimon J. Gerraty 	debug_printf("\n");
574e2eeea75SSimon J. Gerraty 
575e2eeea75SSimon J. Gerraty 	debug_printf("#\n");
576e2eeea75SSimon J. Gerraty 	debug_printf("#   Files that are only sources:\n");
577956e45f6SSimon J. Gerraty 	PrintOnlySources();
578e2eeea75SSimon J. Gerraty 
579956e45f6SSimon J. Gerraty 	debug_printf("#*** Global Variables:\n");
580*dba7b0efSSimon J. Gerraty 	Var_Dump(SCOPE_GLOBAL);
581e2eeea75SSimon J. Gerraty 
582956e45f6SSimon J. Gerraty 	debug_printf("#*** Command-line Variables:\n");
583*dba7b0efSSimon J. Gerraty 	Var_Dump(SCOPE_CMDLINE);
584e2eeea75SSimon J. Gerraty 
585956e45f6SSimon J. Gerraty 	debug_printf("\n");
5863955d011SMarcel Moolenaar 	Dir_PrintDirectories();
587956e45f6SSimon J. Gerraty 	debug_printf("\n");
588e2eeea75SSimon J. Gerraty 
5893955d011SMarcel Moolenaar 	Suff_PrintAll();
5903955d011SMarcel Moolenaar }
5913955d011SMarcel Moolenaar 
59206b9b3e0SSimon J. Gerraty /*
59306b9b3e0SSimon J. Gerraty  * Propagate some type information to cohort nodes (those from the '::'
5942c3632d1SSimon J. Gerraty  * dependency operator).
5953955d011SMarcel Moolenaar  *
5962c3632d1SSimon J. Gerraty  * Should be called after the makefiles are parsed but before any action is
59706b9b3e0SSimon J. Gerraty  * taken.
59806b9b3e0SSimon J. Gerraty  */
5993955d011SMarcel Moolenaar void
6003955d011SMarcel Moolenaar Targ_Propagate(void)
6013955d011SMarcel Moolenaar {
602956e45f6SSimon J. Gerraty 	GNodeListNode *ln, *cln;
6032c3632d1SSimon J. Gerraty 
60406b9b3e0SSimon J. Gerraty 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
605956e45f6SSimon J. Gerraty 		GNode *gn = ln->datum;
606956e45f6SSimon J. Gerraty 		GNodeType type = gn->type;
6072c3632d1SSimon J. Gerraty 
608956e45f6SSimon J. Gerraty 		if (!(type & OP_DOUBLEDEP))
6092c3632d1SSimon J. Gerraty 			continue;
6102c3632d1SSimon J. Gerraty 
61106b9b3e0SSimon J. Gerraty 		for (cln = gn->cohorts.first; cln != NULL; cln = cln->next) {
612956e45f6SSimon J. Gerraty 			GNode *cohort = cln->datum;
6132c3632d1SSimon J. Gerraty 
614956e45f6SSimon J. Gerraty 			cohort->type |= type & ~OP_OPMASK;
6152c3632d1SSimon J. Gerraty 		}
6162c3632d1SSimon J. Gerraty 	}
6173955d011SMarcel Moolenaar }
618