Annotation of src/usr.bin/make/targ.c, Revision 1.9
1.8 deraadt 1: /* $OpenBSD: targ.c,v 1.7 1997/04/28 01:52:42 millert 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.8 deraadt 46: static char *rcsid = "$OpenBSD: targ.c,v 1.7 1997/04/28 01:52:42 millert 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 */
98: static Lst allGNs; /* List of all the GNodes */
99: static Hash_Table targets; /* a hash table of same */
100:
101: #define HTSIZE 191 /* initial size of hash table */
102:
103: static int TargPrintOnlySrc __P((ClientData, ClientData));
104: static int TargPrintName __P((ClientData, ClientData));
105: static int TargPrintNode __P((ClientData, ClientData));
106: static void TargFreeGN __P((ClientData));
107:
108: /*-
109: *-----------------------------------------------------------------------
110: * Targ_Init --
111: * Initialize this module
112: *
113: * Results:
114: * None
115: *
116: * Side Effects:
117: * The allTargets list and the targets hash table are initialized
118: *-----------------------------------------------------------------------
119: */
120: void
121: Targ_Init ()
122: {
123: allTargets = Lst_Init (FALSE);
124: Hash_InitTable (&targets, HTSIZE);
125: }
126:
127: /*-
128: *-----------------------------------------------------------------------
129: * Targ_End --
130: * Finalize this module
131: *
132: * Results:
133: * None
134: *
135: * Side Effects:
136: * All lists and gnodes are cleared
137: *-----------------------------------------------------------------------
138: */
139: void
140: Targ_End ()
141: {
142: Lst_Destroy(allTargets, NOFREE);
143: if (allGNs)
144: Lst_Destroy(allGNs, TargFreeGN);
145: Hash_DeleteTable(&targets);
146: }
147:
148: /*-
149: *-----------------------------------------------------------------------
150: * Targ_NewGN --
151: * Create and initialize a new graph node
152: *
153: * Results:
154: * An initialized graph node with the name field filled with a copy
155: * of the passed name
156: *
157: * Side Effects:
158: * The gnode is added to the list of all gnodes.
159: *-----------------------------------------------------------------------
160: */
161: GNode *
162: Targ_NewGN (name)
163: char *name; /* the name to stick in the new node */
164: {
165: register GNode *gn;
166:
167: gn = (GNode *) emalloc (sizeof (GNode));
1.4 briggs 168: gn->name = estrdup (name);
1.1 deraadt 169: gn->path = (char *) 0;
170: if (name[0] == '-' && name[1] == 'l') {
171: gn->type = OP_LIB;
172: } else {
173: gn->type = 0;
174: }
175: gn->unmade = 0;
176: gn->make = FALSE;
177: gn->made = UNMADE;
178: gn->childMade = FALSE;
1.2 deraadt 179: gn->order = 0;
1.1 deraadt 180: gn->mtime = gn->cmtime = 0;
181: gn->iParents = Lst_Init (FALSE);
182: gn->cohorts = Lst_Init (FALSE);
183: gn->parents = Lst_Init (FALSE);
184: gn->children = Lst_Init (FALSE);
185: gn->successors = Lst_Init (FALSE);
186: gn->preds = Lst_Init (FALSE);
187: gn->context = Lst_Init (FALSE);
188: gn->commands = Lst_Init (FALSE);
189: gn->suffix = NULL;
190:
191: if (allGNs == NULL)
192: allGNs = Lst_Init(FALSE);
193: Lst_AtEnd(allGNs, (ClientData) gn);
194:
195: return (gn);
196: }
197:
198: /*-
199: *-----------------------------------------------------------------------
200: * TargFreeGN --
201: * Destroy a GNode
202: *
203: * Results:
204: * None.
205: *
206: * Side Effects:
207: * None.
208: *-----------------------------------------------------------------------
209: */
210: static void
211: TargFreeGN (gnp)
212: ClientData gnp;
213: {
214: GNode *gn = (GNode *) gnp;
215:
216:
217: free(gn->name);
1.9 ! espie 218: efree(gn->path);
1.1 deraadt 219:
220: Lst_Destroy(gn->iParents, NOFREE);
221: Lst_Destroy(gn->cohorts, NOFREE);
222: Lst_Destroy(gn->parents, NOFREE);
223: Lst_Destroy(gn->children, NOFREE);
224: Lst_Destroy(gn->successors, NOFREE);
225: Lst_Destroy(gn->preds, NOFREE);
226: Lst_Destroy(gn->context, NOFREE);
227: Lst_Destroy(gn->commands, NOFREE);
228: free((Address)gn);
229: }
230:
231:
232: /*-
233: *-----------------------------------------------------------------------
234: * Targ_FindNode --
235: * Find a node in the list using the given name for matching
236: *
237: * Results:
238: * The node in the list if it was. If it wasn't, return NILGNODE of
239: * flags was TARG_NOCREATE or the newly created and initialized node
240: * if it was TARG_CREATE
241: *
242: * Side Effects:
243: * Sometimes a node is created and added to the list
244: *-----------------------------------------------------------------------
245: */
246: GNode *
247: Targ_FindNode (name, flags)
248: char *name; /* the name to find */
249: int flags; /* flags governing events when target not
250: * found */
251: {
252: GNode *gn; /* node in that element */
253: Hash_Entry *he; /* New or used hash entry for node */
254: Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
255: /* an entry for the node */
256:
257:
258: if (flags & TARG_CREATE) {
259: he = Hash_CreateEntry (&targets, name, &isNew);
260: if (isNew) {
261: gn = Targ_NewGN (name);
262: Hash_SetValue (he, gn);
263: (void) Lst_AtEnd (allTargets, (ClientData)gn);
264: }
265: } else {
266: he = Hash_FindEntry (&targets, name);
267: }
268:
269: if (he == (Hash_Entry *) NULL) {
270: return (NILGNODE);
271: } else {
272: return ((GNode *) Hash_GetValue (he));
273: }
274: }
275:
276: /*-
277: *-----------------------------------------------------------------------
278: * Targ_FindList --
1.5 millert 279: * Make a complete list of GNodes from the given list of names
1.1 deraadt 280: *
281: * Results:
282: * A complete list of graph nodes corresponding to all instances of all
1.5 millert 283: * the names in names.
1.1 deraadt 284: *
285: * Side Effects:
286: * If flags is TARG_CREATE, nodes will be created for all names in
287: * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
288: * an error message will be printed for each name which can't be found.
289: * -----------------------------------------------------------------------
290: */
291: Lst
292: Targ_FindList (names, flags)
293: Lst names; /* list of names to find */
294: int flags; /* flags used if no node is found for a given
295: * name */
296: {
297: Lst nodes; /* result list */
298: register LstNode ln; /* name list element */
299: register GNode *gn; /* node in tLn */
300: char *name;
301:
302: nodes = Lst_Init (FALSE);
303:
304: if (Lst_Open (names) == FAILURE) {
305: return (nodes);
306: }
307: while ((ln = Lst_Next (names)) != NILLNODE) {
308: name = (char *)Lst_Datum(ln);
309: gn = Targ_FindNode (name, flags);
310: if (gn != NILGNODE) {
311: /*
312: * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
313: * are added to the list in the order in which they were
314: * encountered in the makefile.
315: */
316: (void) Lst_AtEnd (nodes, (ClientData)gn);
317: if (gn->type & OP_DOUBLEDEP) {
318: (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
319: }
320: } else if (flags == TARG_NOCREATE) {
321: Error ("\"%s\" -- target unknown.", name);
322: }
323: }
324: Lst_Close (names);
325: return (nodes);
326: }
327:
328: /*-
329: *-----------------------------------------------------------------------
330: * Targ_Ignore --
331: * Return true if should ignore errors when creating gn
332: *
333: * Results:
334: * TRUE if should ignore errors
335: *
336: * Side Effects:
337: * None
338: *-----------------------------------------------------------------------
339: */
340: Boolean
341: Targ_Ignore (gn)
342: GNode *gn; /* node to check for */
343: {
344: if (ignoreErrors || gn->type & OP_IGNORE) {
345: return (TRUE);
346: } else {
347: return (FALSE);
348: }
349: }
350:
351: /*-
352: *-----------------------------------------------------------------------
353: * Targ_Silent --
354: * Return true if be silent when creating gn
355: *
356: * Results:
357: * TRUE if should be silent
358: *
359: * Side Effects:
360: * None
361: *-----------------------------------------------------------------------
362: */
363: Boolean
364: Targ_Silent (gn)
365: GNode *gn; /* node to check for */
366: {
367: if (beSilent || gn->type & OP_SILENT) {
368: return (TRUE);
369: } else {
370: return (FALSE);
371: }
372: }
373:
374: /*-
375: *-----------------------------------------------------------------------
376: * Targ_Precious --
377: * See if the given target is precious
378: *
379: * Results:
380: * TRUE if it is precious. FALSE otherwise
381: *
382: * Side Effects:
383: * None
384: *-----------------------------------------------------------------------
385: */
386: Boolean
387: Targ_Precious (gn)
388: GNode *gn; /* the node to check */
389: {
390: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
391: return (TRUE);
392: } else {
393: return (FALSE);
394: }
395: }
396:
397: /******************* DEBUG INFO PRINTING ****************/
398:
399: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
1.5 millert 400: /*-
1.1 deraadt 401: *-----------------------------------------------------------------------
402: * Targ_SetMain --
403: * Set our idea of the main target we'll be creating. Used for
404: * debugging output.
405: *
406: * Results:
407: * None.
408: *
409: * Side Effects:
410: * "mainTarg" is set to the main target's node.
411: *-----------------------------------------------------------------------
412: */
413: void
414: Targ_SetMain (gn)
415: GNode *gn; /* The main target we'll create */
416: {
417: mainTarg = gn;
418: }
419:
420: static int
421: TargPrintName (gnp, ppath)
422: ClientData gnp;
423: ClientData ppath;
424: {
425: GNode *gn = (GNode *) gnp;
426: printf ("%s ", gn->name);
427: #ifdef notdef
428: if (ppath) {
429: if (gn->path) {
430: printf ("[%s] ", gn->path);
431: }
432: if (gn == mainTarg) {
433: printf ("(MAIN NAME) ");
434: }
435: }
436: #endif /* notdef */
437: return (ppath ? 0 : 0);
438: }
439:
440:
441: int
442: Targ_PrintCmd (cmd, dummy)
443: ClientData cmd;
444: ClientData dummy;
445: {
446: printf ("\t%s\n", (char *) cmd);
447: return (dummy ? 0 : 0);
448: }
449:
450: /*-
451: *-----------------------------------------------------------------------
452: * Targ_FmtTime --
453: * Format a modification time in some reasonable way and return it.
454: *
455: * Results:
456: * The time reformatted.
457: *
458: * Side Effects:
459: * The time is placed in a static area, so it is overwritten
460: * with each call.
461: *
462: *-----------------------------------------------------------------------
463: */
464: char *
465: Targ_FmtTime (time)
466: time_t time;
467: {
468: struct tm *parts;
1.8 deraadt 469: static char buf[128];
1.1 deraadt 470:
471: parts = localtime(&time);
1.8 deraadt 472: strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
473: buf[sizeof(buf) - 1] = '\0';
1.1 deraadt 474: return(buf);
475: }
1.5 millert 476:
1.1 deraadt 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;
1.5 millert 494:
1.1 deraadt 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
535: TargPrintNode (gnp, passp)
536: ClientData gnp;
537: ClientData passp;
538: {
539: GNode *gn = (GNode *) gnp;
540: int pass = *(int *) passp;
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);
573: fputc ('\n', stdout);
574: }
575: }
576: if (!Lst_IsEmpty (gn->parents)) {
577: printf("# parents: ");
578: Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
579: fputc ('\n', stdout);
580: }
1.5 millert 581:
1.1 deraadt 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);
593: fputc ('\n', stdout);
594: Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
595: printf("\n\n");
596: if (gn->type & OP_DOUBLEDEP) {
597: Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
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
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);
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: */
640: void
641: Targ_PrintGraph (pass)
642: int pass; /* Which pass this is. 1 => no processing
643: * 2 => processing done */
644: {
645: printf("#*** Input graph:\n");
646: Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
647: printf("\n\n");
648: printf("#\n# Files that are only sources:\n");
649: Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
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: }