targ.c revision 168893
1141104Sharti/*-
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
3762833Swsanchez *
3862833Swsanchez * @(#)targ.c	8.2 (Berkeley) 3/19/94
391590Srgrimes */
401590Srgrimes
4162833Swsanchez#include <sys/cdefs.h>
4294587Sobrien__FBSDID("$FreeBSD: head/usr.bin/make/targ.c 168893 2007-04-20 06:33:25Z fjoe $");
431590Srgrimes
44144469Sharti/*
45144469Sharti * Functions for maintaining the Lst allTargets. Target nodes are
461590Srgrimes * kept in two structures: a Lst, maintained by the list library, and a
471590Srgrimes * hash table, maintained by the hash library.
481590Srgrimes *
491590Srgrimes * Interface:
50144469Sharti *	Targ_Init	Initialization procedure.
511590Srgrimes *
52144469Sharti *	Targ_NewGN	Create a new GNode for the passed target (string).
53144469Sharti *			The node is *not* placed in the hash table, though all
54144469Sharti *			its fields are initialized.
551590Srgrimes *
56144469Sharti *	Targ_FindNode	Find the node for a given target, creating and storing
57144469Sharti *			it if it doesn't exist and the flags are right
58144469Sharti *			(TARG_CREATE)
591590Srgrimes *
60144469Sharti *	Targ_FindList	Given a list of names, find nodes for all of them. If a
61144469Sharti *			name doesn't exist and the TARG_NOCREATE flag was given,
62144469Sharti *			an error message is printed. Else, if a name doesn't
63144469Sharti *			exist, its node is created.
641590Srgrimes *
65144469Sharti *	Targ_Ignore	Return TRUE if errors should be ignored when creating
66144469Sharti *			the given target.
671590Srgrimes *
68144469Sharti *	Targ_Silent	Return TRUE if we should be silent when creating the
69144469Sharti *			given target.
701590Srgrimes *
71144469Sharti *	Targ_Precious	Return TRUE if the target is precious and should not
72144469Sharti *			be removed if we are interrupted.
731590Srgrimes *
741590Srgrimes * Debugging:
75144469Sharti *	Targ_PrintGraph	Print out the entire graphm all variables and statistics
76144469Sharti *			for the directory cache. Should print something for
77144469Sharti *			suffixes, too, but...
781590Srgrimes */
791590Srgrimes
80141104Sharti#include <stdio.h>
81141104Sharti#include <string.h>
821590Srgrimes
83141104Sharti#include "dir.h"
84141104Sharti#include "globals.h"
85141104Sharti#include "GNode.h"
86141104Sharti#include "hash.h"
87141104Sharti#include "make.h"
88141104Sharti#include "suff.h"
89141104Sharti#include "targ.h"
90141104Sharti#include "util.h"
91141104Sharti#include "var.h"
92141104Sharti
93138916Sharti/* the list of all targets found so far */
94138916Shartistatic Lst allTargets = Lst_Initializer(allTargets);
95138916Sharti
961590Srgrimesstatic Hash_Table targets;	/* a hash table of same */
971590Srgrimes
98103503Sjmallett#define	HTSIZE	191		/* initial size of hash table */
991590Srgrimes
100144469Sharti/**
101144469Sharti * Targ_Init
1021590Srgrimes *	Initialize this module
1031590Srgrimes *
1041590Srgrimes * Side Effects:
1051590Srgrimes *	The allTargets list and the targets hash table are initialized
1061590Srgrimes */
1071590Srgrimesvoid
108138232ShartiTarg_Init(void)
1091590Srgrimes{
110138232Sharti
111144469Sharti	Hash_InitTable(&targets, HTSIZE);
1121590Srgrimes}
1131590Srgrimes
114144469Sharti/**
115144469Sharti * Targ_NewGN
1161590Srgrimes *	Create and initialize a new graph node
1171590Srgrimes *
1181590Srgrimes * Results:
1191590Srgrimes *	An initialized graph node with the name field filled with a copy
1201590Srgrimes *	of the passed name
1211590Srgrimes *
1221590Srgrimes * Side Effects:
1235814Sjkh *	The gnode is added to the list of all gnodes.
1241590Srgrimes */
1251590SrgrimesGNode *
126141252ShartiTarg_NewGN(const char *name)
1271590Srgrimes{
128144469Sharti	GNode *gn;
1291590Srgrimes
130144469Sharti	gn = emalloc(sizeof(GNode));
131144469Sharti	gn->name = estrdup(name);
132144469Sharti	gn->path = NULL;
133144469Sharti	if (name[0] == '-' && name[1] == 'l') {
134144469Sharti		gn->type = OP_LIB;
135144469Sharti	} else {
136144469Sharti		gn->type = 0;
137144469Sharti	}
138144469Sharti	gn->unmade = 0;
139144469Sharti	gn->make = FALSE;
140144469Sharti	gn->made = UNMADE;
141144469Sharti	gn->childMade = FALSE;
142144469Sharti	gn->order = 0;
143144469Sharti	gn->mtime = gn->cmtime = 0;
144168893Sfjoe	gn->cmtime_gn = NULL;
145144469Sharti	Lst_Init(&gn->iParents);
146144469Sharti	Lst_Init(&gn->cohorts);
147144469Sharti	Lst_Init(&gn->parents);
148144469Sharti	Lst_Init(&gn->children);
149144469Sharti	Lst_Init(&gn->successors);
150144469Sharti	Lst_Init(&gn->preds);
151144469Sharti	Lst_Init(&gn->context);
152144469Sharti	Lst_Init(&gn->commands);
153144469Sharti	gn->suffix = NULL;
1541590Srgrimes
155144469Sharti	return (gn);
1561590Srgrimes}
1571590Srgrimes
158144469Sharti/**
159144469Sharti * Targ_FindNode
1601590Srgrimes *	Find a node in the list using the given name for matching
1611590Srgrimes *
1621590Srgrimes * Results:
16369527Swill *	The node in the list if it was. If it wasn't, return NULL of
1641590Srgrimes *	flags was TARG_NOCREATE or the newly created and initialized node
1651590Srgrimes *	if it was TARG_CREATE
1661590Srgrimes *
1671590Srgrimes * Side Effects:
1681590Srgrimes *	Sometimes a node is created and added to the list
1691590Srgrimes */
1701590SrgrimesGNode *
171141252ShartiTarg_FindNode(const char *name, int flags)
1721590Srgrimes{
173144469Sharti	GNode		*gn;	/* node in that element */
174144469Sharti	Hash_Entry	*he;	/* New or used hash entry for node */
175144469Sharti	Boolean		isNew;	/* Set TRUE if Hash_CreateEntry had to create */
176144469Sharti		      		/* an entry for the node */
1771590Srgrimes
178144469Sharti	if (flags & TARG_CREATE) {
179144469Sharti		he = Hash_CreateEntry(&targets, name, &isNew);
180144469Sharti		if (isNew) {
181144469Sharti			gn = Targ_NewGN(name);
182144469Sharti			Hash_SetValue(he, gn);
183144469Sharti			Lst_AtEnd(&allTargets, gn);
184144469Sharti		}
185144469Sharti	} else {
186144469Sharti		he = Hash_FindEntry(&targets, name);
1871590Srgrimes	}
1881590Srgrimes
189144469Sharti	if (he == NULL) {
190144469Sharti		return (NULL);
191144469Sharti	} else {
192144469Sharti		return (Hash_GetValue(he));
193144469Sharti	}
1941590Srgrimes}
1951590Srgrimes
196144469Sharti/**
197144469Sharti * Targ_FindList
1988874Srgrimes *	Make a complete list of GNodes from the given list of names
1991590Srgrimes *
2001590Srgrimes * Results:
2011590Srgrimes *	A complete list of graph nodes corresponding to all instances of all
2028874Srgrimes *	the names in names.
2031590Srgrimes *
2041590Srgrimes * Side Effects:
2051590Srgrimes *	If flags is TARG_CREATE, nodes will be created for all names in
2061590Srgrimes *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
2071590Srgrimes *	an error message will be printed for each name which can't be found.
2081590Srgrimes */
209138916Shartivoid
210138916ShartiTarg_FindList(Lst *nodes, Lst *names, int flags)
2111590Srgrimes{
212144469Sharti	LstNode	*ln;	/* name list element */
213144469Sharti	GNode	*gn;	/* node in tLn */
214144469Sharti	char	*name;
2151590Srgrimes
216144469Sharti	for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
217144469Sharti		name = Lst_Datum(ln);
218144469Sharti		gn = Targ_FindNode(name, flags);
219144469Sharti		if (gn != NULL) {
220144469Sharti			/*
221144469Sharti			 * Note: Lst_AtEnd must come before the Lst_Concat so
222144469Sharti			 * the nodes are added to the list in the order in which
223144469Sharti			 * they were encountered in the makefile.
224144469Sharti			 */
225144469Sharti			Lst_AtEnd(nodes, gn);
226144469Sharti			if (gn->type & OP_DOUBLEDEP) {
227144469Sharti				Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
228144469Sharti			}
229144469Sharti
230144469Sharti		} else if (flags == TARG_NOCREATE) {
231144469Sharti			Error("\"%s\" -- target unknown.", name);
232144469Sharti		}
2331590Srgrimes	}
2341590Srgrimes}
2351590Srgrimes
236144469Sharti/**
237144469Sharti * Targ_Ignore
2381590Srgrimes *	Return true if should ignore errors when creating gn
2391590Srgrimes *
2401590Srgrimes * Results:
2411590Srgrimes *	TRUE if should ignore errors
2421590Srgrimes */
2431590SrgrimesBoolean
244138232ShartiTarg_Ignore(GNode *gn)
2451590Srgrimes{
246138232Sharti
247144469Sharti	if (ignoreErrors || (gn->type & OP_IGNORE)) {
248144469Sharti		return (TRUE);
249144469Sharti	} else {
250144469Sharti		return (FALSE);
251144469Sharti	}
2521590Srgrimes}
2531590Srgrimes
254144469Sharti/**
255144469Sharti * Targ_Silent
2561590Srgrimes *	Return true if be silent when creating gn
2571590Srgrimes *
2581590Srgrimes * Results:
2591590Srgrimes *	TRUE if should be silent
2601590Srgrimes */
2611590SrgrimesBoolean
262138232ShartiTarg_Silent(GNode *gn)
2631590Srgrimes{
264138232Sharti
265144469Sharti	if (beSilent || (gn->type & OP_SILENT)) {
266144469Sharti		return (TRUE);
267144469Sharti	} else {
268144469Sharti		return (FALSE);
269144469Sharti	}
2701590Srgrimes}
2711590Srgrimes
272144469Sharti/**
273144469Sharti * Targ_Precious
2741590Srgrimes *	See if the given target is precious
2751590Srgrimes *
2761590Srgrimes * Results:
2771590Srgrimes *	TRUE if it is precious. FALSE otherwise
2781590Srgrimes */
2791590SrgrimesBoolean
280138232ShartiTarg_Precious(GNode *gn)
2811590Srgrimes{
282138232Sharti
283144469Sharti	if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
284144469Sharti		return (TRUE);
285144469Sharti	} else {
286144469Sharti		return (FALSE);
287144469Sharti	}
2881590Srgrimes}
2891590Srgrimes
290144469Shartistatic GNode	*mainTarg;	/* the main target, as set by Targ_SetMain */
2911590Srgrimes
292144469Sharti/**
293144469Sharti * Targ_SetMain
2941590Srgrimes *	Set our idea of the main target we'll be creating. Used for
2951590Srgrimes *	debugging output.
2961590Srgrimes *
2971590Srgrimes * Side Effects:
2981590Srgrimes *	"mainTarg" is set to the main target's node.
2991590Srgrimes */
3001590Srgrimesvoid
301138232ShartiTarg_SetMain(GNode *gn)
3021590Srgrimes{
303138232Sharti
304144469Sharti	mainTarg = gn;
3051590Srgrimes}
3061590Srgrimes
307144469Sharti/**
308144469Sharti * Targ_FmtTime
3091590Srgrimes *	Format a modification time in some reasonable way and return it.
3101590Srgrimes *
3111590Srgrimes * Results:
3121590Srgrimes *	The time reformatted.
3131590Srgrimes *
3141590Srgrimes * Side Effects:
3151590Srgrimes *	The time is placed in a static area, so it is overwritten
3161590Srgrimes *	with each call.
3171590Srgrimes */
3181590Srgrimeschar *
319138232ShartiTarg_FmtTime(time_t modtime)
3201590Srgrimes{
321144469Sharti	struct tm	*parts;
322144469Sharti	static char	buf[128];
3231590Srgrimes
324144469Sharti	parts = localtime(&modtime);
3251590Srgrimes
326144469Sharti	strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts);
327144469Sharti	buf[sizeof(buf) - 1] = '\0';
328144469Sharti	return (buf);
3291590Srgrimes}
3308874Srgrimes
331144469Sharti/**
332144469Sharti * Targ_PrintType
3331590Srgrimes *	Print out a type field giving only those attributes the user can
3341590Srgrimes *	set.
3351590Srgrimes */
3361590Srgrimesvoid
337138232ShartiTarg_PrintType(int type)
3381590Srgrimes{
339146184Sharti	static const struct flag2str type2str[] = {
340146184Sharti		{ OP_OPTIONAL,	".OPTIONAL" },
341146184Sharti		{ OP_USE,	".USE" },
342146184Sharti		{ OP_EXEC,	".EXEC" },
343146184Sharti		{ OP_IGNORE,	".IGNORE" },
344146184Sharti		{ OP_PRECIOUS,	".PRECIOUS" },
345146184Sharti		{ OP_SILENT,	".SILENT" },
346146184Sharti		{ OP_MAKE,	".MAKE" },
347146184Sharti		{ OP_JOIN,	".JOIN" },
348146184Sharti		{ OP_INVISIBLE,	".INVISIBLE" },
349146184Sharti		{ OP_NOTMAIN,	".NOTMAIN" },
350146184Sharti		{ OP_PHONY,	".PHONY" },
351146184Sharti		{ OP_LIB,	".LIB" },
352146184Sharti		{ OP_MEMBER,	".MEMBER" },
353146184Sharti		{ OP_ARCHV,	".ARCHV" },
354146184Sharti		{ 0,		NULL }
355146184Sharti	};
3568874Srgrimes
357144469Sharti	type &= ~OP_OPMASK;
358146184Sharti	if (!DEBUG(TARG))
359146184Sharti		type &= ~(OP_ARCHV | OP_LIB | OP_MEMBER);
360146184Sharti	print_flags(stdout, type2str, type, 0);
3611590Srgrimes}
3621590Srgrimes
363144469Sharti/**
364144469Sharti * TargPrintNode
3651590Srgrimes *	print the contents of a node
3661590Srgrimes */
3671590Srgrimesstatic int
368143650ShartiTargPrintNode(const GNode *gn, int pass)
3691590Srgrimes{
370144469Sharti	const LstNode	*tln;
371138232Sharti
372144469Sharti	if (!OP_NOP(gn->type)) {
373144469Sharti		printf("#\n");
374144469Sharti		if (gn == mainTarg) {
375144469Sharti			printf("# *** MAIN TARGET ***\n");
3761590Srgrimes		}
377144469Sharti		if (pass == 2) {
378144469Sharti			if (gn->unmade) {
379144469Sharti				printf("# %d unmade children\n", gn->unmade);
380144469Sharti			} else {
381144469Sharti				printf("# No unmade children\n");
382144469Sharti			}
383144469Sharti			if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
384144469Sharti				if (gn->mtime != 0) {
385144469Sharti					printf("# last modified %s: %s\n",
386144469Sharti					    Targ_FmtTime(gn->mtime),
387144469Sharti					    gn->made == UNMADE ? "unmade" :
388144469Sharti					    gn->made == MADE ? "made" :
389144469Sharti					    gn->made == UPTODATE ? "up-to-date":
390144469Sharti					    "error when made");
391144469Sharti				} else if (gn->made != UNMADE) {
392144469Sharti					printf("# non-existent (maybe): %s\n",
393144469Sharti					    gn->made == MADE ? "made" :
394144469Sharti					    gn->made == UPTODATE ? "up-to-date":
395144469Sharti					    gn->made == ERROR?"error when made":
396144469Sharti				 	    "aborted");
397144469Sharti				} else {
398144469Sharti					printf("# unmade\n");
399144469Sharti				}
400144469Sharti			}
401144469Sharti			if (!Lst_IsEmpty(&gn->iParents)) {
402144469Sharti				printf("# implicit parents: ");
403144469Sharti				LST_FOREACH(tln, &gn->iParents)
404144469Sharti					printf("%s ", ((const GNode *)
405144469Sharti					    Lst_Datum(tln))->name);
406144469Sharti				printf("\n");
407144469Sharti			}
408144469Sharti		}
409144469Sharti		if (!Lst_IsEmpty(&gn->parents)) {
410144469Sharti			printf("# parents: ");
411144469Sharti			LST_FOREACH(tln, &gn->parents)
412144469Sharti				printf("%s ", ((const GNode *)
413144469Sharti				    Lst_Datum(tln))->name);
414144469Sharti			printf("\n");
415144469Sharti		}
416144469Sharti
417144469Sharti		printf("%-16s", gn->name);
418144469Sharti		switch (gn->type & OP_OPMASK) {
419144469Sharti		  case OP_DEPENDS:
420144469Sharti			printf(": ");
421144469Sharti			break;
422144469Sharti		  case OP_FORCE:
423144469Sharti			printf("! ");
424144469Sharti			break;
425144469Sharti		  case OP_DOUBLEDEP:
426144469Sharti			printf(":: ");
427144469Sharti			break;
428144469Sharti		  default:
429144469Sharti			break;
430144469Sharti		}
431144469Sharti		Targ_PrintType(gn->type);
432144469Sharti		LST_FOREACH(tln, &gn->children)
433143650Sharti			printf("%s ", ((const GNode *)Lst_Datum(tln))->name);
434143650Sharti		printf("\n");
435144469Sharti		LST_FOREACH(tln, &gn->commands)
436144469Sharti			printf("\t%s\n", (const char *)Lst_Datum(tln));
437144469Sharti		printf("\n\n");
438144469Sharti		if (gn->type & OP_DOUBLEDEP) {
439144469Sharti			LST_FOREACH(tln, &gn->cohorts)
440144469Sharti				TargPrintNode((const GNode *)Lst_Datum(tln),
441144469Sharti				    pass);
442144469Sharti		}
4431590Srgrimes	}
444144469Sharti	return (0);
4451590Srgrimes}
4461590Srgrimes
447144469Sharti/**
448144469Sharti * Targ_PrintGraph
449104696Sjmallett *	Print the entire graph.
4501590Srgrimes */
4511590Srgrimesvoid
452138232ShartiTarg_PrintGraph(int pass)
4531590Srgrimes{
454144469Sharti	const GNode	*gn;
455144469Sharti	const LstNode	*tln;
456138264Sharti
457144469Sharti	printf("#*** Input graph:\n");
458144469Sharti	LST_FOREACH(tln, &allTargets)
459144469Sharti		TargPrintNode((const GNode *)Lst_Datum(tln), pass);
460144469Sharti	printf("\n\n");
461143650Sharti
462144469Sharti	printf("#\n#   Files that are only sources:\n");
463144469Sharti	LST_FOREACH(tln, &allTargets) {
464144469Sharti		gn = Lst_Datum(tln);
465144469Sharti		if (OP_NOP(gn->type))
466144469Sharti			printf("#\t%s [%s]\n", gn->name,
467144469Sharti			    gn->path ? gn->path : gn->name);
468144469Sharti	}
469146039Sharti	Var_Dump();
470144469Sharti	printf("\n");
471144469Sharti	Dir_PrintDirectories();
472144469Sharti	printf("\n");
473144469Sharti	Suff_PrintAll();
4741590Srgrimes}
475