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