1 /**	$MirOS: src/usr.bin/make/targ.c,v 1.3 2007/06/21 14:17:08 tg Exp $ */
2 /*	$OpenPackages$ */
3 /*	$OpenBSD: targ.c,v 1.40 2006/01/20 23:10:19 espie Exp $ */
4 /*	$NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $	*/
5 
6 /*
7  * Copyright (c) 1999 Marc Espie.
8  *
9  * Extensive code changes for the OpenBSD project.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
24  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1988, 1989, 1990, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  * Copyright (c) 1989 by Berkeley Softworks
36  * All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Adam de Boor.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  */
65 
66 /*-
67  * targ.c --
68  *		Target nodes are kept into a hash table.
69  *
70  * Interface:
71  *	Targ_Init		Initialization procedure.
72  *
73  *	Targ_End		Cleanup the module
74  *
75  *	Targ_NewGN		Create a new GNode for the passed target
76  *				(string). The node is *not* placed in the
77  *				hash table, though all its fields are
78  *				initialized.
79  *
80  *	Targ_FindNode		Find the node for a given target, creating
81  *				and storing it if it doesn't exist and the
82  *				flags are right (TARG_CREATE)
83  *
84  *	Targ_FindList		Given a list of names, find nodes for all
85  *				of them, creating nodes if needed.
86  *
87  *	Targ_Ignore		Return true if errors should be ignored when
88  *				creating the given target.
89  *
90  *	Targ_Silent		Return true if we should be silent when
91  *				creating the given target.
92  *
93  *	Targ_Precious		Return true if the target is precious and
94  *				should not be removed if we are interrupted.
95  *
96  * Debugging:
97  *	Targ_PrintGraph 	Print out the entire graphm all variables
98  *				and statistics for the directory cache. Should
99  *				print something for suffixes, too, but...
100  */
101 
102 #include <limits.h>
103 #include <stddef.h>
104 #include <stdio.h>
105 #include <stdint.h>
106 #include <string.h>
107 #include "config.h"
108 #include "defines.h"
109 #include "ohash.h"
110 #include "stats.h"
111 #include "suff.h"
112 #include "var.h"
113 #include "targ.h"
114 #include "memory.h"
115 #include "gnode.h"
116 #include "extern.h"
117 #include "timestamp.h"
118 #include "lst.h"
119 #ifdef CLEANUP
120 #include <stdlib.h>
121 #endif
122 
123 __RCSID("$MirOS: src/usr.bin/make/targ.c,v 1.3 2007/06/21 14:17:08 tg Exp $");
124 
125 static struct ohash targets;	/* a hash table of same */
126 static struct ohash_info gnode_info = {
127 	offsetof(GNode, name),
128     NULL, hash_alloc, hash_free, element_alloc };
129 
130 static void TargPrintOnlySrc(GNode *);
131 static void TargPrintName(void *);
132 static void TargPrintNode(GNode *, int);
133 #ifdef CLEANUP
134 static LIST allTargets;
135 static void TargFreeGN(void *);
136 #endif
137 
138 /*-
139  *-----------------------------------------------------------------------
140  * Targ_Init --
141  *	Initialize this module
142  *
143  * Side Effects:
144  *	The targets hash table is initialized
145  *-----------------------------------------------------------------------
146  */
147 void
Targ_Init(void)148 Targ_Init(void)
149 {
150     /* A small make file already creates 200 targets.  */
151     ohash_init(&targets, 10, &gnode_info);
152 #ifdef CLEANUP
153     Lst_Init(&allTargets);
154 #endif
155 }
156 
157 /*-
158  *-----------------------------------------------------------------------
159  * Targ_End --
160  *	Finalize this module
161  *
162  * Side Effects:
163  *	All lists and gnodes are cleared
164  *-----------------------------------------------------------------------
165  */
166 #ifdef CLEANUP
167 void
Targ_End(void)168 Targ_End(void)
169 {
170     Lst_Every(&allTargets, TargFreeGN);
171     ohash_delete(&targets);
172 }
173 #endif
174 
175 /*-
176  *-----------------------------------------------------------------------
177  * Targ_NewGNi  --
178  *	Create and initialize a new graph node
179  *
180  * Results:
181  *	An initialized graph node with the name field filled with a copy
182  *	of the passed name
183  *
184  * Side effect:
185  *	add targets to list of all targets if CLEANUP
186  *-----------------------------------------------------------------------
187  */
188 GNode *
Targ_NewGNi(const char * name,const char * ename)189 Targ_NewGNi(const char *name, /* the name to stick in the new node */
190     const char *ename)
191 {
192     GNode *gn;
193 
194     gn = ohash_create_entry(&gnode_info, name, &ename);
195     gn->path = NULL;
196     if (name[0] == '-' && name[1] == 'l') {
197 	gn->type = OP_LIB;
198     } else {
199 	gn->type = 0;
200     }
201     gn->unmade =	0;
202     gn->make =		false;
203     gn->made =		UNMADE;
204     gn->childMade =	false;
205     gn->order = 	0;
206     ts_set_out_of_date(gn->mtime);
207     ts_set_out_of_date(gn->cmtime);
208     Lst_Init(&gn->iParents);
209     Lst_Init(&gn->cohorts);
210     Lst_Init(&gn->parents);
211     Lst_Init(&gn->children);
212     Lst_Init(&gn->successors);
213     Lst_Init(&gn->preds);
214     SymTable_Init(&gn->context);
215     gn->lineno = 0;
216     gn->fname = NULL;
217     Lst_Init(&gn->commands);
218     gn->suffix =	NULL;
219 
220 #ifdef STATS_GN_CREATION
221     STAT_GN_COUNT++;
222 #endif
223 
224 #ifdef CLEANUP
225     Lst_AtEnd(&allTargets, gn);
226 #endif
227     return gn;
228 }
229 
230 #ifdef CLEANUP
231 /*-
232  *-----------------------------------------------------------------------
233  * TargFreeGN  --
234  *	Destroy a GNode
235  *-----------------------------------------------------------------------
236  */
237 static void
TargFreeGN(void * gnp)238 TargFreeGN(void *gnp)
239 {
240     GNode *gn = (GNode *)gnp;
241 
242     efree(gn->path);
243     Lst_Destroy(&gn->iParents, NOFREE);
244     Lst_Destroy(&gn->cohorts, NOFREE);
245     Lst_Destroy(&gn->parents, NOFREE);
246     Lst_Destroy(&gn->children, NOFREE);
247     Lst_Destroy(&gn->successors, NOFREE);
248     Lst_Destroy(&gn->preds, NOFREE);
249     Lst_Destroy(&gn->commands, NOFREE);
250     SymTable_Destroy(&gn->context);
251     free(gn);
252 }
253 #endif
254 
255 
256 /*-
257  *-----------------------------------------------------------------------
258  * Targ_FindNodei  --
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 NULL if
263  *	flags was TARG_NOCREATE or the newly created and initialized node
264  *	if flags was TARG_CREATE
265  *
266  * Side Effects:
267  *	Sometimes a node is created and added to the list
268  *-----------------------------------------------------------------------
269  */
270 GNode *
Targ_FindNodei(const char * name,const char * ename,int flags)271 Targ_FindNodei(const char *name, const char *ename,
272     int flags)			/* flags governing events when target not
273 				 * found */
274 {
275     GNode		*gn;	/* node in that element */
276     unsigned int	slot;
277 
278     slot = ohash_qlookupi(&targets, name, &ename);
279 
280     gn = ohash_find(&targets, slot);
281 
282     if (gn == NULL && (flags & TARG_CREATE)) {
283 	gn = Targ_NewGNi(name, ename);
284 	ohash_insert(&targets, slot, gn);
285     }
286 
287     return gn;
288 }
289 
290 /*-
291  *-----------------------------------------------------------------------
292  * Targ_FindList --
293  *	Make a complete list of GNodes from the given list of names
294  *
295  * Side Effects:
296  *	Nodes will be created for all names in names which do not yet have graph
297  *	nodes.
298  *
299  *	A complete list of graph nodes corresponding to all instances of all
300  *	the names in names is added to nodes.
301  * -----------------------------------------------------------------------
302  */
303 void
Targ_FindList(Lst nodes,Lst names)304 Targ_FindList(Lst nodes, 	/* result list */
305     Lst names) 			/* list of names to find */
306 {
307     LstNode	   ln;		/* name list element */
308     GNode	  *gn;		/* node in tLn */
309     char	  *name;
310 
311     for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
312 	name = (char *)Lst_Datum(ln);
313 	gn = Targ_FindNode(name, TARG_CREATE);
314 	    /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
315 	     * are added to the list in the order in which they were
316 	     * encountered in the makefile.  */
317 	Lst_AtEnd(nodes, gn);
318 	if (gn->type & OP_DOUBLEDEP)
319 	    Lst_Concat(nodes, &gn->cohorts);
320     }
321 }
322 
323 /*-
324  *-----------------------------------------------------------------------
325  * Targ_Ignore	--
326  *	Return true if should ignore errors when creating gn
327  *-----------------------------------------------------------------------
328  */
329 bool
Targ_Ignore(GNode * gn)330 Targ_Ignore(GNode *gn)
331 {
332     if (ignoreErrors || gn->type & OP_IGNORE)
333 	return true;
334     else
335 	return false;
336 }
337 
338 /*-
339  *-----------------------------------------------------------------------
340  * Targ_Silent	--
341  *	Return true if be silent when creating gn
342  *-----------------------------------------------------------------------
343  */
344 bool
Targ_Silent(GNode * gn)345 Targ_Silent(GNode *gn)
346 {
347     if (beSilent || gn->type & OP_SILENT)
348 	return true;
349     else
350 	return false;
351 }
352 
353 /*-
354  *-----------------------------------------------------------------------
355  * Targ_Precious --
356  *	See if the given target is precious
357  *-----------------------------------------------------------------------
358  */
359 bool
Targ_Precious(GNode * gn)360 Targ_Precious(GNode *gn)
361 {
362     if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
363 	return true;
364     else
365 	return false;
366 }
367 
368 /******************* DEBUG INFO PRINTING ****************/
369 
370 static GNode	  *mainTarg;	/* the main target, as set by Targ_SetMain */
371 /*-
372  *-----------------------------------------------------------------------
373  * Targ_SetMain --
374  *	Set our idea of the main target we'll be creating. Used for
375  *	debugging output.
376  *
377  * Side Effects:
378  *	"mainTarg" is set to the main target's node.
379  *-----------------------------------------------------------------------
380  */
381 void
Targ_SetMain(GNode * gn)382 Targ_SetMain(GNode *gn)
383 {
384     mainTarg = gn;
385 }
386 
387 static void
TargPrintName(void * gnp)388 TargPrintName(void *gnp)
389 {
390     GNode *gn = (GNode *)gnp;
391     printf("%s ", gn->name);
392 }
393 
394 
395 void
Targ_PrintCmd(void * cmd)396 Targ_PrintCmd(void *cmd)
397 {
398     printf("\t%s\n", (char *)cmd);
399 }
400 
401 /*-
402  *-----------------------------------------------------------------------
403  * Targ_FmtTime --
404  *	Format a modification time in some reasonable way and return it.
405  *
406  * Results:
407  *	The time reformatted.
408  *
409  * Side Effects:
410  *	The time is placed in a static area, so it is overwritten
411  *	with each call.
412  *-----------------------------------------------------------------------
413  */
414 char *
Targ_FmtTime(TIMESTAMP tm)415 Targ_FmtTime(TIMESTAMP tm)
416 {
417     struct tm		*parts;
418     static char 	buf[128];
419     time_t t;
420 
421     t = timestamp2time_t(tm);
422 
423     parts = localtime(&t);
424     strftime(buf, sizeof buf, "%H:%M:%S %b %d, %Y", parts);
425     buf[sizeof(buf) - 1] = '\0';
426     return buf;
427 }
428 
429 /*-
430  *-----------------------------------------------------------------------
431  * Targ_PrintType --
432  *	Print out a type field giving only those attributes the user can
433  *	set.
434  *-----------------------------------------------------------------------
435  */
436 void
Targ_PrintType(int type)437 Targ_PrintType(int type)
438 {
439     int    tbit;
440 
441 #define PRINTBIT(attr)	case CONCAT(OP_,attr): printf("." #attr " "); break
442 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
443 
444     type &= ~OP_OPMASK;
445 
446     while (type) {
447 	tbit = 1 << (ffs(type) - 1);
448 	type &= ~tbit;
449 
450 	switch (tbit) {
451 	    PRINTBIT(OPTIONAL);
452 	    PRINTBIT(USE);
453 	    PRINTBIT(EXEC);
454 	    PRINTBIT(IGNORE);
455 	    PRINTBIT(PRECIOUS);
456 	    PRINTBIT(SILENT);
457 	    PRINTBIT(MAKE);
458 	    PRINTBIT(JOIN);
459 	    PRINTBIT(INVISIBLE);
460 	    PRINTBIT(NOTMAIN);
461 	    PRINTDBIT(LIB);
462 	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
463 	    case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
464 	    PRINTDBIT(ARCHV);
465 	}
466     }
467 }
468 
469 /*-
470  *-----------------------------------------------------------------------
471  * TargPrintNode --
472  *	print the contents of a node
473  *-----------------------------------------------------------------------
474  */
475 static void
TargPrintNode(GNode * gn,int pass)476 TargPrintNode(GNode *gn, int pass)
477 {
478     if (!OP_NOP(gn->type)) {
479 	printf("#\n");
480 	if (gn == mainTarg) {
481 	    printf("# *** MAIN TARGET ***\n");
482 	}
483 	if (pass == 2) {
484 	    if (gn->unmade) {
485 		printf("# %d unmade children\n", gn->unmade);
486 	    } else {
487 		printf("# No unmade children\n");
488 	    }
489 	    if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
490 		if (!is_out_of_date(gn->mtime)) {
491 		    printf("# last modified %s: %s\n",
492 			      Targ_FmtTime(gn->mtime),
493 			      (gn->made == UNMADE ? "unmade" :
494 			       (gn->made == MADE ? "made" :
495 				(gn->made == UPTODATE ? "up-to-date" :
496 				 "error when made"))));
497 		} else if (gn->made != UNMADE) {
498 		    printf("# non-existent (maybe): %s\n",
499 			      (gn->made == MADE ? "made" :
500 			       (gn->made == UPTODATE ? "up-to-date" :
501 				(gn->made == ERROR ? "error when made" :
502 				 "aborted"))));
503 		} else {
504 		    printf("# unmade\n");
505 		}
506 	    }
507 	    if (!Lst_IsEmpty(&gn->iParents)) {
508 		printf("# implicit parents: ");
509 		Lst_Every(&gn->iParents, TargPrintName);
510 		fputc('\n', stdout);
511 	    }
512 	}
513 	if (!Lst_IsEmpty(&gn->parents)) {
514 	    printf("# parents: ");
515 	    Lst_Every(&gn->parents, TargPrintName);
516 	    fputc('\n', stdout);
517 	}
518 
519 	printf("%-16s", gn->name);
520 	switch (gn->type & OP_OPMASK) {
521 	    case OP_DEPENDS:
522 		printf(": "); break;
523 	    case OP_FORCE:
524 		printf("! "); break;
525 	    case OP_DOUBLEDEP:
526 		printf(":: "); break;
527 	}
528 	Targ_PrintType(gn->type);
529 	Lst_Every(&gn->children, TargPrintName);
530 	fputc('\n', stdout);
531 	Lst_Every(&gn->commands, Targ_PrintCmd);
532 	printf("\n\n");
533 	if (gn->type & OP_DOUBLEDEP) {
534 	    LstNode ln;
535 
536 	    for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
537 		    TargPrintNode((GNode *)Lst_Datum(ln), pass);
538 	}
539     }
540 }
541 
542 /*-
543  *-----------------------------------------------------------------------
544  * TargPrintOnlySrc --
545  *	Print targets that are just a source.
546  *-----------------------------------------------------------------------
547  */
548 static void
TargPrintOnlySrc(GNode * gn)549 TargPrintOnlySrc(GNode *gn)
550 {
551     if (OP_NOP(gn->type))
552 	printf("#\t%s [%s]\n", gn->name,
553 	    gn->path != NULL ? gn->path : gn->name);
554 }
555 
556 /*-
557  *-----------------------------------------------------------------------
558  * Targ_PrintGraph --
559  *	print the entire graph.
560  *-----------------------------------------------------------------------
561  */
562 void
Targ_PrintGraph(int pass)563 Targ_PrintGraph(int pass)	/* Which pass this is. 1 => no processing
564 				 * 2 => processing done */
565 {
566     GNode		*gn;
567     unsigned int	i;
568 
569     printf("#*** Input graph:\n");
570     for (gn = ohash_first(&targets, &i); gn != NULL;
571 	gn = ohash_next(&targets, &i))
572 	    TargPrintNode(gn, pass);
573     printf("\n\n");
574     printf("#\n#   Files that are only sources:\n");
575     for (gn = ohash_first(&targets, &i); gn != NULL;
576 	gn = ohash_next(&targets, &i))
577 		TargPrintOnlySrc(gn);
578     Var_Dump();
579     printf("\n");
580 #ifdef DEBUG_DIRECTORY_CACHE
581     Dir_PrintDirectories();
582     printf("\n");
583 #endif
584     Suff_PrintAll();
585 }
586