Annotation of src/usr.bin/make/targ.c, Revision 1.17
1.17 ! espie 1: /* $OpenBSD: targ.c,v 1.16 2000/04/17 23:57:46 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.17 ! espie 46: static char *rcsid = "$OpenBSD: targ.c,v 1.16 2000/04/17 23:57:46 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:
1.17 ! espie 105: static void TargPrintOnlySrc __P((ClientData));
! 106: static void TargPrintName __P((ClientData));
! 107: static void 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:
1.17 ! espie 432: static void
! 433: TargPrintName(gnp)
1.1 deraadt 434: ClientData gnp;
435: {
1.17 ! espie 436: GNode *gn = (GNode *)gnp;
! 437:
! 438: printf("%s ", gn->name);
1.1 deraadt 439: }
440:
441:
1.17 ! espie 442: void
! 443: Targ_PrintCmd(cmd)
1.1 deraadt 444: ClientData cmd;
445: {
1.17 ! espie 446: printf("\t%s\n", (char *)cmd);
1.1 deraadt 447: }
448:
449: /*-
450: *-----------------------------------------------------------------------
451: * Targ_FmtTime --
452: * Format a modification time in some reasonable way and return it.
453: *
454: * Results:
455: * The time reformatted.
456: *
457: * Side Effects:
458: * The time is placed in a static area, so it is overwritten
459: * with each call.
460: *
461: *-----------------------------------------------------------------------
462: */
463: char *
464: Targ_FmtTime (time)
465: time_t time;
466: {
467: struct tm *parts;
1.8 deraadt 468: static char buf[128];
1.1 deraadt 469:
470: parts = localtime(&time);
1.8 deraadt 471: strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
472: buf[sizeof(buf) - 1] = '\0';
1.1 deraadt 473: return(buf);
474: }
1.5 millert 475:
1.1 deraadt 476: /*-
477: *-----------------------------------------------------------------------
478: * Targ_PrintType --
479: * Print out a type field giving only those attributes the user can
480: * set.
481: *
482: * Results:
483: *
484: * Side Effects:
485: *
486: *-----------------------------------------------------------------------
487: */
488: void
489: Targ_PrintType (type)
490: register int type;
491: {
492: register int tbit;
1.5 millert 493:
1.1 deraadt 494: #ifdef __STDC__
495: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
496: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
497: #else
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: #endif /* __STDC__ */
501:
502: type &= ~OP_OPMASK;
503:
504: while (type) {
505: tbit = 1 << (ffs(type) - 1);
506: type &= ~tbit;
507:
508: switch(tbit) {
509: PRINTBIT(OPTIONAL);
510: PRINTBIT(USE);
511: PRINTBIT(EXEC);
512: PRINTBIT(IGNORE);
513: PRINTBIT(PRECIOUS);
514: PRINTBIT(SILENT);
515: PRINTBIT(MAKE);
516: PRINTBIT(JOIN);
517: PRINTBIT(INVISIBLE);
518: PRINTBIT(NOTMAIN);
519: PRINTDBIT(LIB);
520: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
521: case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
522: PRINTDBIT(ARCHV);
523: }
524: }
525: }
526:
527: /*-
528: *-----------------------------------------------------------------------
529: * TargPrintNode --
530: * print the contents of a node
531: *-----------------------------------------------------------------------
532: */
1.17 ! espie 533: static void
! 534: TargPrintNode(gnp, passp)
1.1 deraadt 535: ClientData gnp;
536: ClientData passp;
537: {
1.17 ! espie 538: GNode *gn = (GNode *)gnp;
! 539: int pass = *(int *)passp;
1.1 deraadt 540: if (!OP_NOP(gn->type)) {
541: printf("#\n");
1.17 ! espie 542: if (gn == mainTarg)
1.1 deraadt 543: printf("# *** MAIN TARGET ***\n");
544: if (pass == 2) {
1.17 ! espie 545: if (gn->unmade)
1.1 deraadt 546: printf("# %d unmade children\n", gn->unmade);
1.17 ! espie 547: else
1.1 deraadt 548: printf("# No unmade children\n");
549: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
1.17 ! espie 550: if (gn->mtime != OUT_OF_DATE)
1.1 deraadt 551: printf("# last modified %s: %s\n",
552: Targ_FmtTime(gn->mtime),
553: (gn->made == UNMADE ? "unmade" :
554: (gn->made == MADE ? "made" :
555: (gn->made == UPTODATE ? "up-to-date" :
556: "error when made"))));
1.17 ! espie 557: else if (gn->made != UNMADE)
1.1 deraadt 558: printf("# non-existent (maybe): %s\n",
559: (gn->made == MADE ? "made" :
560: (gn->made == UPTODATE ? "up-to-date" :
561: (gn->made == ERROR ? "error when made" :
562: "aborted"))));
1.17 ! espie 563: else
1.1 deraadt 564: printf("# unmade\n");
565: }
566: if (!Lst_IsEmpty (gn->iParents)) {
567: printf("# implicit parents: ");
1.17 ! espie 568: Lst_Every(gn->iParents, TargPrintName);
! 569: fputc('\n', stdout);
1.1 deraadt 570: }
571: }
572: if (!Lst_IsEmpty (gn->parents)) {
573: printf("# parents: ");
1.17 ! espie 574: Lst_Every(gn->parents, TargPrintName);
1.1 deraadt 575: fputc ('\n', stdout);
576: }
1.5 millert 577:
1.1 deraadt 578: printf("%-16s", gn->name);
579: switch (gn->type & OP_OPMASK) {
580: case OP_DEPENDS:
581: printf(": "); break;
582: case OP_FORCE:
583: printf("! "); break;
584: case OP_DOUBLEDEP:
585: printf(":: "); break;
586: }
1.17 ! espie 587: Targ_PrintType(gn->type);
! 588: Lst_Every(gn->children, TargPrintName);
! 589: fputc('\n', stdout);
! 590: Lst_Every(gn->commands, Targ_PrintCmd);
1.1 deraadt 591: printf("\n\n");
1.17 ! espie 592: if (gn->type & OP_DOUBLEDEP)
1.15 espie 593: Lst_ForEach(gn->cohorts, TargPrintNode, &pass);
1.1 deraadt 594: }
595: }
596:
597: /*-
598: *-----------------------------------------------------------------------
599: * TargPrintOnlySrc --
600: * Print only those targets that are just a source.
601: *
602: * Side Effects:
603: * The name of each file is printed preceeded by #\t
604: *
605: *-----------------------------------------------------------------------
606: */
1.17 ! espie 607: static void
! 608: TargPrintOnlySrc(gnp)
1.1 deraadt 609: ClientData gnp;
610: {
1.17 ! espie 611: GNode *gn = (GNode *)gnp;
! 612:
1.1 deraadt 613: if (OP_NOP(gn->type))
614: printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
615: }
616:
617: /*-
618: *-----------------------------------------------------------------------
619: * Targ_PrintGraph --
620: * print the entire graph. heh heh
621: *
622: * Results:
623: * none
624: *
625: * Side Effects:
626: * lots o' output
627: *-----------------------------------------------------------------------
628: */
629: void
630: Targ_PrintGraph (pass)
631: int pass; /* Which pass this is. 1 => no processing
632: * 2 => processing done */
633: {
634: printf("#*** Input graph:\n");
1.15 espie 635: Lst_ForEach(allTargets, TargPrintNode, &pass);
1.1 deraadt 636: printf("\n\n");
637: printf("#\n# Files that are only sources:\n");
1.17 ! espie 638: Lst_Every(allTargets, TargPrintOnlySrc);
1.1 deraadt 639: printf("#*** Global Variables:\n");
640: Var_Dump (VAR_GLOBAL);
641: printf("#*** Command-line Variables:\n");
642: Var_Dump (VAR_CMD);
643: printf("\n");
644: Dir_PrintDirectories();
645: printf("\n");
646: Suff_PrintAll();
647: }