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