Annotation of src/usr.bin/make/targ.c, Revision 1.4
1.1 cgd 1: /*
2: * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
3: * Copyright (c) 1988, 1989 by Adam de Boor
4: * Copyright (c) 1989 by Berkeley Softworks
5: * 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. 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.
25: *
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
36: * SUCH DAMAGE.
37: */
38:
39: #ifndef lint
1.3 cgd 40: /* from: static char sccsid[] = "@(#)targ.c 5.9 (Berkeley) 3/1/91"; */
1.4 ! jtc 41: static char *rcsid = "$Id: targ.c,v 1.3 1994/03/05 00:35:13 cgd Exp $";
1.1 cgd 42: #endif /* not lint */
43:
44: /*-
45: * targ.c --
46: * Functions for maintaining the Lst allTargets. Target nodes are
47: * kept in two structures: a Lst, maintained by the list library, and a
48: * hash table, maintained by the hash library.
49: *
50: * Interface:
51: * Targ_Init Initialization procedure.
52: *
1.4 ! jtc 53: * Targ_End Cleanup the module
! 54: *
1.1 cgd 55: * Targ_NewGN Create a new GNode for the passed target
56: * (string). The node is *not* placed in the
57: * hash table, though all its fields are
58: * initialized.
59: *
60: * Targ_FindNode Find the node for a given target, creating
61: * and storing it if it doesn't exist and the
62: * flags are right (TARG_CREATE)
63: *
64: * Targ_FindList Given a list of names, find nodes for all
65: * of them. If a name doesn't exist and the
66: * TARG_NOCREATE flag was given, an error message
67: * is printed. Else, if a name doesn't exist,
68: * its node is created.
69: *
70: * Targ_Ignore Return TRUE if errors should be ignored when
71: * creating the given target.
72: *
73: * Targ_Silent Return TRUE if we should be silent when
74: * creating the given target.
75: *
76: * Targ_Precious Return TRUE if the target is precious and
77: * should not be removed if we are interrupted.
78: *
79: * Debugging:
80: * Targ_PrintGraph Print out the entire graphm all variables
81: * and statistics for the directory cache. Should
82: * print something for suffixes, too, but...
83: */
84:
85: #include <stdio.h>
86: #include <time.h>
87: #include "make.h"
88: #include "hash.h"
1.3 cgd 89: #include "dir.h"
1.1 cgd 90:
91: static Lst allTargets; /* the list of all targets found so far */
1.4 ! jtc 92: static Lst allGNs; /* List of all the GNodes */
1.1 cgd 93: static Hash_Table targets; /* a hash table of same */
94:
95: #define HTSIZE 191 /* initial size of hash table */
96:
1.4 ! jtc 97: static int TargPrintOnlySrc __P((ClientData, ClientData));
! 98: static int TargPrintName __P((ClientData, ClientData));
! 99: static int TargPrintNode __P((ClientData, ClientData));
! 100: static void TargFreeGN __P((ClientData));
! 101:
1.1 cgd 102: /*-
103: *-----------------------------------------------------------------------
104: * Targ_Init --
105: * Initialize this module
106: *
107: * Results:
108: * None
109: *
110: * Side Effects:
111: * The allTargets list and the targets hash table are initialized
112: *-----------------------------------------------------------------------
113: */
114: void
115: Targ_Init ()
116: {
117: allTargets = Lst_Init (FALSE);
118: Hash_InitTable (&targets, HTSIZE);
119: }
120:
121: /*-
122: *-----------------------------------------------------------------------
1.4 ! jtc 123: * Targ_End --
! 124: * Finalize this module
! 125: *
! 126: * Results:
! 127: * None
! 128: *
! 129: * Side Effects:
! 130: * All lists and gnodes are cleared
! 131: *-----------------------------------------------------------------------
! 132: */
! 133: void
! 134: Targ_End ()
! 135: {
! 136: Lst_Destroy(allTargets, NOFREE);
! 137: if (allGNs)
! 138: Lst_Destroy(allGNs, TargFreeGN);
! 139: Hash_DeleteTable(&targets);
! 140: }
! 141:
! 142: /*-
! 143: *-----------------------------------------------------------------------
1.1 cgd 144: * Targ_NewGN --
145: * Create and initialize a new graph node
146: *
147: * Results:
148: * An initialized graph node with the name field filled with a copy
149: * of the passed name
150: *
151: * Side Effects:
1.4 ! jtc 152: * The gnode is added to the list of all gnodes.
1.1 cgd 153: *-----------------------------------------------------------------------
154: */
155: GNode *
156: Targ_NewGN (name)
157: char *name; /* the name to stick in the new node */
158: {
159: register GNode *gn;
160:
161: gn = (GNode *) emalloc (sizeof (GNode));
162: gn->name = strdup (name);
163: gn->path = (char *) 0;
164: if (name[0] == '-' && name[1] == 'l') {
165: gn->type = OP_LIB;
166: } else {
167: gn->type = 0;
168: }
169: gn->unmade = 0;
170: gn->make = FALSE;
171: gn->made = UNMADE;
172: gn->childMade = FALSE;
173: gn->mtime = gn->cmtime = 0;
174: gn->iParents = Lst_Init (FALSE);
175: gn->cohorts = Lst_Init (FALSE);
176: gn->parents = Lst_Init (FALSE);
177: gn->children = Lst_Init (FALSE);
1.4 ! jtc 178: gn->successors = Lst_Init (FALSE);
! 179: gn->preds = Lst_Init (FALSE);
1.1 cgd 180: gn->context = Lst_Init (FALSE);
181: gn->commands = Lst_Init (FALSE);
1.3 cgd 182: gn->suffix = NULL;
1.1 cgd 183:
1.4 ! jtc 184: if (allGNs == NULL)
! 185: allGNs = Lst_Init(FALSE);
! 186: Lst_AtEnd(allGNs, (ClientData) gn);
! 187:
1.1 cgd 188: return (gn);
189: }
190:
191: /*-
192: *-----------------------------------------------------------------------
1.4 ! jtc 193: * TargFreeGN --
! 194: * Destroy a GNode
! 195: *
! 196: * Results:
! 197: * None.
! 198: *
! 199: * Side Effects:
! 200: * None.
! 201: *-----------------------------------------------------------------------
! 202: */
! 203: static void
! 204: TargFreeGN (gnp)
! 205: ClientData gnp;
! 206: {
! 207: GNode *gn = (GNode *) gnp;
! 208:
! 209:
! 210: free(gn->name);
! 211: if (gn->path)
! 212: free(gn->path);
! 213:
! 214: Lst_Destroy(gn->iParents, NOFREE);
! 215: Lst_Destroy(gn->cohorts, NOFREE);
! 216: Lst_Destroy(gn->parents, NOFREE);
! 217: Lst_Destroy(gn->children, NOFREE);
! 218: Lst_Destroy(gn->successors, NOFREE);
! 219: Lst_Destroy(gn->preds, NOFREE);
! 220: Lst_Destroy(gn->context, NOFREE);
! 221: Lst_Destroy(gn->commands, NOFREE);
! 222: free((Address)gn);
! 223: }
! 224:
! 225:
! 226: /*-
! 227: *-----------------------------------------------------------------------
1.1 cgd 228: * Targ_FindNode --
229: * Find a node in the list using the given name for matching
230: *
231: * Results:
232: * The node in the list if it was. If it wasn't, return NILGNODE of
233: * flags was TARG_NOCREATE or the newly created and initialized node
234: * if it was TARG_CREATE
235: *
236: * Side Effects:
237: * Sometimes a node is created and added to the list
238: *-----------------------------------------------------------------------
239: */
240: GNode *
241: Targ_FindNode (name, flags)
242: char *name; /* the name to find */
243: int flags; /* flags governing events when target not
244: * found */
245: {
246: GNode *gn; /* node in that element */
247: Hash_Entry *he; /* New or used hash entry for node */
248: Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
249: /* an entry for the node */
250:
251:
252: if (flags & TARG_CREATE) {
253: he = Hash_CreateEntry (&targets, name, &isNew);
254: if (isNew) {
255: gn = Targ_NewGN (name);
256: Hash_SetValue (he, gn);
257: (void) Lst_AtEnd (allTargets, (ClientData)gn);
258: }
259: } else {
260: he = Hash_FindEntry (&targets, name);
261: }
262:
263: if (he == (Hash_Entry *) NULL) {
264: return (NILGNODE);
265: } else {
266: return ((GNode *) Hash_GetValue (he));
267: }
268: }
269:
270: /*-
271: *-----------------------------------------------------------------------
272: * Targ_FindList --
273: * Make a complete list of GNodes from the given list of names
274: *
275: * Results:
276: * A complete list of graph nodes corresponding to all instances of all
277: * the names in names.
278: *
279: * Side Effects:
280: * If flags is TARG_CREATE, nodes will be created for all names in
281: * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
282: * an error message will be printed for each name which can't be found.
283: * -----------------------------------------------------------------------
284: */
285: Lst
286: Targ_FindList (names, flags)
287: Lst names; /* list of names to find */
288: int flags; /* flags used if no node is found for a given
289: * name */
290: {
291: Lst nodes; /* result list */
292: register LstNode ln; /* name list element */
293: register GNode *gn; /* node in tLn */
294: char *name;
295:
296: nodes = Lst_Init (FALSE);
297:
298: if (Lst_Open (names) == FAILURE) {
299: return (nodes);
300: }
301: while ((ln = Lst_Next (names)) != NILLNODE) {
302: name = (char *)Lst_Datum(ln);
303: gn = Targ_FindNode (name, flags);
304: if (gn != NILGNODE) {
305: /*
306: * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
307: * are added to the list in the order in which they were
308: * encountered in the makefile.
309: */
310: (void) Lst_AtEnd (nodes, (ClientData)gn);
311: if (gn->type & OP_DOUBLEDEP) {
312: (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
313: }
314: } else if (flags == TARG_NOCREATE) {
315: Error ("\"%s\" -- target unknown.", name);
316: }
317: }
318: Lst_Close (names);
319: return (nodes);
320: }
321:
322: /*-
323: *-----------------------------------------------------------------------
324: * Targ_Ignore --
325: * Return true if should ignore errors when creating gn
326: *
327: * Results:
328: * TRUE if should ignore errors
329: *
330: * Side Effects:
331: * None
332: *-----------------------------------------------------------------------
333: */
334: Boolean
335: Targ_Ignore (gn)
336: GNode *gn; /* node to check for */
337: {
338: if (ignoreErrors || gn->type & OP_IGNORE) {
339: return (TRUE);
340: } else {
341: return (FALSE);
342: }
343: }
344:
345: /*-
346: *-----------------------------------------------------------------------
347: * Targ_Silent --
348: * Return true if be silent when creating gn
349: *
350: * Results:
351: * TRUE if should be silent
352: *
353: * Side Effects:
354: * None
355: *-----------------------------------------------------------------------
356: */
357: Boolean
358: Targ_Silent (gn)
359: GNode *gn; /* node to check for */
360: {
361: if (beSilent || gn->type & OP_SILENT) {
362: return (TRUE);
363: } else {
364: return (FALSE);
365: }
366: }
367:
368: /*-
369: *-----------------------------------------------------------------------
370: * Targ_Precious --
371: * See if the given target is precious
372: *
373: * Results:
374: * TRUE if it is precious. FALSE otherwise
375: *
376: * Side Effects:
377: * None
378: *-----------------------------------------------------------------------
379: */
380: Boolean
381: Targ_Precious (gn)
382: GNode *gn; /* the node to check */
383: {
384: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
385: return (TRUE);
386: } else {
387: return (FALSE);
388: }
389: }
390:
391: /******************* DEBUG INFO PRINTING ****************/
392:
393: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
394: /*-
395: *-----------------------------------------------------------------------
396: * Targ_SetMain --
397: * Set our idea of the main target we'll be creating. Used for
398: * debugging output.
399: *
400: * Results:
401: * None.
402: *
403: * Side Effects:
404: * "mainTarg" is set to the main target's node.
405: *-----------------------------------------------------------------------
406: */
407: void
408: Targ_SetMain (gn)
409: GNode *gn; /* The main target we'll create */
410: {
411: mainTarg = gn;
412: }
413:
414: static int
1.4 ! jtc 415: TargPrintName (gnp, ppath)
! 416: ClientData gnp;
! 417: ClientData ppath;
1.1 cgd 418: {
1.4 ! jtc 419: GNode *gn = (GNode *) gnp;
1.1 cgd 420: printf ("%s ", gn->name);
421: #ifdef notdef
422: if (ppath) {
423: if (gn->path) {
424: printf ("[%s] ", gn->path);
425: }
426: if (gn == mainTarg) {
427: printf ("(MAIN NAME) ");
428: }
429: }
1.3 cgd 430: #endif /* notdef */
1.4 ! jtc 431: return (ppath ? 0 : 0);
1.1 cgd 432: }
433:
434:
435: int
1.4 ! jtc 436: Targ_PrintCmd (cmd, dummy)
! 437: ClientData cmd;
! 438: ClientData dummy;
1.1 cgd 439: {
1.4 ! jtc 440: printf ("\t%s\n", (char *) cmd);
! 441: return (dummy ? 0 : 0);
1.1 cgd 442: }
443:
444: /*-
445: *-----------------------------------------------------------------------
446: * Targ_FmtTime --
447: * Format a modification time in some reasonable way and return it.
448: *
449: * Results:
450: * The time reformatted.
451: *
452: * Side Effects:
453: * The time is placed in a static area, so it is overwritten
454: * with each call.
455: *
456: *-----------------------------------------------------------------------
457: */
458: char *
459: Targ_FmtTime (time)
460: time_t time;
461: {
462: struct tm *parts;
463: static char buf[40];
464: static char *months[] = {
465: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
466: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
467: };
468:
469: parts = localtime(&time);
470:
471: sprintf (buf, "%d:%02d:%02d %s %d, 19%d",
472: parts->tm_hour, parts->tm_min, parts->tm_sec,
473: months[parts->tm_mon], parts->tm_mday, parts->tm_year);
474: return(buf);
475: }
476:
477: /*-
478: *-----------------------------------------------------------------------
479: * Targ_PrintType --
480: * Print out a type field giving only those attributes the user can
481: * set.
482: *
483: * Results:
484: *
485: * Side Effects:
486: *
487: *-----------------------------------------------------------------------
488: */
489: void
490: Targ_PrintType (type)
491: register int type;
492: {
493: register int tbit;
494:
495: #ifdef __STDC__
496: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
497: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
498: #else
499: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
500: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
501: #endif /* __STDC__ */
502:
503: type &= ~OP_OPMASK;
504:
505: while (type) {
506: tbit = 1 << (ffs(type) - 1);
507: type &= ~tbit;
508:
509: switch(tbit) {
510: PRINTBIT(OPTIONAL);
511: PRINTBIT(USE);
512: PRINTBIT(EXEC);
513: PRINTBIT(IGNORE);
514: PRINTBIT(PRECIOUS);
515: PRINTBIT(SILENT);
516: PRINTBIT(MAKE);
517: PRINTBIT(JOIN);
518: PRINTBIT(INVISIBLE);
519: PRINTBIT(NOTMAIN);
520: PRINTDBIT(LIB);
521: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
522: case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
523: PRINTDBIT(ARCHV);
524: }
525: }
526: }
527:
528: /*-
529: *-----------------------------------------------------------------------
530: * TargPrintNode --
531: * print the contents of a node
532: *-----------------------------------------------------------------------
533: */
534: static int
1.4 ! jtc 535: TargPrintNode (gnp, passp)
! 536: ClientData gnp;
! 537: ClientData passp;
1.1 cgd 538: {
1.4 ! jtc 539: GNode *gn = (GNode *) gnp;
! 540: int pass = *(int *) passp;
1.1 cgd 541: if (!OP_NOP(gn->type)) {
542: printf("#\n");
543: if (gn == mainTarg) {
544: printf("# *** MAIN TARGET ***\n");
545: }
546: if (pass == 2) {
547: if (gn->unmade) {
548: printf("# %d unmade children\n", gn->unmade);
549: } else {
550: printf("# No unmade children\n");
551: }
552: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
553: if (gn->mtime != 0) {
554: printf("# last modified %s: %s\n",
555: Targ_FmtTime(gn->mtime),
556: (gn->made == UNMADE ? "unmade" :
557: (gn->made == MADE ? "made" :
558: (gn->made == UPTODATE ? "up-to-date" :
559: "error when made"))));
560: } else if (gn->made != UNMADE) {
561: printf("# non-existent (maybe): %s\n",
562: (gn->made == MADE ? "made" :
563: (gn->made == UPTODATE ? "up-to-date" :
564: (gn->made == ERROR ? "error when made" :
565: "aborted"))));
566: } else {
567: printf("# unmade\n");
568: }
569: }
570: if (!Lst_IsEmpty (gn->iParents)) {
571: printf("# implicit parents: ");
572: Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
1.3 cgd 573: fputc ('\n', stdout);
1.1 cgd 574: }
575: }
576: if (!Lst_IsEmpty (gn->parents)) {
577: printf("# parents: ");
578: Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
1.3 cgd 579: fputc ('\n', stdout);
1.1 cgd 580: }
581:
582: printf("%-16s", gn->name);
583: switch (gn->type & OP_OPMASK) {
584: case OP_DEPENDS:
585: printf(": "); break;
586: case OP_FORCE:
587: printf("! "); break;
588: case OP_DOUBLEDEP:
589: printf(":: "); break;
590: }
591: Targ_PrintType (gn->type);
592: Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
1.3 cgd 593: fputc ('\n', stdout);
1.1 cgd 594: Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
595: printf("\n\n");
596: if (gn->type & OP_DOUBLEDEP) {
1.4 ! jtc 597: Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
1.1 cgd 598: }
599: }
600: return (0);
601: }
602:
603: /*-
604: *-----------------------------------------------------------------------
605: * TargPrintOnlySrc --
606: * Print only those targets that are just a source.
607: *
608: * Results:
609: * 0.
610: *
611: * Side Effects:
612: * The name of each file is printed preceeded by #\t
613: *
614: *-----------------------------------------------------------------------
615: */
616: static int
1.4 ! jtc 617: TargPrintOnlySrc(gnp, dummy)
! 618: ClientData gnp;
! 619: ClientData dummy;
! 620: {
! 621: GNode *gn = (GNode *) gnp;
! 622: if (OP_NOP(gn->type))
! 623: printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
! 624:
! 625: return (dummy ? 0 : 0);
1.1 cgd 626: }
627:
628: /*-
629: *-----------------------------------------------------------------------
630: * Targ_PrintGraph --
631: * print the entire graph. heh heh
632: *
633: * Results:
634: * none
635: *
636: * Side Effects:
637: * lots o' output
638: *-----------------------------------------------------------------------
639: */
1.3 cgd 640: void
1.1 cgd 641: Targ_PrintGraph (pass)
642: int pass; /* Which pass this is. 1 => no processing
643: * 2 => processing done */
644: {
645: printf("#*** Input graph:\n");
1.4 ! jtc 646: Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
1.1 cgd 647: printf("\n\n");
648: printf("#\n# Files that are only sources:\n");
1.4 ! jtc 649: Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
1.1 cgd 650: printf("#*** Global Variables:\n");
651: Var_Dump (VAR_GLOBAL);
652: printf("#*** Command-line Variables:\n");
653: Var_Dump (VAR_CMD);
654: printf("\n");
655: Dir_PrintDirectories();
656: printf("\n");
657: Suff_PrintAll();
658: }
CVSweb <webmaster@jp.NetBSD.org>