xref: /freebsd/contrib/bmake/targ.c (revision 9093286b)
19093286bSSimon J. Gerraty /*	$NetBSD: targ.c,v 1.181 2024/04/27 17:33:47 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 
713955d011SMarcel Moolenaar /*
729093286bSSimon J. Gerraty  * Maintaining the targets and sources, which are both implemented as GNode.
733955d011SMarcel Moolenaar  *
743955d011SMarcel Moolenaar  * Interface:
753955d011SMarcel Moolenaar  *	Targ_Init	Initialize the module.
763955d011SMarcel Moolenaar  *
773955d011SMarcel Moolenaar  *	Targ_End	Clean up the module.
783955d011SMarcel Moolenaar  *
799093286bSSimon J. Gerraty  *	Targ_List	Return the list of all targets so far.
803955d011SMarcel Moolenaar  *
813955d011SMarcel Moolenaar  *	GNode_New	Create a new GNode with the given name, don't add it
823955d011SMarcel Moolenaar  *			to allNodes.
833955d011SMarcel Moolenaar  *
843955d011SMarcel Moolenaar  *	Targ_FindNode	Find the node, or return NULL.
853955d011SMarcel Moolenaar  *
863955d011SMarcel Moolenaar  *	Targ_GetNode	Find the node, or create it.
873955d011SMarcel Moolenaar  *
883955d011SMarcel Moolenaar  *	Targ_NewInternalNode
893955d011SMarcel Moolenaar  *			Create an internal node.
903955d011SMarcel Moolenaar  *
913955d011SMarcel Moolenaar  *	Targ_FindList	Given a list of names, find nodes for all
923955d011SMarcel Moolenaar  *			of them, creating them as necessary.
933955d011SMarcel Moolenaar  *
943955d011SMarcel Moolenaar  *	Targ_Propagate	Propagate information between related nodes.
953955d011SMarcel Moolenaar  *			Should be called after the makefiles are parsed
963955d011SMarcel Moolenaar  *			but before any action is taken.
973955d011SMarcel Moolenaar  *
983955d011SMarcel Moolenaar  * Debugging:
993955d011SMarcel Moolenaar  *	Targ_PrintGraph
1003955d011SMarcel Moolenaar  *			Print out the entire graph, all variables and
1013955d011SMarcel Moolenaar  *			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 
1093955d011SMarcel Moolenaar /*	"@(#)targ.c	8.2 (Berkeley) 3/19/94"	*/
1103955d011SMarcel Moolenaar MAKE_RCSID("$NetBSD: targ.c,v 1.181 2024/04/27 17:33:47 rillig Exp $");
1113955d011SMarcel Moolenaar 
1123955d011SMarcel Moolenaar /*
1133955d011SMarcel Moolenaar  * All target nodes that appeared on the left-hand side of one of the
1143955d011SMarcel Moolenaar  * dependency operators ':', '::', '!'.
1153955d011SMarcel Moolenaar  */
1163955d011SMarcel Moolenaar static GNodeList allTargets = LST_INIT;
1173955d011SMarcel Moolenaar static HashTable allTargetsByName;
1183955d011SMarcel Moolenaar 
1193955d011SMarcel Moolenaar #ifdef CLEANUP
1203955d011SMarcel Moolenaar static GNodeList allNodes = LST_INIT;
1213955d011SMarcel Moolenaar 
1223955d011SMarcel Moolenaar static void GNode_Free(GNode *);
1233955d011SMarcel Moolenaar #endif
1243955d011SMarcel Moolenaar 
1253955d011SMarcel Moolenaar void
Targ_Init(void)1263955d011SMarcel Moolenaar Targ_Init(void)
1273955d011SMarcel Moolenaar {
1283955d011SMarcel Moolenaar 	HashTable_Init(&allTargetsByName);
1293955d011SMarcel Moolenaar }
1303955d011SMarcel Moolenaar 
1313955d011SMarcel Moolenaar void
Targ_End(void)1323955d011SMarcel Moolenaar Targ_End(void)
1333955d011SMarcel Moolenaar {
1343955d011SMarcel Moolenaar #ifdef CLEANUP
1353955d011SMarcel Moolenaar 	GNodeListNode *ln;
1363955d011SMarcel Moolenaar #endif
1373955d011SMarcel Moolenaar 	Targ_Stats();
1383955d011SMarcel Moolenaar #ifdef CLEANUP
1393955d011SMarcel Moolenaar 	Lst_Done(&allTargets);
1403955d011SMarcel Moolenaar 	HashTable_Done(&allTargetsByName);
1413955d011SMarcel Moolenaar 	for (ln = allNodes.first; ln != NULL; ln = ln->next)
1423955d011SMarcel Moolenaar 		GNode_Free(ln->datum);
1433955d011SMarcel Moolenaar 	Lst_Done(&allNodes);
1443955d011SMarcel Moolenaar #endif
1453955d011SMarcel Moolenaar }
1463955d011SMarcel Moolenaar 
1473955d011SMarcel Moolenaar void
Targ_Stats(void)1483955d011SMarcel Moolenaar Targ_Stats(void)
1493955d011SMarcel Moolenaar {
1503955d011SMarcel Moolenaar 	HashTable_DebugStats(&allTargetsByName, "targets");
1513955d011SMarcel Moolenaar }
1523955d011SMarcel Moolenaar 
1533955d011SMarcel Moolenaar /*
1543955d011SMarcel Moolenaar  * Return the list of all targets, which are all nodes that appear on the
1553955d011SMarcel Moolenaar  * left-hand side of a dependency declaration such as "target: source".
1563955d011SMarcel Moolenaar  * The returned list does not contain pure sources.
1573955d011SMarcel Moolenaar  */
1583955d011SMarcel Moolenaar GNodeList *
Targ_List(void)1593955d011SMarcel Moolenaar Targ_List(void)
1603955d011SMarcel Moolenaar {
1613955d011SMarcel Moolenaar 	return &allTargets;
1623955d011SMarcel Moolenaar }
1633955d011SMarcel Moolenaar 
1643955d011SMarcel Moolenaar /*
1653955d011SMarcel Moolenaar  * Create a new graph node, but don't register it anywhere.
1663955d011SMarcel Moolenaar  *
1673955d011SMarcel Moolenaar  * Graph nodes that occur on the left-hand side of a dependency line such
1683955d011SMarcel Moolenaar  * as "target: source" are called targets.  XXX: In some cases (like the
1693955d011SMarcel Moolenaar  * .ALLTARGETS variable), other nodes are called targets as well, even if
1703955d011SMarcel Moolenaar  * they never occur on the left-hand side of a dependency line.
1713955d011SMarcel Moolenaar  *
1723955d011SMarcel Moolenaar  * Typical names for graph nodes are:
1733955d011SMarcel Moolenaar  *	"src.c"		an ordinary file
1743955d011SMarcel Moolenaar  *	"clean"		a .PHONY target
1753955d011SMarcel Moolenaar  *	".END"		a special hook target
1763955d011SMarcel Moolenaar  *	"-lm"		a library
1773955d011SMarcel Moolenaar  *	"libm.a(sin.o)"	an archive member
1783955d011SMarcel Moolenaar  */
1793955d011SMarcel Moolenaar GNode *
GNode_New(const char * name)1803955d011SMarcel Moolenaar GNode_New(const char *name)
1813955d011SMarcel Moolenaar {
1823955d011SMarcel Moolenaar 	GNode *gn;
1833955d011SMarcel Moolenaar 
1843955d011SMarcel Moolenaar 	gn = bmake_malloc(sizeof *gn);
1853955d011SMarcel Moolenaar 	gn->name = bmake_strdup(name);
1863955d011SMarcel Moolenaar 	gn->uname = NULL;
1873955d011SMarcel Moolenaar 	gn->path = NULL;
1883955d011SMarcel Moolenaar 	gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : OP_NONE;
1893955d011SMarcel Moolenaar 	memset(&gn->flags, 0, sizeof(gn->flags));
1903955d011SMarcel Moolenaar 	gn->made = UNMADE;
1913955d011SMarcel Moolenaar 	gn->unmade = 0;
1923955d011SMarcel Moolenaar 	gn->mtime = 0;
1933955d011SMarcel Moolenaar 	gn->youngestChild = NULL;
1943955d011SMarcel Moolenaar 	Lst_Init(&gn->implicitParents);
1953955d011SMarcel Moolenaar 	Lst_Init(&gn->parents);
1963955d011SMarcel Moolenaar 	Lst_Init(&gn->children);
1973955d011SMarcel Moolenaar 	Lst_Init(&gn->order_pred);
1983955d011SMarcel Moolenaar 	Lst_Init(&gn->order_succ);
1993955d011SMarcel Moolenaar 	Lst_Init(&gn->cohorts);
2003955d011SMarcel Moolenaar 	gn->cohort_num[0] = '\0';
2013955d011SMarcel Moolenaar 	gn->unmade_cohorts = 0;
2023955d011SMarcel Moolenaar 	gn->centurion = NULL;
2033955d011SMarcel Moolenaar 	gn->checked_seqno = 0;
2043955d011SMarcel Moolenaar 	HashTable_Init(&gn->vars);
2053955d011SMarcel Moolenaar 	Lst_Init(&gn->commands);
2063955d011SMarcel Moolenaar 	gn->suffix = NULL;
2073955d011SMarcel Moolenaar 	gn->fname = NULL;
2083955d011SMarcel Moolenaar 	gn->lineno = 0;
2093955d011SMarcel Moolenaar 	gn->exit_status = 0;
2103955d011SMarcel Moolenaar 
2113955d011SMarcel Moolenaar #ifdef CLEANUP
2123955d011SMarcel Moolenaar 	Lst_Append(&allNodes, gn);
2133955d011SMarcel Moolenaar #endif
2143955d011SMarcel Moolenaar 
2153955d011SMarcel Moolenaar 	return gn;
2163955d011SMarcel Moolenaar }
2173955d011SMarcel Moolenaar 
2183955d011SMarcel Moolenaar #ifdef CLEANUP
2193955d011SMarcel Moolenaar static void
GNode_Free(GNode * gn)2203955d011SMarcel Moolenaar GNode_Free(GNode *gn)
2213955d011SMarcel Moolenaar {
2223955d011SMarcel Moolenaar 	free(gn->name);
2233955d011SMarcel Moolenaar 	free(gn->uname);
2243955d011SMarcel Moolenaar 	free(gn->path);
2253955d011SMarcel Moolenaar 
2263955d011SMarcel Moolenaar 	/* Don't free gn->youngestChild since it is not owned by this node. */
2273955d011SMarcel Moolenaar 
2283955d011SMarcel Moolenaar 	/*
2293955d011SMarcel Moolenaar 	 * In the following lists, only free the list nodes, but not the
2303955d011SMarcel Moolenaar 	 * GNodes in them since these are not owned by this node.
2313955d011SMarcel Moolenaar 	 */
2323955d011SMarcel Moolenaar 	Lst_Done(&gn->implicitParents);
2333955d011SMarcel Moolenaar 	Lst_Done(&gn->parents);
2343955d011SMarcel Moolenaar 	Lst_Done(&gn->children);
2353955d011SMarcel Moolenaar 	Lst_Done(&gn->order_pred);
2363955d011SMarcel Moolenaar 	Lst_Done(&gn->order_succ);
2373955d011SMarcel Moolenaar 	Lst_Done(&gn->cohorts);
2383955d011SMarcel Moolenaar 
2393955d011SMarcel Moolenaar 	/*
2403955d011SMarcel Moolenaar 	 * Do not free the variables themselves, even though they are owned
2413955d011SMarcel Moolenaar 	 * by this node.
2423955d011SMarcel Moolenaar 	 *
2433955d011SMarcel Moolenaar 	 * XXX: For the nodes that represent targets or sources (and not
2443955d011SMarcel Moolenaar 	 * SCOPE_GLOBAL), it should be safe to free the variables as well,
2453955d011SMarcel Moolenaar 	 * since each node manages the memory for all its variables itself.
2463955d011SMarcel Moolenaar 	 *
2473955d011SMarcel Moolenaar 	 * XXX: The GNodes that are only used as variable scopes (SCOPE_CMD,
2483955d011SMarcel Moolenaar 	 * SCOPE_GLOBAL, SCOPE_INTERNAL) are not freed at all (see Var_End,
2493955d011SMarcel Moolenaar 	 * where they are not mentioned).  These may be freed if their
2503955d011SMarcel Moolenaar 	 * variable values are indeed not used anywhere else (see Trace_Init
2513955d011SMarcel Moolenaar 	 * for the only suspicious use).
2523955d011SMarcel Moolenaar 	 */
2533955d011SMarcel Moolenaar 	HashTable_Done(&gn->vars);
2543955d011SMarcel Moolenaar 
2553955d011SMarcel Moolenaar 	/*
2563955d011SMarcel Moolenaar 	 * Do not free the commands themselves, as they may be shared with
2573955d011SMarcel Moolenaar 	 * other nodes.
2583955d011SMarcel Moolenaar 	 */
2593955d011SMarcel Moolenaar 	Lst_Done(&gn->commands);
2603955d011SMarcel Moolenaar 
2613955d011SMarcel Moolenaar 	/*
2623955d011SMarcel Moolenaar 	 * gn->suffix is not owned by this node.
2633955d011SMarcel Moolenaar 	 *
2643955d011SMarcel Moolenaar 	 * XXX: gn->suffix should be unreferenced here.  This requires a
2653955d011SMarcel Moolenaar 	 * thorough check that the reference counting is done correctly in
2663955d011SMarcel Moolenaar 	 * all places, otherwise a suffix might be freed too early.
2673955d011SMarcel Moolenaar 	 */
2683955d011SMarcel Moolenaar 
2693955d011SMarcel Moolenaar 	free(gn);
2703955d011SMarcel Moolenaar }
2713955d011SMarcel Moolenaar #endif
2729093286bSSimon J. Gerraty 
2733955d011SMarcel Moolenaar /* Get the existing global node, or return NULL. */
2743955d011SMarcel Moolenaar GNode *
Targ_FindNode(const char * name)2753955d011SMarcel Moolenaar Targ_FindNode(const char *name)
2763955d011SMarcel Moolenaar {
2773955d011SMarcel Moolenaar 	return HashTable_FindValue(&allTargetsByName, name);
2783955d011SMarcel Moolenaar }
2793955d011SMarcel Moolenaar 
2803955d011SMarcel Moolenaar /* Get the existing global node, or create it. */
2813955d011SMarcel Moolenaar GNode *
Targ_GetNode(const char * name)2823955d011SMarcel Moolenaar Targ_GetNode(const char *name)
2833955d011SMarcel Moolenaar {
2843955d011SMarcel Moolenaar 	bool isNew;
2853955d011SMarcel Moolenaar 	HashEntry *he = HashTable_CreateEntry(&allTargetsByName, name, &isNew);
2863955d011SMarcel Moolenaar 	if (!isNew)
2873955d011SMarcel Moolenaar 		return HashEntry_Get(he);
2883955d011SMarcel Moolenaar 
2893955d011SMarcel Moolenaar 	{
2903955d011SMarcel Moolenaar 		GNode *gn = Targ_NewInternalNode(name);
2913955d011SMarcel Moolenaar 		HashEntry_Set(he, gn);
2923955d011SMarcel Moolenaar 		return gn;
2933955d011SMarcel Moolenaar 	}
2943955d011SMarcel Moolenaar }
2953955d011SMarcel Moolenaar 
2963955d011SMarcel Moolenaar /*
2973955d011SMarcel Moolenaar  * Create a node, register it in .ALLTARGETS but don't store it in the
2983955d011SMarcel Moolenaar  * table of global nodes.  This means it cannot be found by name.
2993955d011SMarcel Moolenaar  *
3003955d011SMarcel Moolenaar  * This is used for internal nodes, such as cohorts or .WAIT nodes.
3013955d011SMarcel Moolenaar  */
3023955d011SMarcel Moolenaar GNode *
Targ_NewInternalNode(const char * name)3033955d011SMarcel Moolenaar Targ_NewInternalNode(const char *name)
3043955d011SMarcel Moolenaar {
3053955d011SMarcel Moolenaar 	GNode *gn = GNode_New(name);
3063955d011SMarcel Moolenaar 	Global_Append(".ALLTARGETS", name);
3073955d011SMarcel Moolenaar 	Lst_Append(&allTargets, gn);
3083955d011SMarcel Moolenaar 	DEBUG1(TARG, "Adding \"%s\" to all targets.\n", gn->name);
3093955d011SMarcel Moolenaar 	if (doing_depend)
3103955d011SMarcel Moolenaar 		gn->flags.fromDepend = true;
3113955d011SMarcel Moolenaar 	return gn;
3123955d011SMarcel Moolenaar }
3133955d011SMarcel Moolenaar 
3143955d011SMarcel Moolenaar /*
3153955d011SMarcel Moolenaar  * Return the .END node, which contains the commands to be run when
3163955d011SMarcel Moolenaar  * everything else has been made.
3173955d011SMarcel Moolenaar  */
3183955d011SMarcel Moolenaar GNode *
Targ_GetEndNode(void)3193955d011SMarcel Moolenaar Targ_GetEndNode(void)
3203955d011SMarcel Moolenaar {
3213955d011SMarcel Moolenaar 	/*
3223955d011SMarcel Moolenaar 	 * Save the node locally to avoid having to search for it all
3233955d011SMarcel Moolenaar 	 * the time.
3243955d011SMarcel Moolenaar 	 */
3253955d011SMarcel Moolenaar 	static GNode *endNode = NULL;
3263955d011SMarcel Moolenaar 
3273955d011SMarcel Moolenaar 	if (endNode == NULL) {
3283955d011SMarcel Moolenaar 		endNode = Targ_GetNode(".END");
3293955d011SMarcel Moolenaar 		endNode->type = OP_SPECIAL;
3303955d011SMarcel Moolenaar 	}
3313955d011SMarcel Moolenaar 	return endNode;
3323955d011SMarcel Moolenaar }
3333955d011SMarcel Moolenaar 
3343955d011SMarcel Moolenaar /* Add the named nodes to the list, creating them as necessary. */
3353955d011SMarcel Moolenaar void
Targ_FindList(GNodeList * gns,StringList * names)3363955d011SMarcel Moolenaar Targ_FindList(GNodeList *gns, StringList *names)
3373955d011SMarcel Moolenaar {
3383955d011SMarcel Moolenaar 	StringListNode *ln;
3393955d011SMarcel Moolenaar 
3403955d011SMarcel Moolenaar 	for (ln = names->first; ln != NULL; ln = ln->next) {
3413955d011SMarcel Moolenaar 		const char *name = ln->datum;
3423955d011SMarcel Moolenaar 		GNode *gn = Targ_GetNode(name);
3433955d011SMarcel Moolenaar 		Lst_Append(gns, gn);
3443955d011SMarcel Moolenaar 	}
3453955d011SMarcel Moolenaar }
3463955d011SMarcel Moolenaar 
3473955d011SMarcel Moolenaar static void
PrintNodeNames(GNodeList * gnodes)3483955d011SMarcel Moolenaar PrintNodeNames(GNodeList *gnodes)
3493955d011SMarcel Moolenaar {
3503955d011SMarcel Moolenaar 	GNodeListNode *ln;
3513955d011SMarcel Moolenaar 
3523955d011SMarcel Moolenaar 	for (ln = gnodes->first; ln != NULL; ln = ln->next) {
3533955d011SMarcel Moolenaar 		GNode *gn = ln->datum;
3543955d011SMarcel Moolenaar 		debug_printf(" %s%s", gn->name, gn->cohort_num);
3553955d011SMarcel Moolenaar 	}
3563955d011SMarcel Moolenaar }
3573955d011SMarcel Moolenaar 
3583955d011SMarcel Moolenaar static void
PrintNodeNamesLine(const char * label,GNodeList * gnodes)3593955d011SMarcel Moolenaar PrintNodeNamesLine(const char *label, GNodeList *gnodes)
3603955d011SMarcel Moolenaar {
3613955d011SMarcel Moolenaar 	if (Lst_IsEmpty(gnodes))
3623955d011SMarcel Moolenaar 		return;
3633955d011SMarcel Moolenaar 	debug_printf("# %s:", label);
3643955d011SMarcel Moolenaar 	PrintNodeNames(gnodes);
3653955d011SMarcel Moolenaar 	debug_printf("\n");
3663955d011SMarcel Moolenaar }
3673955d011SMarcel Moolenaar 
3683955d011SMarcel Moolenaar void
Targ_PrintCmds(GNode * gn)3693955d011SMarcel Moolenaar Targ_PrintCmds(GNode *gn)
3703955d011SMarcel Moolenaar {
3713955d011SMarcel Moolenaar 	StringListNode *ln;
3723955d011SMarcel Moolenaar 
3733955d011SMarcel Moolenaar 	for (ln = gn->commands.first; ln != NULL; ln = ln->next) {
3743955d011SMarcel Moolenaar 		const char *cmd = ln->datum;
3753955d011SMarcel Moolenaar 		debug_printf("\t%s\n", cmd);
3763955d011SMarcel Moolenaar 	}
3773955d011SMarcel Moolenaar }
3783955d011SMarcel Moolenaar 
3793955d011SMarcel Moolenaar /*
3803955d011SMarcel Moolenaar  * Format a modification time in some reasonable way and return it.
3813955d011SMarcel Moolenaar  * The formatted time is placed in a static area, so it is overwritten
3823955d011SMarcel Moolenaar  * with each call.
3833955d011SMarcel Moolenaar  */
3843955d011SMarcel Moolenaar const char *
Targ_FmtTime(time_t tm)3853955d011SMarcel Moolenaar Targ_FmtTime(time_t tm)
3863955d011SMarcel Moolenaar {
3873955d011SMarcel Moolenaar 	static char buf[128];
3883955d011SMarcel Moolenaar 
3893955d011SMarcel Moolenaar 	struct tm *parts = localtime(&tm);
3903955d011SMarcel Moolenaar 	(void)strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
3913955d011SMarcel Moolenaar 	return buf;
3929093286bSSimon J. Gerraty }
3933955d011SMarcel Moolenaar 
3943955d011SMarcel Moolenaar /* Print out a type field giving only those attributes the user can set. */
3953955d011SMarcel Moolenaar void
Targ_PrintType(GNodeType type)3963955d011SMarcel Moolenaar Targ_PrintType(GNodeType type)
3973955d011SMarcel Moolenaar {
3983955d011SMarcel Moolenaar 	static const struct {
3993955d011SMarcel Moolenaar 		GNodeType bit;
4003955d011SMarcel Moolenaar 		bool internal;
4013955d011SMarcel Moolenaar 		const char name[10];
4023955d011SMarcel Moolenaar 	} names[] = {
4033955d011SMarcel Moolenaar 		{ OP_MEMBER,	true,	"MEMBER"	},
4043955d011SMarcel Moolenaar 		{ OP_LIB,	true,	"LIB"		},
4053955d011SMarcel Moolenaar 		{ OP_ARCHV,	true,	"ARCHV"		},
4063955d011SMarcel Moolenaar 		{ OP_PHONY,	true,	"PHONY"		},
4073955d011SMarcel Moolenaar 		{ OP_NOTMAIN,	false,	"NOTMAIN"	},
4083955d011SMarcel Moolenaar 		{ OP_INVISIBLE,	false,	"INVISIBLE"	},
4099093286bSSimon J. Gerraty 		{ OP_MADE,	true,	"MADE"		},
4103955d011SMarcel Moolenaar 		{ OP_JOIN,	false,	"JOIN"		},
4113955d011SMarcel Moolenaar 		{ OP_MAKE,	false,	"MAKE"		},
4123955d011SMarcel Moolenaar 		{ OP_SILENT,	false,	"SILENT"	},
4133955d011SMarcel Moolenaar 		{ OP_PRECIOUS,	false,	"PRECIOUS"	},
4143955d011SMarcel Moolenaar 		{ OP_IGNORE,	false,	"IGNORE"	},
4153955d011SMarcel Moolenaar 		{ OP_EXEC,	false,	"EXEC"		},
4163955d011SMarcel Moolenaar 		{ OP_USE,	false,	"USE"		},
4173955d011SMarcel Moolenaar 		{ OP_USEBEFORE,	false,	"USEBEFORE"	},
4183955d011SMarcel Moolenaar 		{ OP_OPTIONAL,	false,	"OPTIONAL"	},
4193955d011SMarcel Moolenaar 	};
4203955d011SMarcel Moolenaar 	size_t i;
4213955d011SMarcel Moolenaar 
4223955d011SMarcel Moolenaar 	for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
4233955d011SMarcel Moolenaar 		if (type & names[i].bit) {
4243955d011SMarcel Moolenaar 			if (names[i].internal)
4253955d011SMarcel Moolenaar 				DEBUG1(TARG, " .%s", names[i].name);
4263955d011SMarcel Moolenaar 			else
4273955d011SMarcel Moolenaar 				debug_printf(" .%s", names[i].name);
4283955d011SMarcel Moolenaar 		}
4293955d011SMarcel Moolenaar 	}
4303955d011SMarcel Moolenaar }
4319093286bSSimon J. Gerraty 
4323955d011SMarcel Moolenaar const char *
GNodeMade_Name(GNodeMade made)4339093286bSSimon J. Gerraty GNodeMade_Name(GNodeMade made)
4343955d011SMarcel Moolenaar {
4353955d011SMarcel Moolenaar 	switch (made) {
4363955d011SMarcel Moolenaar 	case UNMADE:    return "unmade";
4373955d011SMarcel Moolenaar 	case DEFERRED:  return "deferred";
4383955d011SMarcel Moolenaar 	case REQUESTED: return "requested";
4393955d011SMarcel Moolenaar 	case BEINGMADE: return "being made";
4403955d011SMarcel Moolenaar 	case MADE:      return "made";
4413955d011SMarcel Moolenaar 	case UPTODATE:  return "up-to-date";
4423955d011SMarcel Moolenaar 	case ERROR:     return "error when made";
4433955d011SMarcel Moolenaar 	case ABORTED:   return "aborted";
4443955d011SMarcel Moolenaar 	default:        return "unknown enum_made value";
4453955d011SMarcel Moolenaar 	}
4463955d011SMarcel Moolenaar }
4473955d011SMarcel Moolenaar 
4483955d011SMarcel Moolenaar static const char *
GNode_OpName(const GNode * gn)4493955d011SMarcel Moolenaar GNode_OpName(const GNode *gn)
4503955d011SMarcel Moolenaar {
4513955d011SMarcel Moolenaar 	switch (gn->type & OP_OPMASK) {
4523955d011SMarcel Moolenaar 	case OP_DEPENDS:
4533955d011SMarcel Moolenaar 		return ":";
4543955d011SMarcel Moolenaar 	case OP_FORCE:
4553955d011SMarcel Moolenaar 		return "!";
4569093286bSSimon J. Gerraty 	case OP_DOUBLEDEP:
4573955d011SMarcel Moolenaar 		return "::";
4589093286bSSimon J. Gerraty 	}
4593955d011SMarcel Moolenaar 	return "";
4603955d011SMarcel Moolenaar }
4613955d011SMarcel Moolenaar 
4623955d011SMarcel Moolenaar static bool
GNodeFlags_IsNone(GNodeFlags flags)4633955d011SMarcel Moolenaar GNodeFlags_IsNone(GNodeFlags flags)
4643955d011SMarcel Moolenaar {
4653955d011SMarcel Moolenaar 	return !flags.remake
4663955d011SMarcel Moolenaar 	       && !flags.childMade
4673955d011SMarcel Moolenaar 	       && !flags.force
4683955d011SMarcel Moolenaar 	       && !flags.doneWait
4693955d011SMarcel Moolenaar 	       && !flags.doneOrder
4703955d011SMarcel Moolenaar 	       && !flags.fromDepend
4713955d011SMarcel Moolenaar 	       && !flags.doneAllsrc
4723955d011SMarcel Moolenaar 	       && !flags.cycle
4733955d011SMarcel Moolenaar 	       && !flags.doneCycle;
4743955d011SMarcel Moolenaar }
4753955d011SMarcel Moolenaar 
4763955d011SMarcel Moolenaar /* Print the contents of a node. */
4773955d011SMarcel Moolenaar void
Targ_PrintNode(GNode * gn,int pass)4783955d011SMarcel Moolenaar Targ_PrintNode(GNode *gn, int pass)
4793955d011SMarcel Moolenaar {
4803955d011SMarcel Moolenaar 	debug_printf("# %s%s", gn->name, gn->cohort_num);
4819093286bSSimon J. Gerraty 	GNode_FprintDetails(opts.debug_file, ", ", gn, "\n");
4823955d011SMarcel Moolenaar 	if (GNodeFlags_IsNone(gn->flags))
4839093286bSSimon J. Gerraty 		return;
4843955d011SMarcel Moolenaar 
4853955d011SMarcel Moolenaar 	if (!GNode_IsTarget(gn))
4863955d011SMarcel Moolenaar 		return;
4873955d011SMarcel Moolenaar 
4883955d011SMarcel Moolenaar 	debug_printf("#\n");
4893955d011SMarcel Moolenaar 	if (gn == mainNode)
4903955d011SMarcel Moolenaar 		debug_printf("# *** MAIN TARGET ***\n");
4913955d011SMarcel Moolenaar 
4923955d011SMarcel Moolenaar 	if (pass >= 2) {
4933955d011SMarcel Moolenaar 		if (gn->unmade > 0)
4943955d011SMarcel Moolenaar 			debug_printf("# %d unmade children\n", gn->unmade);
4953955d011SMarcel Moolenaar 		else
4963955d011SMarcel Moolenaar 			debug_printf("# No unmade children\n");
4973955d011SMarcel Moolenaar 		if (!(gn->type & (OP_JOIN | OP_USE | OP_USEBEFORE | OP_EXEC))) {
4983955d011SMarcel Moolenaar 			if (gn->mtime != 0) {
4993955d011SMarcel Moolenaar 				debug_printf("# last modified %s: %s\n",
5003955d011SMarcel Moolenaar 				    Targ_FmtTime(gn->mtime),
5013955d011SMarcel Moolenaar 				    GNodeMade_Name(gn->made));
5023955d011SMarcel Moolenaar 			} else if (gn->made != UNMADE) {
5033955d011SMarcel Moolenaar 				debug_printf("# nonexistent (maybe): %s\n",
5043955d011SMarcel Moolenaar 				    GNodeMade_Name(gn->made));
5053955d011SMarcel Moolenaar 			} else
5063955d011SMarcel Moolenaar 				debug_printf("# unmade\n");
5073955d011SMarcel Moolenaar 		}
5083955d011SMarcel Moolenaar 		PrintNodeNamesLine("implicit parents", &gn->implicitParents);
5093955d011SMarcel Moolenaar 	} else {
5103955d011SMarcel Moolenaar 		if (gn->unmade != 0)
5113955d011SMarcel Moolenaar 			debug_printf("# %d unmade children\n", gn->unmade);
5123955d011SMarcel Moolenaar 	}
5133955d011SMarcel Moolenaar 
5143955d011SMarcel Moolenaar 	PrintNodeNamesLine("parents", &gn->parents);
5153955d011SMarcel Moolenaar 	PrintNodeNamesLine("order_pred", &gn->order_pred);
5163955d011SMarcel Moolenaar 	PrintNodeNamesLine("order_succ", &gn->order_succ);
5173955d011SMarcel Moolenaar 
5183955d011SMarcel Moolenaar 	debug_printf("%-16s%s", gn->name, GNode_OpName(gn));
5193955d011SMarcel Moolenaar 	Targ_PrintType(gn->type);
5203955d011SMarcel Moolenaar 	PrintNodeNames(&gn->children);
5213955d011SMarcel Moolenaar 	debug_printf("\n");
5223955d011SMarcel Moolenaar 	Targ_PrintCmds(gn);
5233955d011SMarcel Moolenaar 	debug_printf("\n\n");
524e1cee40dSSimon J. Gerraty 	if (gn->type & OP_DOUBLEDEP)
5253955d011SMarcel Moolenaar 		Targ_PrintNodes(&gn->cohorts, pass);
5263955d011SMarcel Moolenaar }
527e1cee40dSSimon J. Gerraty 
5283955d011SMarcel Moolenaar void
Targ_PrintNodes(GNodeList * gnodes,int pass)5293955d011SMarcel Moolenaar Targ_PrintNodes(GNodeList *gnodes, int pass)
5303955d011SMarcel Moolenaar {
5313955d011SMarcel Moolenaar 	GNodeListNode *ln;
5323955d011SMarcel Moolenaar 
5333955d011SMarcel Moolenaar 	for (ln = gnodes->first; ln != NULL; ln = ln->next)
5343955d011SMarcel Moolenaar 		Targ_PrintNode(ln->datum, pass);
5353955d011SMarcel Moolenaar }
5363955d011SMarcel Moolenaar 
5373955d011SMarcel Moolenaar static void
PrintOnlySources(void)5383955d011SMarcel Moolenaar PrintOnlySources(void)
5393955d011SMarcel Moolenaar {
5403955d011SMarcel Moolenaar 	GNodeListNode *ln;
5413955d011SMarcel Moolenaar 
5423955d011SMarcel Moolenaar 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
5433955d011SMarcel Moolenaar 		GNode *gn = ln->datum;
5443955d011SMarcel Moolenaar 		if (GNode_IsTarget(gn))
5453955d011SMarcel Moolenaar 			continue;
5463955d011SMarcel Moolenaar 
5473955d011SMarcel Moolenaar 		debug_printf("#\t%s [%s]", gn->name, GNode_Path(gn));
5483955d011SMarcel Moolenaar 		Targ_PrintType(gn->type);
5493955d011SMarcel Moolenaar 		debug_printf("\n");
5503955d011SMarcel Moolenaar 	}
5513955d011SMarcel Moolenaar }
5529093286bSSimon J. Gerraty 
5533955d011SMarcel Moolenaar /*
5543955d011SMarcel Moolenaar  * Input:
5553955d011SMarcel Moolenaar  *	pass		1 => before processing
5563955d011SMarcel Moolenaar  *			2 => after processing
5573955d011SMarcel Moolenaar  *			3 => after processing, an error occurred
5583955d011SMarcel Moolenaar  */
5593955d011SMarcel Moolenaar void
Targ_PrintGraph(int pass)5603955d011SMarcel Moolenaar Targ_PrintGraph(int pass)
5613955d011SMarcel Moolenaar {
5623955d011SMarcel Moolenaar 	debug_printf("#*** Input graph:\n");
5633955d011SMarcel Moolenaar 	Targ_PrintNodes(&allTargets, pass);
5643955d011SMarcel Moolenaar 	debug_printf("\n");
5653955d011SMarcel Moolenaar 	debug_printf("\n");
5663955d011SMarcel Moolenaar 
5673955d011SMarcel Moolenaar 	debug_printf("#\n");
5683955d011SMarcel Moolenaar 	debug_printf("#   Files that are only sources:\n");
5693955d011SMarcel Moolenaar 	PrintOnlySources();
5703955d011SMarcel Moolenaar 
5713955d011SMarcel Moolenaar 	debug_printf("#*** Global Variables:\n");
5723955d011SMarcel Moolenaar 	Var_Dump(SCOPE_GLOBAL);
5733955d011SMarcel Moolenaar 
5743955d011SMarcel Moolenaar 	debug_printf("#*** Command-line Variables:\n");
5753955d011SMarcel Moolenaar 	Var_Dump(SCOPE_CMDLINE);
5763955d011SMarcel Moolenaar 
5773955d011SMarcel Moolenaar 	debug_printf("\n");
5783955d011SMarcel Moolenaar 	Dir_PrintDirectories();
5793955d011SMarcel Moolenaar 	debug_printf("\n");
5803955d011SMarcel Moolenaar 
5813955d011SMarcel Moolenaar 	Suff_PrintAll();
5823955d011SMarcel Moolenaar }
5833955d011SMarcel Moolenaar 
5843955d011SMarcel Moolenaar /*
5853955d011SMarcel Moolenaar  * Propagate some type information to cohort nodes (those from the '::'
5863955d011SMarcel Moolenaar  * dependency operator).
5873955d011SMarcel Moolenaar  *
5883955d011SMarcel Moolenaar  * Should be called after the makefiles are parsed but before any action is
5893955d011SMarcel Moolenaar  * taken.
5903955d011SMarcel Moolenaar  */
5913955d011SMarcel Moolenaar void
Targ_Propagate(void)5923955d011SMarcel Moolenaar Targ_Propagate(void)
5933955d011SMarcel Moolenaar {
5943955d011SMarcel Moolenaar 	GNodeListNode *ln, *cln;
5953955d011SMarcel Moolenaar 
5963955d011SMarcel Moolenaar 	for (ln = allTargets.first; ln != NULL; ln = ln->next) {
5973955d011SMarcel Moolenaar 		GNode *gn = ln->datum;
5983955d011SMarcel Moolenaar 		GNodeType type = gn->type;
5993955d011SMarcel Moolenaar 
6003955d011SMarcel Moolenaar 		if (!(type & OP_DOUBLEDEP))
6013955d011SMarcel Moolenaar 			continue;
6023955d011SMarcel Moolenaar 
6033955d011SMarcel Moolenaar 		for (cln = gn->cohorts.first; cln != NULL; cln = cln->next) {
6043955d011SMarcel Moolenaar 			GNode *cohort = cln->datum;
6053955d011SMarcel Moolenaar 
6063955d011SMarcel Moolenaar 			cohort->type |= type & (unsigned)~OP_OPMASK;
6073955d011SMarcel Moolenaar 		}
6083955d011SMarcel Moolenaar 	}
6093955d011SMarcel Moolenaar }
6103955d011SMarcel Moolenaar