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
41 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
43 static const char rcsid[] =
44 "$FreeBSD: src/usr.bin/make/targ.c,v 1.10 1999/09/11 13:08:02 hoek Exp $";
50 * Functions for maintaining the Lst allTargets. Target nodes are
51 * kept in two structures: a Lst, maintained by the list library, and a
52 * hash table, maintained by the hash library.
55 * Targ_Init Initialization procedure.
57 * Targ_End Cleanup the module
59 * Targ_NewGN Create a new GNode for the passed target
60 * (string). The node is *not* placed in the
61 * hash table, though all its fields are
64 * Targ_FindNode Find the node for a given target, creating
65 * and storing it if it doesn't exist and the
66 * flags are right (TARG_CREATE)
68 * Targ_FindList Given a list of names, find nodes for all
69 * of them. If a name doesn't exist and the
70 * TARG_NOCREATE flag was given, an error message
71 * is printed. Else, if a name doesn't exist,
72 * its node is created.
74 * Targ_Ignore Return TRUE if errors should be ignored when
75 * creating the given target.
77 * Targ_Silent Return TRUE if we should be silent when
78 * creating the given target.
80 * Targ_Precious Return TRUE if the target is precious and
81 * should not be removed if we are interrupted.
84 * Targ_PrintGraph Print out the entire graphm all variables
85 * and statistics for the directory cache. Should
86 * print something for suffixes, too, but...
95 static Lst allTargets; /* the list of all targets found so far */
96 static Lst allGNs; /* List of all the GNodes */
97 static Hash_Table targets; /* a hash table of same */
99 #define HTSIZE 191 /* initial size of hash table */
101 static int TargPrintOnlySrc __P((ClientData, ClientData));
102 static int TargPrintName __P((ClientData, ClientData));
103 static int TargPrintNode __P((ClientData, ClientData));
104 static void TargFreeGN __P((ClientData));
107 *-----------------------------------------------------------------------
109 * Initialize this module
115 * The allTargets list and the targets hash table are initialized
116 *-----------------------------------------------------------------------
121 allTargets = Lst_Init (FALSE);
122 Hash_InitTable (&targets, HTSIZE);
126 *-----------------------------------------------------------------------
128 * Finalize this module
134 * All lists and gnodes are cleared
135 *-----------------------------------------------------------------------
140 Lst_Destroy(allTargets, NOFREE);
142 Lst_Destroy(allGNs, TargFreeGN);
143 Hash_DeleteTable(&targets);
147 *-----------------------------------------------------------------------
149 * Create and initialize a new graph node
152 * An initialized graph node with the name field filled with a copy
156 * The gnode is added to the list of all gnodes.
157 *-----------------------------------------------------------------------
161 char *name; /* the name to stick in the new node */
165 gn = (GNode *) emalloc (sizeof (GNode));
166 gn->name = estrdup (name);
167 gn->path = (char *) 0;
168 if (name[0] == '-' && name[1] == 'l') {
176 gn->childMade = FALSE;
178 gn->mtime = gn->cmtime = 0;
179 gn->iParents = Lst_Init (FALSE);
180 gn->cohorts = Lst_Init (FALSE);
181 gn->parents = Lst_Init (FALSE);
182 gn->children = Lst_Init (FALSE);
183 gn->successors = Lst_Init (FALSE);
184 gn->preds = Lst_Init (FALSE);
185 gn->context = Lst_Init (FALSE);
186 gn->commands = Lst_Init (FALSE);
190 allGNs = Lst_Init(FALSE);
191 Lst_AtEnd(allGNs, (ClientData) gn);
197 *-----------------------------------------------------------------------
206 *-----------------------------------------------------------------------
212 GNode *gn = (GNode *) gnp;
218 Lst_Destroy(gn->iParents, NOFREE);
219 Lst_Destroy(gn->cohorts, NOFREE);
220 Lst_Destroy(gn->parents, NOFREE);
221 Lst_Destroy(gn->children, NOFREE);
222 Lst_Destroy(gn->successors, NOFREE);
223 Lst_Destroy(gn->preds, NOFREE);
224 Lst_Destroy(gn->context, NOFREE);
225 Lst_Destroy(gn->commands, NOFREE);
231 *-----------------------------------------------------------------------
233 * Find a node in the list using the given name for matching
236 * The node in the list if it was. If it wasn't, return NILGNODE of
237 * flags was TARG_NOCREATE or the newly created and initialized node
238 * if it was TARG_CREATE
241 * Sometimes a node is created and added to the list
242 *-----------------------------------------------------------------------
245 Targ_FindNode (name, flags)
246 char *name; /* the name to find */
247 int flags; /* flags governing events when target not
250 GNode *gn; /* node in that element */
251 Hash_Entry *he; /* New or used hash entry for node */
252 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
253 /* an entry for the node */
256 if (flags & TARG_CREATE) {
257 he = Hash_CreateEntry (&targets, name, &isNew);
259 gn = Targ_NewGN (name);
260 Hash_SetValue (he, gn);
261 (void) Lst_AtEnd (allTargets, (ClientData)gn);
264 he = Hash_FindEntry (&targets, name);
267 if (he == (Hash_Entry *) NULL) {
270 return ((GNode *) Hash_GetValue (he));
275 *-----------------------------------------------------------------------
277 * Make a complete list of GNodes from the given list of names
280 * A complete list of graph nodes corresponding to all instances of all
281 * the names in names.
284 * If flags is TARG_CREATE, nodes will be created for all names in
285 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
286 * an error message will be printed for each name which can't be found.
287 * -----------------------------------------------------------------------
290 Targ_FindList (names, flags)
291 Lst names; /* list of names to find */
292 int flags; /* flags used if no node is found for a given
295 Lst nodes; /* result list */
296 register LstNode ln; /* name list element */
297 register GNode *gn; /* node in tLn */
300 nodes = Lst_Init (FALSE);
302 if (Lst_Open (names) == FAILURE) {
305 while ((ln = Lst_Next (names)) != NILLNODE) {
306 name = (char *)Lst_Datum(ln);
307 gn = Targ_FindNode (name, flags);
308 if (gn != NILGNODE) {
310 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
311 * are added to the list in the order in which they were
312 * encountered in the makefile.
314 (void) Lst_AtEnd (nodes, (ClientData)gn);
315 if (gn->type & OP_DOUBLEDEP) {
316 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
318 } else if (flags == TARG_NOCREATE) {
319 Error ("\"%s\" -- target unknown.", name);
327 *-----------------------------------------------------------------------
329 * Return true if should ignore errors when creating gn
332 * TRUE if should ignore errors
336 *-----------------------------------------------------------------------
340 GNode *gn; /* node to check for */
342 if (ignoreErrors || gn->type & OP_IGNORE) {
350 *-----------------------------------------------------------------------
352 * Return true if be silent when creating gn
355 * TRUE if should be silent
359 *-----------------------------------------------------------------------
363 GNode *gn; /* node to check for */
365 if (beSilent || gn->type & OP_SILENT) {
373 *-----------------------------------------------------------------------
375 * See if the given target is precious
378 * TRUE if it is precious. FALSE otherwise
382 *-----------------------------------------------------------------------
386 GNode *gn; /* the node to check */
388 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
395 /******************* DEBUG INFO PRINTING ****************/
397 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
399 *-----------------------------------------------------------------------
401 * Set our idea of the main target we'll be creating. Used for
408 * "mainTarg" is set to the main target's node.
409 *-----------------------------------------------------------------------
413 GNode *gn; /* The main target we'll create */
419 TargPrintName (gnp, ppath)
423 GNode *gn = (GNode *) gnp;
424 printf ("%s ", gn->name);
428 printf ("[%s] ", gn->path);
430 if (gn == mainTarg) {
431 printf ("(MAIN NAME) ");
435 return (ppath ? 0 : 0);
440 Targ_PrintCmd (cmd, dummy)
444 printf ("\t%s\n", (char *) cmd);
445 return (dummy ? 0 : 0);
449 *-----------------------------------------------------------------------
451 * Format a modification time in some reasonable way and return it.
454 * The time reformatted.
457 * The time is placed in a static area, so it is overwritten
460 *-----------------------------------------------------------------------
467 static char buf[128];
469 parts = localtime(&time);
471 strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
472 buf[sizeof(buf) - 1] = '\0';
477 *-----------------------------------------------------------------------
479 * Print out a type field giving only those attributes the user can
486 *-----------------------------------------------------------------------
489 Targ_PrintType (type)
495 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
496 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
498 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
499 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
500 #endif /* __STDC__ */
505 tbit = 1 << (ffs(type) - 1);
520 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
521 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
528 *-----------------------------------------------------------------------
530 * print the contents of a node
531 *-----------------------------------------------------------------------
534 TargPrintNode (gnp, passp)
538 GNode *gn = (GNode *) gnp;
539 int pass = *(int *) passp;
540 if (!OP_NOP(gn->type)) {
542 if (gn == mainTarg) {
543 printf("# *** MAIN TARGET ***\n");
547 printf("# %d unmade children\n", gn->unmade);
549 printf("# No unmade children\n");
551 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
552 if (gn->mtime != 0) {
553 printf("# last modified %s: %s\n",
554 Targ_FmtTime(gn->mtime),
555 (gn->made == UNMADE ? "unmade" :
556 (gn->made == MADE ? "made" :
557 (gn->made == UPTODATE ? "up-to-date" :
558 "error when made"))));
559 } else if (gn->made != UNMADE) {
560 printf("# non-existent (maybe): %s\n",
561 (gn->made == MADE ? "made" :
562 (gn->made == UPTODATE ? "up-to-date" :
563 (gn->made == ERROR ? "error when made" :
566 printf("# unmade\n");
569 if (!Lst_IsEmpty (gn->iParents)) {
570 printf("# implicit parents: ");
571 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
572 fputc ('\n', stdout);
575 if (!Lst_IsEmpty (gn->parents)) {
576 printf("# parents: ");
577 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
578 fputc ('\n', stdout);
581 printf("%-16s", gn->name);
582 switch (gn->type & OP_OPMASK) {
588 printf(":: "); break;
590 Targ_PrintType (gn->type);
591 Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
592 fputc ('\n', stdout);
593 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
595 if (gn->type & OP_DOUBLEDEP) {
596 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
603 *-----------------------------------------------------------------------
604 * TargPrintOnlySrc --
605 * Print only those targets that are just a source.
611 * The name of each file is printed preceeded by #\t
613 *-----------------------------------------------------------------------
616 TargPrintOnlySrc(gnp, dummy)
620 GNode *gn = (GNode *) gnp;
621 if (OP_NOP(gn->type))
622 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
624 return (dummy ? 0 : 0);
628 *-----------------------------------------------------------------------
630 * print the entire graph. heh heh
637 *-----------------------------------------------------------------------
640 Targ_PrintGraph (pass)
641 int pass; /* Which pass this is. 1 => no processing
642 * 2 => processing done */
644 printf("#*** Input graph:\n");
645 Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
647 printf("#\n# Files that are only sources:\n");
648 Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
649 printf("#*** Global Variables:\n");
650 Var_Dump (VAR_GLOBAL);
651 printf("#*** Command-line Variables:\n");
654 Dir_PrintDirectories();