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