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