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