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