targ.c revision 141104
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 141104 2005-02-01 10:50:37Z harti $");
43
44/*-
45 * targ.c --
46 *	Functions for maintaining the Lst allTargets. Target nodes are
47 * kept in two structures: a Lst, maintained by the list library, and a
48 * hash table, maintained by the hash library.
49 *
50 * Interface:
51 *	Targ_Init 	    	Initialization procedure.
52 *
53 *	Targ_NewGN	    	Create a new GNode for the passed target
54 *	    	  	    	(string). The node is *not* placed in the
55 *	    	  	    	hash table, though all its fields are
56 *	    	  	    	initialized.
57 *
58 *	Targ_FindNode	    	Find the node for a given target, creating
59 *	    	  	    	and storing it if it doesn't exist and the
60 *	    	  	    	flags are right (TARG_CREATE)
61 *
62 *	Targ_FindList	    	Given a list of names, find nodes for all
63 *	    	  	    	of them. If a name doesn't exist and the
64 *	    	  	    	TARG_NOCREATE flag was given, an error message
65 *	    	  	    	is printed. Else, if a name doesn't exist,
66 *	    	  	    	its node is created.
67 *
68 *	Targ_Ignore	    	Return TRUE if errors should be ignored when
69 *	    	  	    	creating the given target.
70 *
71 *	Targ_Silent	    	Return TRUE if we should be silent when
72 *	    	  	    	creating the given target.
73 *
74 *	Targ_Precious	    	Return TRUE if the target is precious and
75 *	    	  	    	should not be removed if we are interrupted.
76 *
77 * Debugging:
78 *	Targ_PrintGraph	    	Print out the entire graphm all variables
79 *	    	  	    	and statistics for the directory cache. Should
80 *	    	  	    	print something for suffixes, too, but...
81 */
82
83#include <stdio.h>
84#include <string.h>
85
86#include "dir.h"
87#include "globals.h"
88#include "GNode.h"
89#include "hash.h"
90#include "make.h"
91#include "suff.h"
92#include "targ.h"
93#include "util.h"
94#include "var.h"
95
96/* the list of all targets found so far */
97static Lst allTargets = Lst_Initializer(allTargets);
98
99static Hash_Table targets;	/* a hash table of same */
100
101#define	HTSIZE	191		/* initial size of hash table */
102
103static int TargPrintOnlySrc(void *, void *);
104static int TargPrintName(void *, void *);
105static int TargPrintNode(void *, void *);
106
107/*-
108 *-----------------------------------------------------------------------
109 * Targ_Init --
110 *	Initialize this module
111 *
112 * Results:
113 *	None
114 *
115 * Side Effects:
116 *	The allTargets list and the targets hash table are initialized
117 *-----------------------------------------------------------------------
118 */
119void
120Targ_Init(void)
121{
122
123    Hash_InitTable(&targets, HTSIZE);
124}
125
126/*-
127 *-----------------------------------------------------------------------
128 * Targ_NewGN  --
129 *	Create and initialize a new graph node
130 *
131 * Results:
132 *	An initialized graph node with the name field filled with a copy
133 *	of the passed name
134 *
135 * Side Effects:
136 *	The gnode is added to the list of all gnodes.
137 *-----------------------------------------------------------------------
138 */
139GNode *
140Targ_NewGN(char *name)
141{
142    GNode *gn;
143
144    gn = emalloc(sizeof(GNode));
145    gn->name = estrdup(name);
146    gn->path = NULL;
147    if (name[0] == '-' && name[1] == 'l') {
148	gn->type = OP_LIB;
149    } else {
150	gn->type = 0;
151    }
152    gn->unmade = 0;
153    gn->make = FALSE;
154    gn->made = UNMADE;
155    gn->childMade = FALSE;
156    gn->order = 0;
157    gn->mtime = gn->cmtime = 0;
158    Lst_Init(&gn->iParents);
159    Lst_Init(&gn->cohorts);
160    Lst_Init(&gn->parents);
161    Lst_Init(&gn->children);
162    Lst_Init(&gn->successors);
163    Lst_Init(&gn->preds);
164    Lst_Init(&gn->context);
165    Lst_Init(&gn->commands);
166    gn->suffix = NULL;
167
168    return (gn);
169}
170
171/*-
172 *-----------------------------------------------------------------------
173 * Targ_FindNode  --
174 *	Find a node in the list using the given name for matching
175 *
176 * Results:
177 *	The node in the list if it was. If it wasn't, return NULL of
178 *	flags was TARG_NOCREATE or the newly created and initialized node
179 *	if it was TARG_CREATE
180 *
181 * Side Effects:
182 *	Sometimes a node is created and added to the list
183 *-----------------------------------------------------------------------
184 */
185GNode *
186Targ_FindNode(char *name, int flags)
187{
188    GNode         *gn;	      /* node in that element */
189    Hash_Entry	  *he;	      /* New or used hash entry for node */
190    Boolean	  isNew;      /* Set TRUE if Hash_CreateEntry had to create */
191			      /* an entry for the node */
192
193    if (flags & TARG_CREATE) {
194	he = Hash_CreateEntry(&targets, name, &isNew);
195	if (isNew) {
196	    gn = Targ_NewGN(name);
197	    Hash_SetValue (he, gn);
198	    Lst_AtEnd(&allTargets, gn);
199	}
200    } else {
201	he = Hash_FindEntry(&targets, name);
202    }
203
204    if (he == NULL) {
205	return (NULL);
206    } else {
207	return (Hash_GetValue(he));
208    }
209}
210
211/*-
212 *-----------------------------------------------------------------------
213 * Targ_FindList --
214 *	Make a complete list of GNodes from the given list of names
215 *
216 * Results:
217 *	A complete list of graph nodes corresponding to all instances of all
218 *	the names in names.
219 *
220 * Side Effects:
221 *	If flags is TARG_CREATE, nodes will be created for all names in
222 *	names which do not yet have graph nodes. If flags is TARG_NOCREATE,
223 *	an error message will be printed for each name which can't be found.
224 * -----------------------------------------------------------------------
225 */
226void
227Targ_FindList(Lst *nodes, Lst *names, int flags)
228{
229    LstNode	   *ln;		/* name list element */
230    GNode	   *gn;		/* node in tLn */
231    char    	   *name;
232
233    for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
234	name = Lst_Datum(ln);
235	gn = Targ_FindNode(name, flags);
236	if (gn != NULL) {
237	    /*
238	     * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
239	     * are added to the list in the order in which they were
240	     * encountered in the makefile.
241	     */
242	    Lst_AtEnd(nodes, gn);
243	    if (gn->type & OP_DOUBLEDEP) {
244		Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
245	    }
246	} else if (flags == TARG_NOCREATE) {
247	    Error("\"%s\" -- target unknown.", name);
248	}
249    }
250}
251
252/*-
253 *-----------------------------------------------------------------------
254 * Targ_Ignore  --
255 *	Return true if should ignore errors when creating gn
256 *
257 * Results:
258 *	TRUE if should ignore errors
259 *
260 * Side Effects:
261 *	None
262 *-----------------------------------------------------------------------
263 */
264Boolean
265Targ_Ignore(GNode *gn)
266{
267
268    if (ignoreErrors || (gn->type & OP_IGNORE)) {
269	return (TRUE);
270    } else {
271	return (FALSE);
272    }
273}
274
275/*-
276 *-----------------------------------------------------------------------
277 * Targ_Silent  --
278 *	Return true if be silent when creating gn
279 *
280 * Results:
281 *	TRUE if should be silent
282 *
283 * Side Effects:
284 *	None
285 *-----------------------------------------------------------------------
286 */
287Boolean
288Targ_Silent(GNode *gn)
289{
290
291    if (beSilent || (gn->type & OP_SILENT)) {
292	return (TRUE);
293    } else {
294	return (FALSE);
295    }
296}
297
298/*-
299 *-----------------------------------------------------------------------
300 * Targ_Precious --
301 *	See if the given target is precious
302 *
303 * Results:
304 *	TRUE if it is precious. FALSE otherwise
305 *
306 * Side Effects:
307 *	None
308 *-----------------------------------------------------------------------
309 */
310Boolean
311Targ_Precious(GNode *gn)
312{
313
314    if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
315	return (TRUE);
316    } else {
317	return (FALSE);
318    }
319}
320
321/******************* DEBUG INFO PRINTING ****************/
322
323static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
324
325/*-
326 *-----------------------------------------------------------------------
327 * Targ_SetMain --
328 *	Set our idea of the main target we'll be creating. Used for
329 *	debugging output.
330 *
331 * Results:
332 *	None.
333 *
334 * Side Effects:
335 *	"mainTarg" is set to the main target's node.
336 *-----------------------------------------------------------------------
337 */
338void
339Targ_SetMain(GNode *gn)
340{
341
342    mainTarg = gn;
343}
344
345static int
346TargPrintName(void *gnp, void *ppath)
347{
348    GNode *gn = (GNode *) gnp;
349
350    printf("%s ", gn->name);
351#ifdef notdef
352    if (ppath) {
353	if (gn->path) {
354	    printf("[%s]  ", gn->path);
355	}
356	if (gn == mainTarg) {
357	    printf("(MAIN NAME)  ");
358	}
359    }
360#endif /* notdef */
361    return (ppath ? 0 : 0);
362}
363
364
365int
366Targ_PrintCmd(void *cmd, void *dummy __unused)
367{
368
369    printf("\t%s\n", (char *)cmd);
370    return (0);
371}
372
373/*-
374 *-----------------------------------------------------------------------
375 * Targ_FmtTime --
376 *	Format a modification time in some reasonable way and return it.
377 *
378 * Results:
379 *	The time reformatted.
380 *
381 * Side Effects:
382 *	The time is placed in a static area, so it is overwritten
383 *	with each call.
384 *
385 *-----------------------------------------------------------------------
386 */
387char *
388Targ_FmtTime(time_t modtime)
389{
390    struct tm	  	*parts;
391    static char	  	buf[128];
392
393    parts = localtime(&modtime);
394
395    strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
396    buf[sizeof(buf) - 1] = '\0';
397    return (buf);
398}
399
400/*-
401 *-----------------------------------------------------------------------
402 * Targ_PrintType --
403 *	Print out a type field giving only those attributes the user can
404 *	set.
405 *
406 * Results:
407 *
408 * Side Effects:
409 *
410 *-----------------------------------------------------------------------
411 */
412void
413Targ_PrintType(int type)
414{
415    int    tbit;
416
417#define	PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
418#define	PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
419
420    type &= ~OP_OPMASK;
421
422    while (type) {
423	tbit = 1 << (ffs(type) - 1);
424	type &= ~tbit;
425
426	switch(tbit) {
427	    PRINTBIT(OPTIONAL);
428	    PRINTBIT(USE);
429	    PRINTBIT(EXEC);
430	    PRINTBIT(IGNORE);
431	    PRINTBIT(PRECIOUS);
432	    PRINTBIT(SILENT);
433	    PRINTBIT(MAKE);
434	    PRINTBIT(JOIN);
435	    PRINTBIT(INVISIBLE);
436	    PRINTBIT(NOTMAIN);
437	    PRINTDBIT(LIB);
438	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
439	    case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
440	    PRINTDBIT(ARCHV);
441	}
442    }
443}
444
445/*-
446 *-----------------------------------------------------------------------
447 * TargPrintNode --
448 *	print the contents of a node
449 *-----------------------------------------------------------------------
450 */
451static int
452TargPrintNode(void *gnp, void *passp)
453{
454    GNode         *gn = gnp;
455    int	    	  pass = *(int *)passp;
456
457    if (!OP_NOP(gn->type)) {
458	printf("#\n");
459	if (gn == mainTarg) {
460	    printf("# *** MAIN TARGET ***\n");
461	}
462	if (pass == 2) {
463	    if (gn->unmade) {
464		printf("# %d unmade children\n", gn->unmade);
465	    } else {
466		printf("# No unmade children\n");
467	    }
468	    if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
469		if (gn->mtime != 0) {
470		    printf("# last modified %s: %s\n",
471			      Targ_FmtTime(gn->mtime),
472			      (gn->made == UNMADE ? "unmade" :
473			       (gn->made == MADE ? "made" :
474				(gn->made == UPTODATE ? "up-to-date" :
475				 "error when made"))));
476		} else if (gn->made != UNMADE) {
477		    printf("# non-existent (maybe): %s\n",
478			      (gn->made == MADE ? "made" :
479			       (gn->made == UPTODATE ? "up-to-date" :
480				(gn->made == ERROR ? "error when made" :
481				 "aborted"))));
482		} else {
483		    printf("# unmade\n");
484		}
485	    }
486	    if (!Lst_IsEmpty(&gn->iParents)) {
487		printf("# implicit parents: ");
488		Lst_ForEach(&gn->iParents, TargPrintName, (void *)NULL);
489		fputc('\n', stdout);
490	    }
491	}
492	if (!Lst_IsEmpty(&gn->parents)) {
493	    printf("# parents: ");
494	    Lst_ForEach(&gn->parents, TargPrintName, (void *)NULL);
495	    fputc('\n', stdout);
496	}
497
498	printf("%-16s", gn->name);
499	switch (gn->type & OP_OPMASK) {
500	    case OP_DEPENDS:
501		printf(": "); break;
502	    case OP_FORCE:
503		printf("! "); break;
504	    case OP_DOUBLEDEP:
505		printf(":: "); break;
506	    default:
507		break;
508	}
509	Targ_PrintType(gn->type);
510	Lst_ForEach(&gn->children, TargPrintName, (void *)NULL);
511	fputc('\n', stdout);
512	Lst_ForEach(&gn->commands, Targ_PrintCmd, (void *)NULL);
513	printf("\n\n");
514	if (gn->type & OP_DOUBLEDEP) {
515	    Lst_ForEach(&gn->cohorts, TargPrintNode, &pass);
516	}
517    }
518    return (0);
519}
520
521/*-
522 *-----------------------------------------------------------------------
523 * TargPrintOnlySrc --
524 *	Print only those targets that are just a source.
525 *
526 * Results:
527 *	0.
528 *
529 * Side Effects:
530 *	The name of each file is printed preceded by #\t
531 *
532 *-----------------------------------------------------------------------
533 */
534static int
535TargPrintOnlySrc(void *gnp, void *dummy __unused)
536{
537    GNode   	  *gn = gnp;
538
539    if (OP_NOP(gn->type))
540	printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
541
542    return (0);
543}
544
545/*-
546 *-----------------------------------------------------------------------
547 * Targ_PrintGraph --
548 *	Print the entire graph.
549 *
550 * Results:
551 *	none
552 *
553 * Side Effects:
554 *	lots o' output
555 *-----------------------------------------------------------------------
556 */
557void
558Targ_PrintGraph(int pass)
559{
560
561    printf("#*** Input graph:\n");
562    Lst_ForEach(&allTargets, TargPrintNode, &pass);
563    printf("\n\n");
564    printf("#\n#   Files that are only sources:\n");
565    Lst_ForEach(&allTargets, TargPrintOnlySrc, (void *)NULL);
566    printf("#*** Global Variables:\n");
567    Var_Dump(VAR_GLOBAL);
568    printf("#*** Command-line Variables:\n");
569    Var_Dump(VAR_CMD);
570    printf("\n");
571    Dir_PrintDirectories();
572    printf("\n");
573    Suff_PrintAll();
574}
575