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