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