Annotation of src/usr.bin/make/targ.c, Revision 1.30
1.30 ! espie 1: /* $OpenBSD: targ.c,v 1.29 2000/11/24 14:36:35 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: /*-
43: * targ.c --
1.27 espie 44: * Target nodes are kept into a hash table.
1.1 deraadt 45: *
46: * Interface:
47: * Targ_Init Initialization procedure.
48: *
49: * Targ_End Cleanup the module
50: *
51: * Targ_NewGN Create a new GNode for the passed target
52: * (string). The node is *not* placed in the
53: * hash table, though all its fields are
54: * initialized.
55: *
56: * Targ_FindNode Find the node for a given target, creating
57: * and storing it if it doesn't exist and the
58: * flags are right (TARG_CREATE)
59: *
60: * Targ_FindList Given a list of names, find nodes for all
1.20 espie 61: * of them, creating nodes if needed.
1.1 deraadt 62: *
63: * Targ_Ignore Return TRUE if errors should be ignored when
64: * creating the given target.
65: *
66: * Targ_Silent Return TRUE if we should be silent when
67: * creating the given target.
68: *
69: * Targ_Precious Return TRUE if the target is precious and
70: * should not be removed if we are interrupted.
71: *
72: * Debugging:
73: * Targ_PrintGraph Print out the entire graphm all variables
74: * and statistics for the directory cache. Should
75: * print something for suffixes, too, but...
76: */
77:
1.27 espie 78: #include <stddef.h>
1.1 deraadt 79: #include <stdio.h>
80: #include <time.h>
81: #include "make.h"
1.27 espie 82: #include "ohash.h"
1.1 deraadt 83: #include "dir.h"
84:
1.26 espie 85: #ifndef lint
86: #if 0
87: static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";
88: #else
89: UNUSED
1.30 ! espie 90: static char *rcsid = "$OpenBSD: targ.c,v 1.29 2000/11/24 14:36:35 espie Exp $";
1.26 espie 91: #endif
92: #endif /* not lint */
93:
1.10 espie 94: #ifdef CLEANUP
1.19 espie 95: static LIST allGNs; /* List of all the GNodes */
1.10 espie 96: #endif
1.30 ! espie 97: static struct ohash targets; /* a hash table of same */
! 98: static struct ohash_info gnode_info = {
1.27 espie 99: offsetof(GNode, name),
100: NULL, hash_alloc, hash_free, element_alloc };
1.1 deraadt 101:
1.27 espie 102: static void TargPrintOnlySrc __P((GNode *));
1.18 espie 103: static void TargPrintName __P((void *));
1.27 espie 104: static void TargPrintNode __P((GNode *, int));
1.10 espie 105: #ifdef CLEANUP
1.18 espie 106: static void TargFreeGN __P((void *));
1.10 espie 107: #endif
1.1 deraadt 108:
109: /*-
110: *-----------------------------------------------------------------------
111: * Targ_Init --
112: * Initialize this module
113: *
1.26 espie 114: * Side Effects:
1.27 espie 115: * The targets hash table is initialized
1.1 deraadt 116: *-----------------------------------------------------------------------
117: */
118: void
1.19 espie 119: Targ_Init()
1.1 deraadt 120: {
1.19 espie 121: #ifdef CLEANUP
122: Lst_Init(&allGNs);
123: #endif
1.27 espie 124: /* A small make file already creates 200 targets. */
1.30 ! espie 125: ohash_init(&targets, 10, &gnode_info);
1.1 deraadt 126: }
127:
128: /*-
129: *-----------------------------------------------------------------------
130: * Targ_End --
131: * Finalize this module
132: *
133: * Side Effects:
134: * All lists and gnodes are cleared
135: *-----------------------------------------------------------------------
136: */
137: void
138: Targ_End ()
139: {
1.10 espie 140: #ifdef CLEANUP
1.19 espie 141: Lst_Destroy(&allGNs, TargFreeGN);
1.30 ! espie 142: ohash_delete(&targets);
1.10 espie 143: #endif
1.1 deraadt 144: }
145:
146: /*-
147: *-----------------------------------------------------------------------
148: * Targ_NewGN --
149: * Create and initialize a new graph node
150: *
151: * Results:
152: * An initialized graph node with the name field filled with a copy
153: * of the passed name
154: *
155: * Side Effects:
1.27 espie 156: * The gnode is added to the set of all gnodes.
1.1 deraadt 157: *-----------------------------------------------------------------------
158: */
159: GNode *
1.27 espie 160: Targ_NewGN(name, end)
161: const char *name; /* the name to stick in the new node */
162: const char *end;
1.1 deraadt 163: {
1.27 espie 164: GNode *gn;
1.1 deraadt 165:
1.30 ! espie 166: gn = ohash_create_entry(&gnode_info, name, &end);
1.27 espie 167: gn->path = NULL;
1.1 deraadt 168: if (name[0] == '-' && name[1] == 'l') {
169: gn->type = OP_LIB;
170: } else {
171: gn->type = 0;
172: }
173: gn->unmade = 0;
174: gn->make = FALSE;
175: gn->made = UNMADE;
176: gn->childMade = FALSE;
1.2 deraadt 177: gn->order = 0;
1.29 espie 178: set_out_of_date(gn->mtime);
179: set_out_of_date(gn->cmtime);
1.19 espie 180: Lst_Init(&gn->iParents);
181: Lst_Init(&gn->cohorts);
182: Lst_Init(&gn->parents);
183: Lst_Init(&gn->children);
184: Lst_Init(&gn->successors);
185: Lst_Init(&gn->preds);
1.25 espie 186: SymTable_Init(&gn->context);
1.16 espie 187: gn->lineno = 0;
188: gn->fname = NULL;
1.19 espie 189: Lst_Init(&gn->commands);
1.1 deraadt 190: gn->suffix = NULL;
191:
1.10 espie 192: #ifdef CLEANUP
1.19 espie 193: Lst_AtEnd(&allGNs, gn);
1.10 espie 194: #endif
1.1 deraadt 195:
1.27 espie 196: return gn;
1.1 deraadt 197: }
198:
1.10 espie 199: #ifdef CLEANUP
1.1 deraadt 200: /*-
201: *-----------------------------------------------------------------------
202: * TargFreeGN --
203: * Destroy a GNode
204: *
205: * Results:
206: * None.
207: *
208: * Side Effects:
209: * None.
210: *-----------------------------------------------------------------------
211: */
212: static void
1.18 espie 213: TargFreeGN(gnp)
214: void *gnp;
1.1 deraadt 215: {
216: GNode *gn = (GNode *) gnp;
217:
1.9 espie 218: efree(gn->path);
1.24 espie 219: Lst_Destroy(&gn->iParents, NOFREE);
220: Lst_Destroy(&gn->cohorts, NOFREE);
221: Lst_Destroy(&gn->parents, NOFREE);
222: Lst_Destroy(&gn->children, NOFREE);
223: Lst_Destroy(&gn->successors, NOFREE);
224: Lst_Destroy(&gn->preds, NOFREE);
1.25 espie 225: SymTable_Destroy(&gn->context);
1.24 espie 226: Lst_Destroy(&gn->commands, NOFREE);
1.18 espie 227: free(gn);
1.1 deraadt 228: }
1.10 espie 229: #endif
1.1 deraadt 230:
231:
232: /*-
233: *-----------------------------------------------------------------------
234: * Targ_FindNode --
235: * Find a node in the list using the given name for matching
236: *
237: * Results:
1.12 espie 238: * The node in the list if it was. If it wasn't, return NULL of
1.1 deraadt 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 *
1.27 espie 247: Targ_FindNode(name, flags)
248: const char *name; /* the name to find */
249: int flags; /* flags governing events when target not
1.1 deraadt 250: * found */
251: {
1.27 espie 252: const char *end = NULL;
253: GNode *gn; /* node in that element */
254: unsigned int slot;
255:
1.30 ! espie 256: slot = ohash_qlookupi(&targets, name, &end);
1.27 espie 257:
1.30 ! espie 258: gn = ohash_find(&targets, slot);
1.27 espie 259:
260: if (gn == NULL && (flags & TARG_CREATE)) {
261: gn = Targ_NewGN(name, end);
1.30 ! espie 262: ohash_insert(&targets, slot, gn);
1.1 deraadt 263: }
264:
1.27 espie 265: return gn;
1.1 deraadt 266: }
267:
268: /*-
269: *-----------------------------------------------------------------------
270: * Targ_FindList --
1.5 millert 271: * Make a complete list of GNodes from the given list of names
1.1 deraadt 272: *
1.20 espie 273: * Side Effects:
274: * Nodes will be created for all names which do not yet have graph
275: * nodes.
1.1 deraadt 276: *
1.20 espie 277: * A complete list of graph nodes corresponding to all instances of
278: * all names is added to nodes.
1.1 deraadt 279: * -----------------------------------------------------------------------
280: */
1.20 espie 281: void
282: Targ_FindList(nodes, names)
283: Lst nodes; /* result list */
284: Lst names; /* list of names to find */
1.1 deraadt 285: {
1.20 espie 286: LstNode ln; /* name list element */
287: GNode *gn; /* node in tLn */
288: char *name;
1.1 deraadt 289:
1.22 espie 290: for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
1.1 deraadt 291: name = (char *)Lst_Datum(ln);
1.20 espie 292: gn = Targ_FindNode(name, TARG_CREATE);
293: /*
294: * Note: Lst_AtEnd must come before the Lst_Concat so the nodes
295: * are added to the list in the order in which they were
296: * encountered in the makefile.
297: */
298: Lst_AtEnd(nodes, gn);
299: if (gn->type & OP_DOUBLEDEP)
1.21 espie 300: Lst_Concat(nodes, &gn->cohorts);
1.1 deraadt 301: }
302: }
303:
304: /*-
305: *-----------------------------------------------------------------------
306: * Targ_Ignore --
307: * Return true if should ignore errors when creating gn
308: *-----------------------------------------------------------------------
309: */
310: Boolean
1.27 espie 311: Targ_Ignore(gn)
1.1 deraadt 312: GNode *gn; /* node to check for */
313: {
1.27 espie 314: if (ignoreErrors || gn->type & OP_IGNORE)
315: return TRUE;
316: else
317: return FALSE;
1.1 deraadt 318: }
319:
320: /*-
321: *-----------------------------------------------------------------------
322: * Targ_Silent --
323: * Return true if be silent when creating gn
324: *-----------------------------------------------------------------------
325: */
326: Boolean
1.27 espie 327: Targ_Silent(gn)
1.1 deraadt 328: GNode *gn; /* node to check for */
329: {
1.27 espie 330: if (beSilent || gn->type & OP_SILENT)
331: return TRUE;
332: else
333: return FALSE;
1.1 deraadt 334: }
335:
336: /*-
337: *-----------------------------------------------------------------------
338: * Targ_Precious --
339: * See if the given target is precious
340: *-----------------------------------------------------------------------
341: */
342: Boolean
343: Targ_Precious (gn)
344: GNode *gn; /* the node to check */
345: {
1.27 espie 346: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
347: return TRUE;
348: else
349: return FALSE;
1.1 deraadt 350: }
351:
352: /******************* DEBUG INFO PRINTING ****************/
353:
354: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
1.5 millert 355: /*-
1.1 deraadt 356: *-----------------------------------------------------------------------
357: * Targ_SetMain --
358: * Set our idea of the main target we'll be creating. Used for
359: * debugging output.
360: *
361: * Side Effects:
362: * "mainTarg" is set to the main target's node.
363: *-----------------------------------------------------------------------
364: */
365: void
1.27 espie 366: Targ_SetMain(gn)
1.1 deraadt 367: GNode *gn; /* The main target we'll create */
368: {
369: mainTarg = gn;
370: }
371:
1.17 espie 372: static void
373: TargPrintName(gnp)
1.18 espie 374: void *gnp;
1.1 deraadt 375: {
1.17 espie 376: GNode *gn = (GNode *)gnp;
377:
378: printf("%s ", gn->name);
1.1 deraadt 379: }
380:
381:
1.17 espie 382: void
383: Targ_PrintCmd(cmd)
1.18 espie 384: void *cmd;
1.1 deraadt 385: {
1.17 espie 386: printf("\t%s\n", (char *)cmd);
1.1 deraadt 387: }
388:
389: /*-
390: *-----------------------------------------------------------------------
391: * Targ_FmtTime --
392: * Format a modification time in some reasonable way and return it.
393: *
394: * Results:
395: * The time reformatted.
396: *
397: * Side Effects:
398: * The time is placed in a static area, so it is overwritten
399: * with each call.
400: *
401: *-----------------------------------------------------------------------
402: */
403: char *
1.27 espie 404: Targ_FmtTime(time)
1.29 espie 405: TIMESTAMP time;
1.1 deraadt 406: {
407: struct tm *parts;
1.27 espie 408: static char buf[128];
1.29 espie 409: time_t t;
1.1 deraadt 410:
1.29 espie 411: t = timestamp2time_t(time);
412:
413: parts = localtime(&t);
1.8 deraadt 414: strftime(buf, sizeof buf, "%k:%M:%S %b %d, %Y", parts);
415: buf[sizeof(buf) - 1] = '\0';
1.1 deraadt 416: return(buf);
417: }
1.5 millert 418:
1.1 deraadt 419: /*-
420: *-----------------------------------------------------------------------
421: * Targ_PrintType --
422: * Print out a type field giving only those attributes the user can
423: * set.
424: *-----------------------------------------------------------------------
425: */
426: void
1.27 espie 427: Targ_PrintType(type)
428: int type;
1.1 deraadt 429: {
1.27 espie 430: int tbit;
1.5 millert 431:
1.1 deraadt 432: #ifdef __STDC__
433: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break
434: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break
435: #else
436: #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break
437: #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break
438: #endif /* __STDC__ */
439:
440: type &= ~OP_OPMASK;
441:
442: while (type) {
443: tbit = 1 << (ffs(type) - 1);
444: type &= ~tbit;
445:
446: switch(tbit) {
447: PRINTBIT(OPTIONAL);
448: PRINTBIT(USE);
449: PRINTBIT(EXEC);
450: PRINTBIT(IGNORE);
451: PRINTBIT(PRECIOUS);
452: PRINTBIT(SILENT);
453: PRINTBIT(MAKE);
454: PRINTBIT(JOIN);
455: PRINTBIT(INVISIBLE);
456: PRINTBIT(NOTMAIN);
457: PRINTDBIT(LIB);
458: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
459: case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;
460: PRINTDBIT(ARCHV);
461: }
462: }
463: }
464:
465: /*-
466: *-----------------------------------------------------------------------
467: * TargPrintNode --
468: * print the contents of a node
469: *-----------------------------------------------------------------------
470: */
1.17 espie 471: static void
1.27 espie 472: TargPrintNode(gn, pass)
473: GNode *gn;
474: int pass;
1.1 deraadt 475: {
476: if (!OP_NOP(gn->type)) {
477: printf("#\n");
1.17 espie 478: if (gn == mainTarg)
1.1 deraadt 479: printf("# *** MAIN TARGET ***\n");
480: if (pass == 2) {
1.17 espie 481: if (gn->unmade)
1.1 deraadt 482: printf("# %d unmade children\n", gn->unmade);
1.17 espie 483: else
1.1 deraadt 484: printf("# No unmade children\n");
485: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
1.29 espie 486: if (!is_out_of_date(gn->mtime))
1.1 deraadt 487: printf("# last modified %s: %s\n",
488: Targ_FmtTime(gn->mtime),
489: (gn->made == UNMADE ? "unmade" :
490: (gn->made == MADE ? "made" :
491: (gn->made == UPTODATE ? "up-to-date" :
492: "error when made"))));
1.17 espie 493: else if (gn->made != UNMADE)
1.1 deraadt 494: printf("# non-existent (maybe): %s\n",
495: (gn->made == MADE ? "made" :
496: (gn->made == UPTODATE ? "up-to-date" :
497: (gn->made == ERROR ? "error when made" :
498: "aborted"))));
1.17 espie 499: else
1.1 deraadt 500: printf("# unmade\n");
501: }
1.19 espie 502: if (!Lst_IsEmpty(&gn->iParents)) {
1.1 deraadt 503: printf("# implicit parents: ");
1.19 espie 504: Lst_Every(&gn->iParents, TargPrintName);
1.17 espie 505: fputc('\n', stdout);
1.1 deraadt 506: }
507: }
1.19 espie 508: if (!Lst_IsEmpty(&gn->parents)) {
1.1 deraadt 509: printf("# parents: ");
1.19 espie 510: Lst_Every(&gn->parents, TargPrintName);
1.1 deraadt 511: fputc ('\n', stdout);
512: }
1.5 millert 513:
1.1 deraadt 514: printf("%-16s", gn->name);
515: switch (gn->type & OP_OPMASK) {
516: case OP_DEPENDS:
517: printf(": "); break;
518: case OP_FORCE:
519: printf("! "); break;
520: case OP_DOUBLEDEP:
521: printf(":: "); break;
522: }
1.17 espie 523: Targ_PrintType(gn->type);
1.19 espie 524: Lst_Every(&gn->children, TargPrintName);
1.17 espie 525: fputc('\n', stdout);
1.19 espie 526: Lst_Every(&gn->commands, Targ_PrintCmd);
1.1 deraadt 527: printf("\n\n");
1.27 espie 528: if (gn->type & OP_DOUBLEDEP) {
529: LstNode ln;
530:
531: for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
532: TargPrintNode((GNode *)Lst_Datum(ln), pass);
533: }
1.1 deraadt 534: }
535: }
536:
537: /*-
538: *-----------------------------------------------------------------------
539: * TargPrintOnlySrc --
540: * Print only those targets that are just a source.
541: *-----------------------------------------------------------------------
542: */
1.17 espie 543: static void
1.27 espie 544: TargPrintOnlySrc(gn)
545: GNode *gn;
1.1 deraadt 546: {
547: if (OP_NOP(gn->type))
548: printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);
549: }
550:
551: /*-
552: *-----------------------------------------------------------------------
553: * Targ_PrintGraph --
1.27 espie 554: * print the entire graph.
1.1 deraadt 555: *-----------------------------------------------------------------------
556: */
557: void
1.27 espie 558: Targ_PrintGraph(pass)
559: int pass; /* Which pass this is. 1 => no processing
560: * 2 => processing done */
1.1 deraadt 561: {
1.27 espie 562: GNode *gn;
563: unsigned int i;
564:
1.1 deraadt 565: printf("#*** Input graph:\n");
1.30 ! espie 566: for (gn = ohash_first(&targets, &i); gn != NULL;
! 567: gn = ohash_next(&targets, &i))
1.27 espie 568: TargPrintNode(gn, pass);
1.1 deraadt 569: printf("\n\n");
570: printf("#\n# Files that are only sources:\n");
1.30 ! espie 571: for (gn = ohash_first(&targets, &i); gn != NULL;
! 572: gn = ohash_next(&targets, &i))
1.27 espie 573: TargPrintOnlySrc(gn);
1.1 deraadt 574: printf("#*** Global Variables:\n");
1.23 espie 575: Var_Dump(VAR_GLOBAL);
1.1 deraadt 576: printf("#*** Command-line Variables:\n");
1.23 espie 577: Var_Dump(VAR_CMD);
1.1 deraadt 578: printf("\n");
579: Dir_PrintDirectories();
580: printf("\n");
581: Suff_PrintAll();
582: }