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