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