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