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.23 2005/01/09 23:03:28 okumoto 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_NewGN Create a new GNode for the passed target
53 * (string). The node is *not* placed in the
54 * hash table, though all its fields are
57 * Targ_FindNode Find the node for a given target, creating
58 * and storing it if it doesn't exist and the
59 * flags are right (TARG_CREATE)
61 * Targ_FindList Given a list of names, find nodes for all
62 * of them. If a name doesn't exist and the
63 * TARG_NOCREATE flag was given, an error message
64 * is printed. Else, if a name doesn't exist,
65 * its node is created.
67 * Targ_Ignore Return TRUE if errors should be ignored when
68 * creating the given target.
70 * Targ_Silent Return TRUE if we should be silent when
71 * creating the given target.
73 * Targ_Precious Return TRUE if the target is precious and
74 * should not be removed if we are interrupted.
77 * Targ_PrintGraph Print out the entire graphm all variables
78 * and statistics for the directory cache. Should
79 * print something for suffixes, too, but...
94 /* the list of all targets found so far */
95 static Lst allTargets = Lst_Initializer(allTargets);
97 static Hash_Table targets; /* a hash table of same */
99 #define HTSIZE 191 /* initial size of hash table */
101 static int TargPrintOnlySrc(void *, void *);
102 static int TargPrintName(void *, void *);
103 static int TargPrintNode(void *, void *);
106 *-----------------------------------------------------------------------
108 * Initialize this module
114 * The allTargets list and the targets hash table are initialized
115 *-----------------------------------------------------------------------
121 Hash_InitTable(&targets, HTSIZE);
125 *-----------------------------------------------------------------------
127 * Create and initialize a new graph node
130 * An initialized graph node with the name field filled with a copy
134 * The gnode is added to the list of all gnodes.
135 *-----------------------------------------------------------------------
138 Targ_NewGN(const char *name)
142 gn = emalloc(sizeof(GNode));
143 gn->name = estrdup(name);
145 if (name[0] == '-' && name[1] == 'l') {
153 gn->childMade = FALSE;
155 gn->mtime = gn->cmtime = 0;
156 Lst_Init(&gn->iParents);
157 Lst_Init(&gn->cohorts);
158 Lst_Init(&gn->parents);
159 Lst_Init(&gn->children);
160 Lst_Init(&gn->successors);
161 Lst_Init(&gn->preds);
162 Lst_Init(&gn->context);
163 Lst_Init(&gn->commands);
170 *-----------------------------------------------------------------------
172 * Find a node in the list using the given name for matching
175 * The node in the list if it was. If it wasn't, return NULL of
176 * flags was TARG_NOCREATE or the newly created and initialized node
177 * if it was TARG_CREATE
180 * Sometimes a node is created and added to the list
181 *-----------------------------------------------------------------------
184 Targ_FindNode(const char *name, int flags)
186 GNode *gn; /* node in that element */
187 Hash_Entry *he; /* New or used hash entry for node */
188 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
189 /* an entry for the node */
191 if (flags & TARG_CREATE) {
192 he = Hash_CreateEntry(&targets, name, &isNew);
194 gn = Targ_NewGN(name);
195 Hash_SetValue(he, gn);
196 Lst_AtEnd(&allTargets, gn);
199 he = Hash_FindEntry(&targets, name);
205 return (Hash_GetValue(he));
210 *-----------------------------------------------------------------------
212 * Make a complete list of GNodes from the given list of names
215 * A complete list of graph nodes corresponding to all instances of all
216 * the names in names.
219 * If flags is TARG_CREATE, nodes will be created for all names in
220 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
221 * an error message will be printed for each name which can't be found.
222 * -----------------------------------------------------------------------
225 Targ_FindList(Lst *nodes, Lst *names, int flags)
227 LstNode *ln; /* name list element */
228 GNode *gn; /* node in tLn */
231 for (ln = Lst_First(names); ln != NULL; ln = Lst_Succ(ln)) {
232 name = Lst_Datum(ln);
233 gn = Targ_FindNode(name, flags);
236 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
237 * are added to the list in the order in which they were
238 * encountered in the makefile.
240 Lst_AtEnd(nodes, gn);
241 if (gn->type & OP_DOUBLEDEP) {
242 Lst_Concat(nodes, &gn->cohorts, LST_CONCNEW);
244 } else if (flags == TARG_NOCREATE) {
245 Error("\"%s\" -- target unknown.", name);
251 *-----------------------------------------------------------------------
253 * Return true if should ignore errors when creating gn
256 * TRUE if should ignore errors
260 *-----------------------------------------------------------------------
263 Targ_Ignore(GNode *gn)
266 if (ignoreErrors || (gn->type & OP_IGNORE)) {
274 *-----------------------------------------------------------------------
276 * Return true if be silent when creating gn
279 * TRUE if should be silent
283 *-----------------------------------------------------------------------
286 Targ_Silent(GNode *gn)
289 if (beSilent || (gn->type & OP_SILENT)) {
297 *-----------------------------------------------------------------------
299 * See if the given target is precious
302 * TRUE if it is precious. FALSE otherwise
306 *-----------------------------------------------------------------------
309 Targ_Precious(GNode *gn)
312 if (allPrecious || (gn->type & (OP_PRECIOUS | OP_DOUBLEDEP))) {
319 /******************* DEBUG INFO PRINTING ****************/
321 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
324 *-----------------------------------------------------------------------
326 * Set our idea of the main target we'll be creating. Used for
333 * "mainTarg" is set to the main target's node.
334 *-----------------------------------------------------------------------
337 Targ_SetMain(GNode *gn)
344 TargPrintName(void *gnp, void *ppath)
346 GNode *gn = (GNode *) gnp;
348 printf("%s ", gn->name);
352 printf("[%s] ", gn->path);
354 if (gn == mainTarg) {
355 printf("(MAIN NAME) ");
359 return (ppath ? 0 : 0);
364 Targ_PrintCmd(void *cmd, void *dummy __unused)
367 printf("\t%s\n", (char *)cmd);
372 *-----------------------------------------------------------------------
374 * Format a modification time in some reasonable way and return it.
377 * The time reformatted.
380 * The time is placed in a static area, so it is overwritten
383 *-----------------------------------------------------------------------
386 Targ_FmtTime(time_t modtime)
389 static char buf[128];
391 parts = localtime(&modtime);
393 strftime(buf, sizeof(buf), "%H:%M:%S %b %d, %Y", parts);
394 buf[sizeof(buf) - 1] = '\0';
399 *-----------------------------------------------------------------------
401 * Print out a type field giving only those attributes the user can
408 *-----------------------------------------------------------------------
411 Targ_PrintType(int type)
415 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
416 #define PRINTDBIT(attr) case CONCAT(OP_,attr): DEBUGF(TARG, ("." #attr " ")); break
421 tbit = 1 << (ffs(type) - 1);
436 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
437 case OP_MEMBER: DEBUGF(TARG, (".MEMBER ")); break;
444 *-----------------------------------------------------------------------
446 * print the contents of a node
447 *-----------------------------------------------------------------------
450 TargPrintNode(void *gnp, void *passp)
453 int pass = *(int *)passp;
455 if (!OP_NOP(gn->type)) {
457 if (gn == mainTarg) {
458 printf("# *** MAIN TARGET ***\n");
462 printf("# %d unmade children\n", gn->unmade);
464 printf("# No unmade children\n");
466 if (!(gn->type & (OP_JOIN | OP_USE | OP_EXEC))) {
467 if (gn->mtime != 0) {
468 printf("# last modified %s: %s\n",
469 Targ_FmtTime(gn->mtime),
470 (gn->made == UNMADE ? "unmade" :
471 (gn->made == MADE ? "made" :
472 (gn->made == UPTODATE ? "up-to-date" :
473 "error when made"))));
474 } else if (gn->made != UNMADE) {
475 printf("# non-existent (maybe): %s\n",
476 (gn->made == MADE ? "made" :
477 (gn->made == UPTODATE ? "up-to-date" :
478 (gn->made == ERROR ? "error when made" :
481 printf("# unmade\n");
484 if (!Lst_IsEmpty(&gn->iParents)) {
485 printf("# implicit parents: ");
486 Lst_ForEach(&gn->iParents, TargPrintName, (void *)NULL);
490 if (!Lst_IsEmpty(&gn->parents)) {
491 printf("# parents: ");
492 Lst_ForEach(&gn->parents, TargPrintName, (void *)NULL);
496 printf("%-16s", gn->name);
497 switch (gn->type & OP_OPMASK) {
503 printf(":: "); break;
507 Targ_PrintType(gn->type);
508 Lst_ForEach(&gn->children, TargPrintName, (void *)NULL);
510 Lst_ForEach(&gn->commands, Targ_PrintCmd, (void *)NULL);
512 if (gn->type & OP_DOUBLEDEP) {
513 Lst_ForEach(&gn->cohorts, TargPrintNode, &pass);
520 *-----------------------------------------------------------------------
521 * TargPrintOnlySrc --
522 * Print only those targets that are just a source.
528 * The name of each file is printed preceded by #\t
530 *-----------------------------------------------------------------------
533 TargPrintOnlySrc(void *gnp, void *dummy __unused)
537 if (OP_NOP(gn->type))
538 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
544 *-----------------------------------------------------------------------
546 * Print the entire graph.
553 *-----------------------------------------------------------------------
556 Targ_PrintGraph(int pass)
559 printf("#*** Input graph:\n");
560 Lst_ForEach(&allTargets, TargPrintNode, &pass);
562 printf("#\n# Files that are only sources:\n");
563 Lst_ForEach(&allTargets, TargPrintOnlySrc, (void *)NULL);
564 printf("#*** Global Variables:\n");
565 Var_Dump(VAR_GLOBAL);
566 printf("#*** Command-line Variables:\n");
569 Dir_PrintDirectories();