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