1 /* $NetBSD: targ.c,v 1.81 2020/09/01 20:54:00 rillig Exp $ */
4 * Copyright (c) 1988, 1989, 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
36 * Copyright (c) 1989 by Berkeley Softworks
37 * All rights reserved.
39 * This code is derived from software contributed to Berkeley by
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
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.
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
72 static char rcsid[] = "$NetBSD: targ.c,v 1.81 2020/09/01 20:54:00 rillig Exp $";
74 #include <sys/cdefs.h>
77 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
79 __RCSID("$NetBSD: targ.c,v 1.81 2020/09/01 20:54:00 rillig Exp $");
86 * Functions for maintaining the Lst allTargets. Target nodes are
87 * kept in two structures: a Lst and a hash table.
90 * Targ_Init Initialization procedure.
92 * Targ_End Cleanup the module
94 * Targ_List Return the list of all targets so far.
96 * Targ_NewGN Create a new GNode for the passed target
97 * (string). The node is *not* placed in the
98 * hash table, though all its fields are
101 * Targ_FindNode Find the node for a given target, creating
102 * and storing it if it doesn't exist and the
103 * flags are right (TARG_CREATE)
105 * Targ_FindList Given a list of names, find nodes for all
106 * of them. If a name doesn't exist and the
107 * TARG_NOCREATE flag was given, an error message
108 * is printed. Else, if a name doesn't exist,
109 * its node is created.
111 * Targ_Ignore Return TRUE if errors should be ignored when
112 * creating the given target.
114 * Targ_Silent Return TRUE if we should be silent when
115 * creating the given target.
117 * Targ_Precious Return TRUE if the target is precious and
118 * should not be removed if we are interrupted.
120 * Targ_Propagate Propagate information between related
121 * nodes. Should be called after the
122 * makefiles are parsed but before any
126 * Targ_PrintGraph Print out the entire graphm all variables
127 * and statistics for the directory cache. Should
128 * print something for suffixes, too, but...
137 static Lst allTargets; /* the list of all targets found so far */
139 static Lst allGNs; /* List of all the GNodes */
141 static Hash_Table targets; /* a hash table of same */
143 static int TargPrintOnlySrc(void *, void *);
144 static int TargPrintName(void *, void *);
146 static void TargFreeGN(void *);
152 allTargets = Lst_Init();
153 Hash_InitTable(&targets, 191);
161 Lst_Free(allTargets);
163 Lst_Destroy(allGNs, TargFreeGN);
164 Hash_DeleteTable(&targets);
171 Hash_DebugStats(&targets, "targets");
174 /* Return the list of all targets. */
181 /* Create and initialize a new graph node. The gnode is added to the list of
185 * name the name of the node, such as "clean", "src.c"
188 Targ_NewGN(const char *name)
192 gn = bmake_malloc(sizeof(GNode));
193 gn->name = bmake_strdup(name);
196 gn->type = name[0] == '-' && name[1] == 'l' ? OP_LIB : 0;
198 gn->unmade_cohorts = 0;
199 gn->cohort_num[0] = 0;
200 gn->centurion = NULL;
206 gn->implicitParents = Lst_Init();
207 gn->cohorts = Lst_Init();
208 gn->parents = Lst_Init();
209 gn->children = Lst_Init();
210 gn->order_pred = Lst_Init();
211 gn->order_succ = Lst_Init();
212 Hash_InitTable(&gn->context, 0);
213 gn->commands = Lst_Init();
221 Lst_Append(allGNs, gn);
229 TargFreeGN(void *gnp)
231 GNode *gn = (GNode *)gnp;
237 Lst_Free(gn->implicitParents);
238 Lst_Free(gn->cohorts);
239 Lst_Free(gn->parents);
240 Lst_Free(gn->children);
241 Lst_Free(gn->order_succ);
242 Lst_Free(gn->order_pred);
243 Hash_DeleteTable(&gn->context);
244 Lst_Free(gn->commands);
246 /* XXX: does gn->suffix need to be freed? It is reference-counted. */
247 /* gn->fname points to name allocated when file was opened, don't free */
254 /* Find a node in the list using the given name for matching.
255 * If the node is created, it is added to the .ALLTARGETS list.
258 * name the name to find
259 * flags flags governing events when target not found
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 it was TARG_CREATE
267 Targ_FindNode(const char *name, int flags)
269 GNode *gn; /* node in that element */
270 Hash_Entry *he = NULL; /* New or used hash entry for node */
271 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
272 /* an entry for the node */
274 if (!(flags & (TARG_CREATE | TARG_NOHASH))) {
275 he = Hash_FindEntry(&targets, name);
278 return (GNode *)Hash_GetValue(he);
281 if (!(flags & TARG_NOHASH)) {
282 he = Hash_CreateEntry(&targets, name, &isNew);
284 return (GNode *)Hash_GetValue(he);
287 gn = Targ_NewGN(name);
288 if (!(flags & TARG_NOHASH))
289 Hash_SetValue(he, gn);
290 Var_Append(".ALLTARGETS", name, VAR_GLOBAL);
291 Lst_Append(allTargets, gn);
293 gn->flags |= FROM_DEPEND;
297 /* Make a complete list of GNodes from the given list of names.
298 * If flags is TARG_CREATE, nodes will be created for all names in
299 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
300 * an error message will be printed for each name which can't be found.
303 * name list of names to find
304 * flags flags used if no node is found for a given name
307 * A complete list of graph nodes corresponding to all instances of all
308 * the names in names.
311 Targ_FindList(Lst names, int flags)
313 Lst nodes; /* result list */
314 LstNode ln; /* name list element */
315 GNode *gn; /* node in tLn */
321 while ((ln = Lst_Next(names)) != NULL) {
322 name = LstNode_Datum(ln);
323 gn = Targ_FindNode(name, flags);
326 * Note: Lst_Append must come before the Lst_Concat so the nodes
327 * are added to the list in the order in which they were
328 * encountered in the makefile.
330 Lst_Append(nodes, gn);
331 } else if (flags == TARG_NOCREATE) {
332 Error("\"%s\" -- target unknown.", name);
339 /* Return true if should ignore errors when creating gn. */
341 Targ_Ignore(GNode *gn)
343 return ignoreErrors || gn->type & OP_IGNORE;
346 /* Return true if be silent when creating gn. */
348 Targ_Silent(GNode *gn)
350 return beSilent || gn->type & OP_SILENT;
353 /* See if the given target is precious. */
355 Targ_Precious(GNode *gn)
357 return allPrecious || gn->type & (OP_PRECIOUS | OP_DOUBLEDEP);
360 /******************* DEBUG INFO PRINTING ****************/
362 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
364 /* Set our idea of the main target we'll be creating. Used for debugging
367 Targ_SetMain(GNode *gn)
373 TargPrintName(void *gnp, void *pflags MAKE_ATTR_UNUSED)
375 GNode *gn = (GNode *)gnp;
377 fprintf(debug_file, "%s%s ", gn->name, gn->cohort_num);
384 Targ_PrintCmd(void *cmd, void *dummy MAKE_ATTR_UNUSED)
386 fprintf(debug_file, "\t%s\n", (char *)cmd);
390 /* Format a modification time in some reasonable way and return it.
391 * The time is placed in a static area, so it is overwritten with each call. */
393 Targ_FmtTime(time_t tm)
396 static char buf[128];
398 parts = localtime(&tm);
399 (void)strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
403 /* Print out a type field giving only those attributes the user can set. */
405 Targ_PrintType(int type)
409 #define PRINTBIT(attr) case CONCAT(OP_,attr): fprintf(debug_file, "." #attr " "); break
410 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG))fprintf(debug_file, "." #attr " "); break
415 tbit = 1 << (ffs(type) - 1);
430 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
431 case OP_MEMBER: if (DEBUG(TARG))fprintf(debug_file, ".MEMBER "); break;
440 made_name(GNodeMade made)
443 case UNMADE: return "unmade";
444 case DEFERRED: return "deferred";
445 case REQUESTED: return "requested";
446 case BEINGMADE: return "being made";
447 case MADE: return "made";
448 case UPTODATE: return "up-to-date";
449 case ERROR: return "error when made";
450 case ABORTED: return "aborted";
451 default: return "unknown enum_made value";
455 /* Print the contents of a node. */
457 Targ_PrintNode(void *gnp, void *passp)
459 GNode *gn = (GNode *)gnp;
460 int pass = passp ? *(int *)passp : 0;
462 fprintf(debug_file, "# %s%s", gn->name, gn->cohort_num);
463 GNode_FprintDetails(debug_file, ", ", gn, "\n");
467 if (!OP_NOP(gn->type)) {
468 fprintf(debug_file, "#\n");
469 if (gn == mainTarg) {
470 fprintf(debug_file, "# *** MAIN TARGET ***\n");
474 fprintf(debug_file, "# %d unmade children\n", gn->unmade);
476 fprintf(debug_file, "# No unmade children\n");
478 if (! (gn->type & (OP_JOIN|OP_USE|OP_USEBEFORE|OP_EXEC))) {
479 if (gn->mtime != 0) {
480 fprintf(debug_file, "# last modified %s: %s\n",
481 Targ_FmtTime(gn->mtime),
482 made_name(gn->made));
483 } else if (gn->made != UNMADE) {
484 fprintf(debug_file, "# non-existent (maybe): %s\n",
485 made_name(gn->made));
487 fprintf(debug_file, "# unmade\n");
490 if (!Lst_IsEmpty(gn->implicitParents)) {
491 fprintf(debug_file, "# implicit parents: ");
492 Lst_ForEach(gn->implicitParents, TargPrintName, NULL);
493 fprintf(debug_file, "\n");
497 fprintf(debug_file, "# %d unmade children\n", gn->unmade);
499 if (!Lst_IsEmpty(gn->parents)) {
500 fprintf(debug_file, "# parents: ");
501 Lst_ForEach(gn->parents, TargPrintName, NULL);
502 fprintf(debug_file, "\n");
504 if (!Lst_IsEmpty(gn->order_pred)) {
505 fprintf(debug_file, "# order_pred: ");
506 Lst_ForEach(gn->order_pred, TargPrintName, NULL);
507 fprintf(debug_file, "\n");
509 if (!Lst_IsEmpty(gn->order_succ)) {
510 fprintf(debug_file, "# order_succ: ");
511 Lst_ForEach(gn->order_succ, TargPrintName, NULL);
512 fprintf(debug_file, "\n");
515 fprintf(debug_file, "%-16s", gn->name);
516 switch (gn->type & OP_OPMASK) {
518 fprintf(debug_file, ": "); break;
520 fprintf(debug_file, "! "); break;
522 fprintf(debug_file, ":: "); break;
524 Targ_PrintType(gn->type);
525 Lst_ForEach(gn->children, TargPrintName, NULL);
526 fprintf(debug_file, "\n");
527 Lst_ForEach(gn->commands, Targ_PrintCmd, NULL);
528 fprintf(debug_file, "\n\n");
529 if (gn->type & OP_DOUBLEDEP) {
530 Lst_ForEach(gn->cohorts, Targ_PrintNode, &pass);
536 /* Print only those targets that are just a source.
537 * The name of each file is printed, preceded by #\t. */
539 TargPrintOnlySrc(void *gnp, void *dummy MAKE_ATTR_UNUSED)
541 GNode *gn = (GNode *)gnp;
542 if (!OP_NOP(gn->type))
545 fprintf(debug_file, "#\t%s [%s] ",
546 gn->name, gn->path ? gn->path : gn->name);
547 Targ_PrintType(gn->type);
548 fprintf(debug_file, "\n");
554 * pass 1 => before processing
555 * 2 => after processing
556 * 3 => after processing, an error occurred
559 Targ_PrintGraph(int pass)
561 fprintf(debug_file, "#*** Input graph:\n");
562 Lst_ForEach(allTargets, Targ_PrintNode, &pass);
563 fprintf(debug_file, "\n\n");
564 fprintf(debug_file, "#\n# Files that are only sources:\n");
565 Lst_ForEach(allTargets, TargPrintOnlySrc, NULL);
566 fprintf(debug_file, "#*** Global Variables:\n");
567 Var_Dump(VAR_GLOBAL);
568 fprintf(debug_file, "#*** Command-line Variables:\n");
570 fprintf(debug_file, "\n");
571 Dir_PrintDirectories();
572 fprintf(debug_file, "\n");
576 /* Propagate some type information to cohort nodes (those from the ::
577 * dependency operator).
579 * Should be called after the makefiles are parsed but before any action is
586 for (pn = Lst_First(allTargets); pn != NULL; pn = LstNode_Next(pn)) {
587 GNode *pgn = LstNode_Datum(pn);
589 if (!(pgn->type & OP_DOUBLEDEP))
592 for (cn = Lst_First(pgn->cohorts); cn != NULL; cn = LstNode_Next(cn)) {
593 GNode *cgn = LstNode_Datum(cn);
595 cgn->type |= pgn->type & ~OP_OPMASK;