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