2 * Copyright (c) 1988, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1989 by Berkeley Softworks
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. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * @(#)targ.c 8.2 (Berkeley) 3/19/94
39 * $FreeBSD: src/usr.bin/make/targ.c,v 1.10 1999/09/11 13:08:02 hoek Exp $
40 * $DragonFly: src/usr.bin/make/targ.c,v 1.10 2004/11/13 22:42:39 dillon Exp $
45 * Functions for maintaining the Lst allTargets. Target nodes are
46 * kept in two structures: a Lst, maintained by the list library, and a
47 * hash table, maintained by the hash library.
50 * Targ_Init Initialization procedure.
52 * Targ_End Cleanup the module
54 * Targ_NewGN Create a new GNode for the passed target
55 * (string). The node is *not* placed in the
56 * hash table, though all its fields are
59 * Targ_FindNode Find the node for a given target, creating
60 * and storing it if it doesn't exist and the
61 * flags are right (TARG_CREATE)
63 * Targ_FindList Given a list of names, find nodes for all
64 * of them. If a name doesn't exist and the
65 * TARG_NOCREATE flag was given, an error message
66 * is printed. Else, if a name doesn't exist,
67 * its node is created.
69 * Targ_Ignore Return TRUE if errors should be ignored when
70 * creating the given target.
72 * Targ_Silent Return TRUE if we should be silent when
73 * creating the given target.
75 * Targ_Precious Return TRUE if the target is precious and
76 * should not be removed if we are interrupted.
79 * Targ_PrintGraph Print out the entire graphm all variables
80 * and statistics for the directory cache. Should
81 * print something for suffixes, too, but...
90 static Lst allTargets; /* the list of all targets found so far */
91 static Lst allGNs; /* List of all the GNodes */
92 static Hash_Table targets; /* a hash table of same */
94 #define HTSIZE 191 /* initial size of hash table */
96 static int TargPrintOnlySrc(void *, void *);
97 static int TargPrintName(void *, void *);
98 static int TargPrintNode(void *, void *);
99 static void TargFreeGN(void *);
102 *-----------------------------------------------------------------------
104 * Initialize this module
110 * The allTargets list and the targets hash table are initialized
111 *-----------------------------------------------------------------------
116 allTargets = Lst_Init (FALSE);
117 Hash_InitTable (&targets, HTSIZE);
121 *-----------------------------------------------------------------------
123 * Finalize this module
129 * All lists and gnodes are cleared
130 *-----------------------------------------------------------------------
135 Lst_Destroy(allTargets, NOFREE);
137 Lst_Destroy(allGNs, TargFreeGN);
138 Hash_DeleteTable(&targets);
142 *-----------------------------------------------------------------------
144 * Create and initialize a new graph node
147 * An initialized graph node with the name field filled with a copy
151 * The gnode is added to the list of all gnodes.
152 *-----------------------------------------------------------------------
155 Targ_NewGN (char *name)
159 gn = (GNode *) emalloc (sizeof (GNode));
160 gn->name = estrdup (name);
161 gn->path = (char *) 0;
162 if (name[0] == '-' && name[1] == 'l') {
170 gn->childMade = FALSE;
172 gn->mtime = gn->cmtime = 0;
173 gn->iParents = Lst_Init (FALSE);
174 gn->cohorts = Lst_Init (FALSE);
175 gn->parents = Lst_Init (FALSE);
176 gn->children = Lst_Init (FALSE);
177 gn->successors = Lst_Init (FALSE);
178 gn->preds = Lst_Init (FALSE);
179 gn->context = Lst_Init (FALSE);
180 gn->commands = Lst_Init (FALSE);
184 allGNs = Lst_Init(FALSE);
185 Lst_AtEnd(allGNs, (void *) gn);
191 *-----------------------------------------------------------------------
200 *-----------------------------------------------------------------------
203 TargFreeGN (void *gnp)
205 GNode *gn = (GNode *) gnp;
211 Lst_Destroy(gn->iParents, NOFREE);
212 Lst_Destroy(gn->cohorts, NOFREE);
213 Lst_Destroy(gn->parents, NOFREE);
214 Lst_Destroy(gn->children, NOFREE);
215 Lst_Destroy(gn->successors, NOFREE);
216 Lst_Destroy(gn->preds, NOFREE);
217 Lst_Destroy(gn->context, NOFREE);
218 Lst_Destroy(gn->commands, NOFREE);
224 *-----------------------------------------------------------------------
226 * Find a node in the list using the given name for matching
229 * The node in the list if it was. If it wasn't, return NULL of
230 * flags was TARG_NOCREATE or the newly created and initialized node
231 * if it was TARG_CREATE
234 * Sometimes a node is created and added to the list
235 *-----------------------------------------------------------------------
238 Targ_FindNode (char *name, int flags)
240 GNode *gn; /* node in that element */
241 Hash_Entry *he; /* New or used hash entry for node */
242 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
243 /* an entry for the node */
246 if (flags & TARG_CREATE) {
247 he = Hash_CreateEntry (&targets, name, &isNew);
249 gn = Targ_NewGN (name);
250 Hash_SetValue (he, gn);
251 (void) Lst_AtEnd (allTargets, (void *)gn);
254 he = Hash_FindEntry (&targets, name);
257 if (he == (Hash_Entry *) NULL) {
260 return ((GNode *) Hash_GetValue (he));
265 *-----------------------------------------------------------------------
267 * Make a complete list of GNodes from the given list of names
270 * A complete list of graph nodes corresponding to all instances of all
271 * the names in names.
274 * If flags is TARG_CREATE, nodes will be created for all names in
275 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
276 * an error message will be printed for each name which can't be found.
277 * -----------------------------------------------------------------------
280 Targ_FindList (Lst names, int flags)
282 Lst nodes; /* result list */
283 LstNode ln; /* name list element */
284 GNode *gn; /* node in tLn */
287 nodes = Lst_Init (FALSE);
289 if (Lst_Open (names) == FAILURE) {
292 while ((ln = Lst_Next (names)) != NULL) {
293 name = (char *)Lst_Datum(ln);
294 gn = Targ_FindNode (name, flags);
297 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
298 * are added to the list in the order in which they were
299 * encountered in the makefile.
301 (void) Lst_AtEnd (nodes, (void *)gn);
302 if (gn->type & OP_DOUBLEDEP) {
303 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
305 } else if (flags == TARG_NOCREATE) {
306 Error ("\"%s\" -- target unknown.", name);
314 *-----------------------------------------------------------------------
316 * Return true if should ignore errors when creating gn
319 * TRUE if should ignore errors
323 *-----------------------------------------------------------------------
326 Targ_Ignore (GNode *gn)
328 if (ignoreErrors || gn->type & OP_IGNORE) {
336 *-----------------------------------------------------------------------
338 * Return true if be silent when creating gn
341 * TRUE if should be silent
345 *-----------------------------------------------------------------------
348 Targ_Silent (GNode *gn)
350 if (beSilent || gn->type & OP_SILENT) {
358 *-----------------------------------------------------------------------
360 * See if the given target is precious
363 * TRUE if it is precious. FALSE otherwise
367 *-----------------------------------------------------------------------
370 Targ_Precious (GNode *gn)
372 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
379 /******************* DEBUG INFO PRINTING ****************/
381 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
383 *-----------------------------------------------------------------------
385 * Set our idea of the main target we'll be creating. Used for
392 * "mainTarg" is set to the main target's node.
393 *-----------------------------------------------------------------------
396 Targ_SetMain (GNode *gn)
402 TargPrintName (void *gnp, void *ppath)
404 GNode *gn = (GNode *) gnp;
405 printf ("%s ", gn->name);
409 printf ("[%s] ", gn->path);
411 if (gn == mainTarg) {
412 printf ("(MAIN NAME) ");
416 return (ppath ? 0 : 0);
421 Targ_PrintCmd (void *cmd, void *dummy __unused)
423 printf ("\t%s\n", (char *) cmd);
428 *-----------------------------------------------------------------------
430 * Format a modification time in some reasonable way and return it.
433 * The time reformatted.
436 * The time is placed in a static area, so it is overwritten
439 *-----------------------------------------------------------------------
442 Targ_FmtTime (time_t time)
445 static char buf[128];
447 parts = localtime(&time);
449 strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
450 buf[sizeof(buf) - 1] = '\0';
455 *-----------------------------------------------------------------------
457 * Print out a type field giving only those attributes the user can
464 *-----------------------------------------------------------------------
467 Targ_PrintType (int type)
471 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
472 #define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
477 tbit = 1 << (ffs(type) - 1);
492 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
493 case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
500 *-----------------------------------------------------------------------
502 * print the contents of a node
503 *-----------------------------------------------------------------------
506 TargPrintNode (void *gnp, void *passp)
508 GNode *gn = (GNode *) gnp;
509 int pass = *(int *) passp;
510 if (!OP_NOP(gn->type)) {
512 if (gn == mainTarg) {
513 printf("# *** MAIN TARGET ***\n");
517 printf("# %d unmade children\n", gn->unmade);
519 printf("# No unmade children\n");
521 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
522 if (gn->mtime != 0) {
523 printf("# last modified %s: %s\n",
524 Targ_FmtTime(gn->mtime),
525 (gn->made == UNMADE ? "unmade" :
526 (gn->made == MADE ? "made" :
527 (gn->made == UPTODATE ? "up-to-date" :
528 "error when made"))));
529 } else if (gn->made != UNMADE) {
530 printf("# non-existent (maybe): %s\n",
531 (gn->made == MADE ? "made" :
532 (gn->made == UPTODATE ? "up-to-date" :
533 (gn->made == ERROR ? "error when made" :
536 printf("# unmade\n");
539 if (!Lst_IsEmpty (gn->iParents)) {
540 printf("# implicit parents: ");
541 Lst_ForEach (gn->iParents, TargPrintName, (void *)0);
542 fputc ('\n', stdout);
545 if (!Lst_IsEmpty (gn->parents)) {
546 printf("# parents: ");
547 Lst_ForEach (gn->parents, TargPrintName, (void *)0);
548 fputc ('\n', stdout);
551 printf("%-16s", gn->name);
552 switch (gn->type & OP_OPMASK) {
558 printf(":: "); break;
560 Targ_PrintType (gn->type);
561 Lst_ForEach (gn->children, TargPrintName, (void *)0);
562 fputc ('\n', stdout);
563 Lst_ForEach (gn->commands, Targ_PrintCmd, (void *)0);
565 if (gn->type & OP_DOUBLEDEP) {
566 Lst_ForEach (gn->cohorts, TargPrintNode, (void *)&pass);
573 *-----------------------------------------------------------------------
574 * TargPrintOnlySrc --
575 * Print only those targets that are just a source.
581 * The name of each file is printed preceded by #\t
583 *-----------------------------------------------------------------------
586 TargPrintOnlySrc(void *gnp, void *dummy __unused)
588 GNode *gn = (GNode *) gnp;
589 if (OP_NOP(gn->type))
590 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
596 *-----------------------------------------------------------------------
598 * Print the entire graph.
605 *-----------------------------------------------------------------------
608 Targ_PrintGraph (int pass)
610 printf("#*** Input graph:\n");
611 Lst_ForEach (allTargets, TargPrintNode, (void *)&pass);
613 printf("#\n# Files that are only sources:\n");
614 Lst_ForEach (allTargets, TargPrintOnlySrc, (void *) 0);
615 printf("#*** Global Variables:\n");
616 Var_Dump (VAR_GLOBAL);
617 printf("#*** Command-line Variables:\n");
620 Dir_PrintDirectories();