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