targ.c revision 144469
1/*-
2 * Copyright (c) 1988, 1989, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1989 by Berkeley Softworks
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Adam de Boor.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)targ.c	8.2 (Berkeley) 3/19/94
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/usr.bin/make/targ.c 144469 2005-04-01 11:12:29Z harti $");
43
44/*
45 * Functions for maintaining the Lst allTargets. Target nodes are
46 * kept in two structures: a Lst, maintained by the list library, and a
47 * hash table, maintained by the hash library.
48 *
49 * Interface:
50 *	Targ_Init	Initialization procedure.
51 *
52 *	Targ_NewGN	Create a new GNode for the passed target (string).
53 *			The node is *not* placed in the hash table, though all
54 *			its fields are initialized.
55 *
56 *	Targ_FindNode	Find the node for a given target, creating and storing
57 *			it if it doesn't exist and the flags are right
58 *			(TARG_CREATE)
59 *
60 *	Targ_FindList	Given a list of names, find nodes for all of them. If a
61 *			name doesn't exist and the TARG_NOCREATE flag was given,
62 *			an error message is printed. Else, if a name doesn't
63 *			exist, its node is created.
64 *
65 *	Targ_Ignore	Return TRUE if errors should be ignored when creating
66 *			the given target.
67 *
68 *	Targ_Silent	Return TRUE if we should be silent when creating the
69 *			given target.
70 *
71 *	Targ_Precious	Return TRUE if the target is precious and should not
72 *			be removed if we are interrupted.
73 *
74 * Debugging:
75 *	Targ_PrintGraph	Print out the entire graphm all variables and statistics
76 *			for the directory cache. Should print something for
77 *			suffixes, too, but...
78 */
79
80#include <stdio.h>
81#include <string.h>
82
83#include "dir.h"
84#include "globals.h"
85#include "GNode.h"
86#include "hash.h"
87#include "make.h"
88#include "suff.h"
89#include "targ.h"
90#include "util.h"
91#include "var.h"
92
93/* the list of all targets found so far */
94static Lst allTargets = Lst_Initializer(allTargets);
95
96static Hash_Table targets;	/* a hash table of same */
97
98#define	HTSIZE	191		/* initial size of hash table */
99
100/**
101 * Targ_Init
102 *	Initialize this module
103 *
104 * Side Effects:
105 *	The allTargets list and the targets hash table are initialized
106 */
107void
108Targ_Init(void)
109{
110
111	Hash_InitTable(&targets, HTSIZE);
112}
113
114/**
115 * Targ_NewGN
116 *	Create and initialize a new graph node
117 *
118 * Results:
119 *	An initialized graph node with the name field filled with a copy
120 *	of the passed name
121 *
122 * Side Effects:
123 *	The gnode is added to the list of all gnodes.
124 */
125GNode *
126Targ_NewGN(const char *name)
127{
128	GNode *gn;
129
130	gn = emalloc(sizeof(GNode));
131	gn->name = estrdup(name);
132	gn->path = NULL;
133	if (name[0] == '-' && name[1] == 'l') {
134		gn->type = OP_LIB;
135	} else {
136		gn->type = 0;
137	}
138	gn->unmade = 0;
139	gn->make = FALSE;
140	gn->made = UNMADE;
141	gn->childMade = FALSE;
142	gn->order = 0;
143	gn->mtime = gn->cmtime = 0;
144	Lst_Init(&gn->iParents);
145	Lst_Init(&gn->cohorts);
146	Lst_Init(&gn->parents);
147	Lst_Init(&gn->children);
148	Lst_Init(&gn->successors);
149	Lst_Init(&gn->preds);
150	Lst_Init(&gn->context);
151	Lst_Init(&gn->commands);
152	gn->suffix = NULL;
153
154	return (gn);
155}
156
157/**
158 * Targ_FindNode
159 *	Find a node in the list using the given name for matching
160 *
161 * Results:
162 *	The node in the list if it was. If it wasn't, return NULL of
163 *	flags was TARG_NOCREATE or the newly created and initialized node
164 *	if it was TARG_CREATE
165 *
166 * Side Effects:
167 *	Sometimes a node is created and added to the list
168 */
169GNode *
170Targ_FindNode(const char *name, int flags)
171{
172	GNode		*gn;	/* node in that element */
173	Hash_Entry	*he;	/* New or used hash entry for node */
174	Boolean		isNew;	/* Set TRUE if Hash_CreateEntry had to create */
175		      		/* an entry for the node */
176
177	if (flags & TARG_CREATE) {
178		he = Hash_CreateEntry(&targets, name, &isNew);
179		if (isNew) {
180			gn = Targ_NewGN(name);
181			Hash_SetValue(he, gn);
182			Lst_AtEnd(&allTargets, gn);
183		}
184	} else {
185		he = Hash_FindEntry(&targets, name);
186	}
187
188	if (he == NULL) {
189		return (NULL);
190	} else {
191		return (Hash_GetValue(he));
192	}
193}
194
195/**
196 * Targ_FindList
197 *	Make a complete list of GNodes from the given list of names
198 *
199 * Results:
200 *	A complete list of graph nodes corresponding to all instances of all
201 *	the names in names.
202 *
203 * Side Effects:
204 *	If flags is TARG_CREATE, nodes will be created for all names in
205 *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
206 *	an error message will be printed for each name which can't be found.
207 */
208void
209Targ_FindList(Lst *nodes, Lst *names, int flags)
210{
211	LstNode	*ln;	/* name list element */
212	GNode	*gn;	/* node in tLn */
213	char	*name;
214
215	for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
216		name = Lst_Datum(ln);
217		gn = Targ_FindNode(name, flags);
218		if (gn != NULL) {
219			/*
220			 * Note: Lst_AtEnd must come before the Lst_Concat so
221			 * the nodes are added to the list in the order in which
222			 * they were encountered in the makefile.
223			 */
224			Lst_AtEnd(nodes, gn);
225			if (gn->type & OP_DOUBLEDEP) {
226				Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
227			}
228
229		} else if (flags == TARG_NOCREATE) {
230			Error("\"%s\" -- target unknown.", name);
231		}
232	}
233}
234
235/**
236 * Targ_Ignore
237 *	Return true if should ignore errors when creating gn
238 *
239 * Results:
240 *	TRUE if should ignore errors
241 */
242Boolean
243Targ_Ignore(GNode *gn)
244{
245
246	if (ignoreErrors || (gn->type & OP_IGNORE)) {
247		return (TRUE);
248	} else {
249		return (FALSE);
250	}
251}
252
253/**
254 * Targ_Silent
255 *	Return true if be silent when creating gn
256 *
257 * Results:
258 *	TRUE if should be silent
259 */
260Boolean
261Targ_Silent(GNode *gn)
262{
263
264	if (beSilent || (gn->type & OP_SILENT)) {
265		return (TRUE);
266	} else {
267		return (FALSE);
268	}
269}
270
271/**
272 * Targ_Precious
273 *	See if the given target is precious
274 *
275 * Results:
276 *	TRUE if it is precious. FALSE otherwise
277 */
278Boolean
279Targ_Precious(GNode *gn)
280{
281
282	if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
283		return (TRUE);
284	} else {
285		return (FALSE);
286	}
287}
288
289static GNode	*mainTarg;	/* the main target, as set by Targ_SetMain */
290
291/**
292 * Targ_SetMain
293 *	Set our idea of the main target we'll be creating. Used for
294 *	debugging output.
295 *
296 * Side Effects:
297 *	"mainTarg" is set to the main target's node.
298 */
299void
300Targ_SetMain(GNode *gn)
301{
302
303	mainTarg = gn;
304}
305
306/**
307 * Targ_FmtTime
308 *	Format a modification time in some reasonable way and return it.
309 *
310 * Results:
311 *	The time reformatted.
312 *
313 * Side Effects:
314 *	The time is placed in a static area, so it is overwritten
315 *	with each call.
316 */
317char *
318Targ_FmtTime(time_t modtime)
319{
320	struct tm	*parts;
321	static char	buf[128];
322
323	parts = localtime(&modtime);
324
325	strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts);
326	buf[sizeof(buf) - 1] = '\0';
327	return (buf);
328}
329
330/**
331 * Targ_PrintType
332 *	Print out a type field giving only those attributes the user can
333 *	set.
334 */
335void
336Targ_PrintType(int type)
337{
338	int	tbit;
339
340#define	PRINTBIT(attr)				\
341	case CONCAT(OP_,attr):			\
342		printf("." #attr " ");		\
343		break
344
345#define	PRINTDBIT(attr)				\
346	case CONCAT(OP_,attr):			\
347		DEBUGF(TARG, ("." #attr " "));	\
348		break
349
350	type &= ~OP_OPMASK;
351
352	while (type) {
353		tbit = 1 << (ffs(type) - 1);
354		type &= ~tbit;
355
356		switch(tbit) {
357		PRINTBIT(OPTIONAL);
358		PRINTBIT(USE);
359		PRINTBIT(EXEC);
360		PRINTBIT(IGNORE);
361		PRINTBIT(PRECIOUS);
362		PRINTBIT(SILENT);
363		PRINTBIT(MAKE);
364		PRINTBIT(JOIN);
365		PRINTBIT(INVISIBLE);
366		PRINTBIT(NOTMAIN);
367		PRINTDBIT(LIB);
368		/*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
369		case OP_MEMBER:
370			DEBUGF(TARG, (".MEMBER "));
371			break;
372		PRINTDBIT(ARCHV);
373		}
374	}
375}
376
377/**
378 * TargPrintNode
379 *	print the contents of a node
380 */
381static int
382TargPrintNode(const GNode *gn, int pass)
383{
384	const LstNode	*tln;
385
386	if (!OP_NOP(gn->type)) {
387		printf("#\n");
388		if (gn == mainTarg) {
389			printf("# *** MAIN TARGET ***\n");
390		}
391		if (pass == 2) {
392			if (gn->unmade) {
393				printf("# %d unmade children\n", gn->unmade);
394			} else {
395				printf("# No unmade children\n");
396			}
397			if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
398				if (gn->mtime != 0) {
399					printf("# last modified %s: %s\n",
400					    Targ_FmtTime(gn->mtime),
401					    gn->made == UNMADE ? "unmade" :
402					    gn->made == MADE ? "made" :
403					    gn->made == UPTODATE ? "up-to-date":
404					    "error when made");
405				} else if (gn->made != UNMADE) {
406					printf("# non-existent (maybe): %s\n",
407					    gn->made == MADE ? "made" :
408					    gn->made == UPTODATE ? "up-to-date":
409					    gn->made == ERROR?"error when made":
410				 	    "aborted");
411				} else {
412					printf("# unmade\n");
413				}
414			}
415			if (!Lst_IsEmpty(&gn->iParents)) {
416				printf("# implicit parents: ");
417				LST_FOREACH(tln, &gn->iParents)
418					printf("%s ", ((const GNode *)
419					    Lst_Datum(tln))->name);
420				printf("\n");
421			}
422		}
423		if (!Lst_IsEmpty(&gn->parents)) {
424			printf("# parents: ");
425			LST_FOREACH(tln, &gn->parents)
426				printf("%s ", ((const GNode *)
427				    Lst_Datum(tln))->name);
428			printf("\n");
429		}
430
431		printf("%-16s", gn->name);
432		switch (gn->type & OP_OPMASK) {
433		  case OP_DEPENDS:
434			printf(": ");
435			break;
436		  case OP_FORCE:
437			printf("! ");
438			break;
439		  case OP_DOUBLEDEP:
440			printf(":: ");
441			break;
442		  default:
443			break;
444		}
445		Targ_PrintType(gn->type);
446		LST_FOREACH(tln, &gn->children)
447			printf("%s ", ((const GNode *)Lst_Datum(tln))->name);
448		printf("\n");
449		LST_FOREACH(tln, &gn->commands)
450			printf("\t%s\n", (const char *)Lst_Datum(tln));
451		printf("\n\n");
452		if (gn->type & OP_DOUBLEDEP) {
453			LST_FOREACH(tln, &gn->cohorts)
454				TargPrintNode((const GNode *)Lst_Datum(tln),
455				    pass);
456		}
457	}
458	return (0);
459}
460
461/**
462 * Targ_PrintGraph
463 *	Print the entire graph.
464 */
465void
466Targ_PrintGraph(int pass)
467{
468	const GNode	*gn;
469	const LstNode	*tln;
470
471	printf("#*** Input graph:\n");
472	LST_FOREACH(tln, &allTargets)
473		TargPrintNode((const GNode *)Lst_Datum(tln), pass);
474	printf("\n\n");
475
476	printf("#\n#   Files that are only sources:\n");
477	LST_FOREACH(tln, &allTargets) {
478		gn = Lst_Datum(tln);
479		if (OP_NOP(gn->type))
480			printf("#\t%s [%s]\n", gn->name,
481			    gn->path ? gn->path : gn->name);
482	}
483
484	printf("#*** Global Variables:\n");
485	Var_Dump(VAR_GLOBAL);
486	printf("#*** Command-line Variables:\n");
487	Var_Dump(VAR_CMD);
488	printf("\n");
489	Dir_PrintDirectories();
490	printf("\n");
491	Suff_PrintAll();
492}
493