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