xref: /freebsd/contrib/bmake/targ.c (revision e2eeea75eb8b6dd50c1298067a0655880d186734)
1 /*	$NetBSD: targ.c,v 1.135 2020/11/16 22:28:44 rillig Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1993
5  *	The Regents of the University of California.  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. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1989 by Berkeley Softworks
37  * All rights reserved.
38  *
39  * This code is derived from software contributed to Berkeley by
40  * Adam de Boor.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *	This product includes software developed by the University of
53  *	California, Berkeley and its contributors.
54  * 4. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  */
70 
71 /*
72  * Maintaining the targets and sources, which are both implemented as GNode.
73  *
74  * Interface:
75  *	Targ_Init	Initialize the module.
76  *
77  *	Targ_End	Clean up the module.
78  *
79  *	Targ_List	Return the list of all targets so far.
80  *
81  *	GNode_New	Create a new GNode for the passed target
82  *			(string). The node is *not* placed in the
83  *			hash table, though all its fields are
84  *			initialized.
85  *
86  *	Targ_FindNode	Find the node, or return NULL.
87  *
88  *	Targ_GetNode	Find the node, or create it.
89  *
90  *	Targ_NewInternalNode
91  *			Create an internal node.
92  *
93  *	Targ_FindList	Given a list of names, find nodes for all
94  *			of them, creating them as necessary.
95  *
96  *	Targ_Ignore	Return TRUE if errors should be ignored when
97  *			creating the given target.
98  *
99  *	Targ_Silent	Return TRUE if we should be silent when
100  *			creating the given target.
101  *
102  *	Targ_Precious	Return TRUE if the target is precious and
103  *			should not be removed if we are interrupted.
104  *
105  *	Targ_Propagate	Propagate information between related nodes.
106  *			Should be called after the makefiles are parsed
107  *			but before any action is taken.
108  *
109  * Debugging:
110  *	Targ_PrintGraph
111  *			Print out the entire graphm all variables and
112  *			statistics for the directory cache. Should print
113  *			something for suffixes, too, but...
114  */
115 
116 #include <time.h>
117 
118 #include "make.h"
119 #include "dir.h"
120 
121 /*	"@(#)targ.c	8.2 (Berkeley) 3/19/94"	*/
122 MAKE_RCSID("$NetBSD: targ.c,v 1.135 2020/11/16 22:28:44 rillig Exp $");
123 
124 /* All target nodes found so far, but not the source nodes. */
125 static GNodeList *allTargets;
126 static HashTable allTargetsByName;
127 
128 #ifdef CLEANUP
129 static GNodeList *allNodes;
130 
131 static void GNode_Free(void *);
132 #endif
133 
134 void
135 Targ_Init(void)
136 {
137     allTargets = Lst_New();
138     HashTable_Init(&allTargetsByName);
139 #ifdef CLEANUP
140     allNodes = Lst_New();
141 #endif
142 }
143 
144 void
145 Targ_End(void)
146 {
147     Targ_Stats();
148 #ifdef CLEANUP
149     Lst_Free(allTargets);
150     HashTable_Done(&allTargetsByName);
151     Lst_Destroy(allNodes, GNode_Free);
152 #endif
153 }
154 
155 void
156 Targ_Stats(void)
157 {
158     HashTable_DebugStats(&allTargetsByName, "targets");
159 }
160 
161 /*
162  * Return the list of all targets, which are all nodes that appear on the
163  * left-hand side of a dependency declaration such as "target: source".
164  * The returned list does not contain pure sources.
165  */
166 GNodeList *
167 Targ_List(void)
168 {
169     return allTargets;
170 }
171 
172 /* Create a new graph node, but don't register it anywhere.
173  *
174  * Graph nodes that appear on the left-hand side of a dependency line such
175  * as "target: source" are called targets.  XXX: In some cases (like the
176  * .ALLTARGETS variable), all nodes are called targets as well, even if they
177  * never appear on the left-hand side.  This is a mistake.
178  *
179  * Typical names for graph nodes are:
180  *	"src.c" (an ordinary file)
181  *	"clean" (a .PHONY target)
182  *	".END" (a special hook target)
183  *	"-lm" (a library)
184  *	"libc.a(isspace.o)" (an archive member)
185  */
186 GNode *
187 GNode_New(const char *name)
188 {
189     GNode *gn;
190 
191     gn = bmake_malloc(sizeof *gn);
192     gn->name = bmake_strdup(name);
193     gn->uname = NULL;
194     gn->path = NULL;
195     gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : 0;
196     gn->flags = 0;
197     gn->made = UNMADE;
198     gn->unmade = 0;
199     gn->mtime = 0;
200     gn->youngestChild = NULL;
201     gn->implicitParents = Lst_New();
202     gn->parents = Lst_New();
203     gn->children = Lst_New();
204     gn->order_pred = Lst_New();
205     gn->order_succ = Lst_New();
206     gn->cohorts = Lst_New();
207     gn->cohort_num[0] = '\0';
208     gn->unmade_cohorts = 0;
209     gn->centurion = NULL;
210     gn->checked_seqno = 0;
211     HashTable_Init(&gn->context);
212     gn->commands = Lst_New();
213     gn->suffix = NULL;
214     gn->fname = NULL;
215     gn->lineno = 0;
216 
217 #ifdef CLEANUP
218     Lst_Append(allNodes, gn);
219 #endif
220 
221     return gn;
222 }
223 
224 #ifdef CLEANUP
225 static void
226 GNode_Free(void *gnp)
227 {
228     GNode *gn = gnp;
229 
230     free(gn->name);
231     free(gn->uname);
232     free(gn->path);
233     /* gn->youngestChild is not owned by this node. */
234     Lst_Free(gn->implicitParents); /* ... but not the nodes themselves, */
235     Lst_Free(gn->parents);	/* as they are not owned by this node. */
236     Lst_Free(gn->children);	/* likewise */
237     Lst_Free(gn->order_pred);	/* likewise */
238     Lst_Free(gn->order_succ);	/* likewise */
239     Lst_Free(gn->cohorts);	/* likewise */
240     HashTable_Done(&gn->context); /* ... but not the variables themselves,
241 				 * even though they are owned by this node.
242 				 * XXX: they should probably be freed. */
243     Lst_Free(gn->commands);	/* ... but not the commands themselves,
244 				 * as they may be shared with other nodes. */
245     /* gn->suffix is not owned by this node. */
246     /* XXX: gn->suffix should be unreferenced here.  This requires a thorough
247      * check that the reference counting is done correctly in all places,
248      * otherwise a suffix might be freed too early. */
249 
250     free(gn);
251 }
252 #endif
253 
254 /* Get the existing global node, or return NULL. */
255 GNode *
256 Targ_FindNode(const char *name)
257 {
258     return HashTable_FindValue(&allTargetsByName, name);
259 }
260 
261 /* Get the existing global node, or create it. */
262 GNode *
263 Targ_GetNode(const char *name)
264 {
265     Boolean isNew;
266     HashEntry *he = HashTable_CreateEntry(&allTargetsByName, name, &isNew);
267     if (!isNew)
268 	return HashEntry_Get(he);
269 
270     {
271 	GNode *gn = Targ_NewInternalNode(name);
272 	HashEntry_Set(he, gn);
273 	return gn;
274     }
275 }
276 
277 /*
278  * Create a node, register it in .ALLTARGETS but don't store it in the
279  * table of global nodes.  This means it cannot be found by name.
280  *
281  * This is used for internal nodes, such as cohorts or .WAIT nodes.
282  */
283 GNode *
284 Targ_NewInternalNode(const char *name)
285 {
286     GNode *gn = GNode_New(name);
287     Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
288     Lst_Append(allTargets, gn);
289     if (doing_depend)
290 	gn->flags |= FROM_DEPEND;
291     return gn;
292 }
293 
294 /*
295  * Return the .END node, which contains the commands to be run when
296  * everything else has been made.
297  */
298 GNode *Targ_GetEndNode(void)
299 {
300     /* Save the node locally to avoid having to search for it all the time. */
301     static GNode *endNode = NULL;
302     if (endNode == NULL) {
303 	endNode = Targ_GetNode(".END");
304 	endNode->type = OP_SPECIAL;
305     }
306     return endNode;
307 }
308 
309 /* Return the named nodes, creating them as necessary. */
310 GNodeList *
311 Targ_FindList(StringList *names)
312 {
313     StringListNode *ln;
314     GNodeList *nodes = Lst_New();
315     for (ln = names->first; ln != NULL; ln = ln->next) {
316 	const char *name = ln->datum;
317 	GNode *gn = Targ_GetNode(name);
318 	Lst_Append(nodes, gn);
319     }
320     return nodes;
321 }
322 
323 /* Return true if should ignore errors when creating gn. */
324 Boolean
325 Targ_Ignore(const GNode *gn)
326 {
327     return opts.ignoreErrors || gn->type & OP_IGNORE;
328 }
329 
330 /* Return true if be silent when creating gn. */
331 Boolean
332 Targ_Silent(const GNode *gn)
333 {
334     return opts.beSilent || gn->type & OP_SILENT;
335 }
336 
337 /* See if the given target is precious. */
338 Boolean
339 Targ_Precious(const GNode *gn)
340 {
341     /* XXX: Why are '::' targets precious? */
342     return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
343 }
344 
345 /*
346  * The main target to be made; only for debugging output.
347  * See mainNode in parse.c for the definitive source.
348  */
349 static GNode *mainTarg;
350 
351 /* Remember the main target to make; only used for debugging. */
352 void
353 Targ_SetMain(GNode *gn)
354 {
355     mainTarg = gn;
356 }
357 
358 static void
359 PrintNodeNames(GNodeList *gnodes)
360 {
361     GNodeListNode *node;
362 
363     for (node = gnodes->first; node != NULL; node = node->next) {
364 	GNode *gn = node->datum;
365 	debug_printf(" %s%s", gn->name, gn->cohort_num);
366     }
367 }
368 
369 static void
370 PrintNodeNamesLine(const char *label, GNodeList *gnodes)
371 {
372     if (Lst_IsEmpty(gnodes))
373 	return;
374     debug_printf("# %s:", label);
375     PrintNodeNames(gnodes);
376     debug_printf("\n");
377 }
378 
379 void
380 Targ_PrintCmds(GNode *gn)
381 {
382     StringListNode *ln;
383     for (ln = gn->commands->first; ln != NULL; ln = ln->next) {
384 	const char *cmd = ln->datum;
385 	debug_printf("\t%s\n", cmd);
386     }
387 }
388 
389 /* Format a modification time in some reasonable way and return it.
390  * The time is placed in a static area, so it is overwritten with each call. */
391 char *
392 Targ_FmtTime(time_t tm)
393 {
394     struct tm *parts;
395     static char buf[128];
396 
397     parts = localtime(&tm);
398     (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
399     return buf;
400 }
401 
402 /* Print out a type field giving only those attributes the user can set. */
403 void
404 Targ_PrintType(int type)
405 {
406     int    tbit;
407 
408 #define PRINTBIT(attr)	case CONCAT(OP_,attr): debug_printf(" ." #attr); break
409 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))debug_printf(" ." #attr); break
410 
411     type &= ~OP_OPMASK;
412 
413     while (type) {
414 	tbit = 1 << (ffs(type) - 1);
415 	type &= ~tbit;
416 
417 	switch(tbit) {
418 	PRINTBIT(OPTIONAL);
419 	PRINTBIT(USE);
420 	PRINTBIT(EXEC);
421 	PRINTBIT(IGNORE);
422 	PRINTBIT(PRECIOUS);
423 	PRINTBIT(SILENT);
424 	PRINTBIT(MAKE);
425 	PRINTBIT(JOIN);
426 	PRINTBIT(INVISIBLE);
427 	PRINTBIT(NOTMAIN);
428 	PRINTDBIT(LIB);
429 	    /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
430 	case OP_MEMBER: if (DEBUG(TARG))debug_printf(" .MEMBER"); break;
431 	PRINTDBIT(ARCHV);
432 	PRINTDBIT(MADE);
433 	PRINTDBIT(PHONY);
434 	}
435     }
436 }
437 
438 static const char *
439 made_name(GNodeMade made)
440 {
441     switch (made) {
442     case UNMADE:     return "unmade";
443     case DEFERRED:   return "deferred";
444     case REQUESTED:  return "requested";
445     case BEINGMADE:  return "being made";
446     case MADE:       return "made";
447     case UPTODATE:   return "up-to-date";
448     case ERROR:      return "error when made";
449     case ABORTED:    return "aborted";
450     default:         return "unknown enum_made value";
451     }
452 }
453 
454 static const char *
455 GNode_OpName(const GNode *gn)
456 {
457     switch (gn->type & OP_OPMASK) {
458     case OP_DEPENDS:
459 	return ":";
460     case OP_FORCE:
461 	return "!";
462     case OP_DOUBLEDEP:
463 	return "::";
464     }
465     return "";
466 }
467 
468 /* Print the contents of a node. */
469 void
470 Targ_PrintNode(GNode *gn, int pass)
471 {
472     debug_printf("# %s%s", gn->name, gn->cohort_num);
473     GNode_FprintDetails(opts.debug_file, ", ", gn, "\n");
474     if (gn->flags == 0)
475 	return;
476 
477     if (GNode_IsTarget(gn)) {
478 	debug_printf("#\n");
479 	if (gn == mainTarg) {
480 	    debug_printf("# *** MAIN TARGET ***\n");
481 	}
482 	if (pass >= 2) {
483 	    if (gn->unmade > 0) {
484 		debug_printf("# %d unmade children\n", gn->unmade);
485 	    } else {
486 		debug_printf("# No unmade children\n");
487 	    }
488 	    if (!(gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
489 		if (gn->mtime != 0) {
490 		    debug_printf("# last modified %s: %s\n",
491 			    Targ_FmtTime(gn->mtime),
492 			    made_name(gn->made));
493 		} else if (gn->made != UNMADE) {
494 		    debug_printf("# non-existent (maybe): %s\n",
495 			    made_name(gn->made));
496 		} else {
497 		    debug_printf("# unmade\n");
498 		}
499 	    }
500 	    PrintNodeNamesLine("implicit parents", gn->implicitParents);
501 	} else {
502 	    if (gn->unmade)
503 		debug_printf("# %d unmade children\n", gn->unmade);
504 	}
505 	PrintNodeNamesLine("parents", gn->parents);
506 	PrintNodeNamesLine("order_pred", gn->order_pred);
507 	PrintNodeNamesLine("order_succ", gn->order_succ);
508 
509 	debug_printf("%-16s%s", gn->name, GNode_OpName(gn));
510 	Targ_PrintType(gn->type);
511 	PrintNodeNames(gn->children);
512 	debug_printf("\n");
513 	Targ_PrintCmds(gn);
514 	debug_printf("\n\n");
515 	if (gn->type & OP_DOUBLEDEP) {
516 	    Targ_PrintNodes(gn->cohorts, pass);
517 	}
518     }
519 }
520 
521 void
522 Targ_PrintNodes(GNodeList *gnodes, int pass)
523 {
524     GNodeListNode *ln;
525     for (ln = gnodes->first; ln != NULL; ln = ln->next)
526 	Targ_PrintNode(ln->datum, pass);
527 }
528 
529 /* Print only those targets that are just a source. */
530 static void
531 PrintOnlySources(void)
532 {
533     GNodeListNode *ln;
534 
535     for (ln = allTargets->first; ln != NULL; ln = ln->next) {
536 	GNode *gn = ln->datum;
537 	if (GNode_IsTarget(gn))
538 	    continue;
539 
540 	debug_printf("#\t%s [%s]", gn->name, GNode_Path(gn));
541 	Targ_PrintType(gn->type);
542 	debug_printf("\n");
543     }
544 }
545 
546 /* Input:
547  *	pass		1 => before processing
548  *			2 => after processing
549  *			3 => after processing, an error occurred
550  */
551 void
552 Targ_PrintGraph(int pass)
553 {
554     debug_printf("#*** Input graph:\n");
555     Targ_PrintNodes(allTargets, pass);
556     debug_printf("\n");
557     debug_printf("\n");
558 
559     debug_printf("#\n");
560     debug_printf("#   Files that are only sources:\n");
561     PrintOnlySources();
562 
563     debug_printf("#*** Global Variables:\n");
564     Var_Dump(VAR_GLOBAL);
565 
566     debug_printf("#*** Command-line Variables:\n");
567     Var_Dump(VAR_CMDLINE);
568 
569     debug_printf("\n");
570     Dir_PrintDirectories();
571     debug_printf("\n");
572 
573     Suff_PrintAll();
574 }
575 
576 /* Propagate some type information to cohort nodes (those from the '::'
577  * dependency operator).
578  *
579  * Should be called after the makefiles are parsed but before any action is
580  * taken. */
581 void
582 Targ_Propagate(void)
583 {
584     GNodeListNode *ln, *cln;
585 
586     for (ln = allTargets->first; ln != NULL; ln = ln->next) {
587 	GNode *gn = ln->datum;
588 	GNodeType type = gn->type;
589 
590 	if (!(type & OP_DOUBLEDEP))
591 	    continue;
592 
593 	for (cln = gn->cohorts->first; cln != NULL; cln = cln->next) {
594 	    GNode *cohort = cln->datum;
595 
596 	    cohort->type |= type & ~OP_OPMASK;
597 	}
598     }
599 }
600