Annotation of src/usr.bin/make/targ.c, Revision 1.5
1.5 ! millert 1: /* $OpenBSD: targ.c,v 1.4 1996/09/02 16:04:20 briggs Exp $ */
! 2: /* $NetBSD: targ.c,v 1.10 1996/11/06 17:59:27 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
! 46: static char *rcsid = "$OpenBSD: targ.c,v 1.4 1996/09/02 16:04:20 briggs Exp $";
! 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);
218: if (gn->path)
219: free(gn->path);
220:
221: Lst_Destroy(gn->iParents, NOFREE);
222: Lst_Destroy(gn->cohorts, NOFREE);
223: Lst_Destroy(gn->parents, NOFREE);
224: Lst_Destroy(gn->children, NOFREE);
225: Lst_Destroy(gn->successors, NOFREE);
226: Lst_Destroy(gn->preds, NOFREE);
227: Lst_Destroy(gn->context, NOFREE);
228: Lst_Destroy(gn->commands, NOFREE);
229: free((Address)gn);
230: }
231:
232:
233: /*-
234: *-----------------------------------------------------------------------
235: * Targ_FindNode --
236: * Find a node in the list using the given name for matching
237: *
238: * Results:
239: * The node in the list if it was. If it wasn't, return NILGNODE of
240: * flags was TARG_NOCREATE or the newly created and initialized node
241: * if it was TARG_CREATE
242: *
243: * Side Effects:
244: * Sometimes a node is created and added to the list
245: *-----------------------------------------------------------------------
246: */
247: GNode *
248: Targ_FindNode (name, flags)
249: char *name; /* the name to find */
250: int flags; /* flags governing events when target not
251: * found */
252: {
253: GNode *gn; /* node in that element */
254: Hash_Entry *he; /* New or used hash entry for node */
255: Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */
256: /* an entry for the node */
257:
258:
259: if (flags & TARG_CREATE) {
260: he = Hash_CreateEntry (&targets, name, &isNew);
261: if (isNew) {
262: gn = Targ_NewGN (name);
263: Hash_SetValue (he, gn);
264: (void) Lst_AtEnd (allTargets, (ClientData)gn);
265: }
266: } else {
267: he = Hash_FindEntry (&targets, name);
268: }
269:
270: if (he == (Hash_Entry *) NULL) {
271: return (NILGNODE);
272: } else {
273: return ((GNode *) Hash_GetValue (he));
274: }
275: }
276:
277: /*-
278: *-----------------------------------------------------------------------
279: * Targ_FindList --
1.5 ! millert 280: * Make a complete list of GNodes from the given list of names
1.1 deraadt 281: *
282: * Results:
283: * A complete list of graph nodes corresponding to all instances of all
1.5 ! millert 284: * the names in names.
1.1 deraadt 285: *
286: * Side Effects:
287: * If flags is TARG_CREATE, nodes will be created for all names in
288: * names which do not yet have graph nodes. If flags is TARG_NOCREATE,
289: * an error message will be printed for each name which can't be found.
290: * -----------------------------------------------------------------------
291: */
292: Lst
293: Targ_FindList (names, flags)
294: Lst names; /* list of names to find */
295: int flags; /* flags used if no node is found for a given
296: * name */
297: {
298: Lst nodes; /* result list */
299: register LstNode ln; /* name list element */
300: register GNode *gn; /* node in tLn */
301: char *name;
302:
303: nodes = Lst_Init (FALSE);
304:
305: if (Lst_Open (names) == FAILURE) {
306: return (nodes);
307: }
308: while ((ln = Lst_Next (names)) != NILLNODE) {
309: name = (char *)Lst_Datum(ln);
310: gn = Targ_FindNode (name, flags);
311: if (gn != NILGNODE) {
312: /*
313: * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
314: * are added to the list in the order in which they were
315: * encountered in the makefile.
316: */
317: (void) Lst_AtEnd (nodes, (ClientData)gn);
318: if (gn->type & OP_DOUBLEDEP) {
319: (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);
320: }
321: } else if (flags == TARG_NOCREATE) {
322: Error ("\"%s\" -- target unknown.", name);
323: }
324: }
325: Lst_Close (names);
326: return (nodes);
327: }
328:
329: /*-
330: *-----------------------------------------------------------------------
331: * Targ_Ignore --
332: * Return true if should ignore errors when creating gn
333: *
334: * Results:
335: * TRUE if should ignore errors
336: *
337: * Side Effects:
338: * None
339: *-----------------------------------------------------------------------
340: */
341: Boolean
342: Targ_Ignore (gn)
343: GNode *gn; /* node to check for */
344: {
345: if (ignoreErrors || gn->type & OP_IGNORE) {
346: return (TRUE);
347: } else {
348: return (FALSE);
349: }
350: }
351:
352: /*-
353: *-----------------------------------------------------------------------
354: * Targ_Silent --
355: * Return true if be silent when creating gn
356: *
357: * Results:
358: * TRUE if should be silent
359: *
360: * Side Effects:
361: * None
362: *-----------------------------------------------------------------------
363: */
364: Boolean
365: Targ_Silent (gn)
366: GNode *gn; /* node to check for */
367: {
368: if (beSilent || gn->type & OP_SILENT) {
369: return (TRUE);
370: } else {
371: return (FALSE);
372: }
373: }
374:
375: /*-
376: *-----------------------------------------------------------------------
377: * Targ_Precious --
378: * See if the given target is precious
379: *
380: * Results:
381: * TRUE if it is precious. FALSE otherwise
382: *
383: * Side Effects:
384: * None
385: *-----------------------------------------------------------------------
386: */
387: Boolean
388: Targ_Precious (gn)
389: GNode *gn; /* the node to check */
390: {
391: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) {
392: return (TRUE);
393: } else {
394: return (FALSE);
395: }
396: }
397:
398: /******************* DEBUG INFO PRINTING ****************/
399:
400: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
1.5 ! millert 401: /*-
1.1 deraadt 402: *-----------------------------------------------------------------------
403: * Targ_SetMain --
404: * Set our idea of the main target we'll be creating. Used for
405: * debugging output.
406: *
407: * Results:
408: * None.
409: *
410: * Side Effects:
411: * "mainTarg" is set to the main target's node.
412: *-----------------------------------------------------------------------
413: */
414: void
415: Targ_SetMain (gn)
416: GNode *gn; /* The main target we'll create */
417: {
418: mainTarg = gn;
419: }
420:
421: static int
422: TargPrintName (gnp, ppath)
423: ClientData gnp;
424: ClientData ppath;
425: {
426: GNode *gn = (GNode *) gnp;
427: printf ("%s ", gn->name);
428: #ifdef notdef
429: if (ppath) {
430: if (gn->path) {
431: printf ("[%s] ", gn->path);
432: }
433: if (gn == mainTarg) {
434: printf ("(MAIN NAME) ");
435: }
436: }
437: #endif /* notdef */
438: return (ppath ? 0 : 0);
439: }
440:
441:
442: int
443: Targ_PrintCmd (cmd, dummy)
444: ClientData cmd;
445: ClientData dummy;
446: {
447: printf ("\t%s\n", (char *) cmd);
448: return (dummy ? 0 : 0);
449: }
450:
451: /*-
452: *-----------------------------------------------------------------------
453: * Targ_FmtTime --
454: * Format a modification time in some reasonable way and return it.
455: *
456: * Results:
457: * The time reformatted.
458: *
459: * Side Effects:
460: * The time is placed in a static area, so it is overwritten
461: * with each call.
462: *
463: *-----------------------------------------------------------------------
464: */
465: char *
466: Targ_FmtTime (time)
467: time_t time;
468: {
469: struct tm *parts;
470: static char buf[40];
471: static char *months[] = {
472: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
473: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
474: };
475:
476: parts = localtime(&time);
477:
1.3 deraadt 478: sprintf (buf, "%d:%02d:%02d %s %d, %d",
1.1 deraadt 479: parts->tm_hour, parts->tm_min, parts->tm_sec,
1.3 deraadt 480: months[parts->tm_mon], parts->tm_mday, 1900 + parts->tm_year);
1.1 deraadt 481: return(buf);
482: }
1.5 ! millert 483:
1.1 deraadt 484: /*-
485: *-----------------------------------------------------------------------
486: * Targ_PrintType --
487: * Print out a type field giving only those attributes the user can
488: * set.
489: *
490: * Results:
491: *
492: * Side Effects:
493: *
494: *-----------------------------------------------------------------------
495: */
496: void
497: Targ_PrintType (type)
498: register int type;
499: {
500: register int tbit;
1.5 ! millert 501:
1.1 deraadt 502: #ifdef __STDC__
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: #else
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: #endif /* __STDC__ */
509:
510: type &= ~OP_OPMASK;
511:
512: while (type) {
513: tbit = 1 << (ffs(type) - 1);
514: type &= ~tbit;
515:
516: switch(tbit) {
517: PRINTBIT(OPTIONAL);
518: PRINTBIT(USE);
519: PRINTBIT(EXEC);
520: PRINTBIT(IGNORE);
521: PRINTBIT(PRECIOUS);
522: PRINTBIT(SILENT);
523: PRINTBIT(MAKE);
524: PRINTBIT(JOIN);
525: PRINTBIT(INVISIBLE);
526: PRINTBIT(NOTMAIN);
527: PRINTDBIT(LIB);
528: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
529: case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
530: PRINTDBIT(ARCHV);
531: }
532: }
533: }
534:
535: /*-
536: *-----------------------------------------------------------------------
537: * TargPrintNode --
538: * print the contents of a node
539: *-----------------------------------------------------------------------
540: */
541: static int
542: TargPrintNode (gnp, passp)
543: ClientData gnp;
544: ClientData passp;
545: {
546: GNode *gn = (GNode *) gnp;
547: int pass = *(int *) passp;
548: if (!OP_NOP(gn->type)) {
549: printf("#\n");
550: if (gn == mainTarg) {
551: printf("# *** MAIN TARGET ***\n");
552: }
553: if (pass == 2) {
554: if (gn->unmade) {
555: printf("# %d unmade children\n", gn->unmade);
556: } else {
557: printf("# No unmade children\n");
558: }
559: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
560: if (gn->mtime != 0) {
561: printf("# last modified %s: %s\n",
562: Targ_FmtTime(gn->mtime),
563: (gn->made == UNMADE ? "unmade" :
564: (gn->made == MADE ? "made" :
565: (gn->made == UPTODATE ? "up-to-date" :
566: "error when made"))));
567: } else if (gn->made != UNMADE) {
568: printf("# non-existent (maybe): %s\n",
569: (gn->made == MADE ? "made" :
570: (gn->made == UPTODATE ? "up-to-date" :
571: (gn->made == ERROR ? "error when made" :
572: "aborted"))));
573: } else {
574: printf("# unmade\n");
575: }
576: }
577: if (!Lst_IsEmpty (gn->iParents)) {
578: printf("# implicit parents: ");
579: Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);
580: fputc ('\n', stdout);
581: }
582: }
583: if (!Lst_IsEmpty (gn->parents)) {
584: printf("# parents: ");
585: Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);
586: fputc ('\n', stdout);
587: }
1.5 ! millert 588:
1.1 deraadt 589: printf("%-16s", gn->name);
590: switch (gn->type & OP_OPMASK) {
591: case OP_DEPENDS:
592: printf(": "); break;
593: case OP_FORCE:
594: printf("! "); break;
595: case OP_DOUBLEDEP:
596: printf(":: "); break;
597: }
598: Targ_PrintType (gn->type);
599: Lst_ForEach (gn->children, TargPrintName, (ClientData)0);
600: fputc ('\n', stdout);
601: Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);
602: printf("\n\n");
603: if (gn->type & OP_DOUBLEDEP) {
604: Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);
605: }
606: }
607: return (0);
608: }
609:
610: /*-
611: *-----------------------------------------------------------------------
612: * TargPrintOnlySrc --
613: * Print only those targets that are just a source.
614: *
615: * Results:
616: * 0.
617: *
618: * Side Effects:
619: * The name of each file is printed preceeded by #\t
620: *
621: *-----------------------------------------------------------------------
622: */
623: static int
624: TargPrintOnlySrc(gnp, dummy)
625: ClientData gnp;
626: ClientData dummy;
627: {
628: GNode *gn = (GNode *) gnp;
629: if (OP_NOP(gn->type))
630: printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
631:
632: return (dummy ? 0 : 0);
633: }
634:
635: /*-
636: *-----------------------------------------------------------------------
637: * Targ_PrintGraph --
638: * print the entire graph. heh heh
639: *
640: * Results:
641: * none
642: *
643: * Side Effects:
644: * lots o' output
645: *-----------------------------------------------------------------------
646: */
647: void
648: Targ_PrintGraph (pass)
649: int pass; /* Which pass this is. 1 => no processing
650: * 2 => processing done */
651: {
652: printf("#*** Input graph:\n");
653: Lst_ForEach (allTargets, TargPrintNode, (ClientData)&pass);
654: printf("\n\n");
655: printf("#\n# Files that are only sources:\n");
656: Lst_ForEach (allTargets, TargPrintOnlySrc, (ClientData) 0);
657: printf("#*** Global Variables:\n");
658: Var_Dump (VAR_GLOBAL);
659: printf("#*** Command-line Variables:\n");
660: Var_Dump (VAR_CMD);
661: printf("\n");
662: Dir_PrintDirectories();
663: printf("\n");
664: Suff_PrintAll();
665: }