Annotation of src/usr.bin/make/targ.c, Revision 1.43
1.31 espie 1: /* $OpenPackages$ */
1.43 ! espie 2: /* $OpenBSD: targ.c,v 1.42 2007/09/16 14:09:18 espie Exp $ */
1.6 millert 3: /* $NetBSD: targ.c,v 1.11 1997/02/20 16:51:50 christos Exp $ */
1.1 deraadt 4:
5: /*
1.31 espie 6: * Copyright (c) 1999 Marc Espie.
7: *
8: * Extensive code changes for the OpenBSD project.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
23: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31: /*
1.5 millert 32: * Copyright (c) 1988, 1989, 1990, 1993
33: * The Regents of the University of California. All rights reserved.
1.1 deraadt 34: * Copyright (c) 1989 by Berkeley Softworks
35: * All rights reserved.
36: *
37: * This code is derived from software contributed to Berkeley by
38: * Adam de Boor.
39: *
40: * Redistribution and use in source and binary forms, with or without
41: * modification, are permitted provided that the following conditions
42: * are met:
43: * 1. Redistributions of source code must retain the above copyright
44: * notice, this list of conditions and the following disclaimer.
45: * 2. Redistributions in binary form must reproduce the above copyright
46: * notice, this list of conditions and the following disclaimer in the
47: * documentation and/or other materials provided with the distribution.
1.38 millert 48: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: */
64:
65: /*-
66: * targ.c --
1.27 espie 67: * Target nodes are kept into a hash table.
1.1 deraadt 68: *
69: * Interface:
1.31 espie 70: * Targ_Init Initialization procedure.
1.1 deraadt 71: *
1.31 espie 72: * Targ_End Cleanup the module
1.1 deraadt 73: *
1.31 espie 74: * Targ_NewGN Create a new GNode for the passed target
75: * (string). The node is *not* placed in the
76: * hash table, though all its fields are
77: * initialized.
1.1 deraadt 78: *
1.31 espie 79: * Targ_FindNode Find the node for a given target, creating
80: * and storing it if it doesn't exist and the
81: * flags are right (TARG_CREATE)
1.1 deraadt 82: *
1.31 espie 83: * Targ_FindList Given a list of names, find nodes for all
84: * of them, creating nodes if needed.
1.1 deraadt 85: *
1.32 espie 86: * Targ_Ignore Return true if errors should be ignored when
1.31 espie 87: * creating the given target.
1.1 deraadt 88: *
1.32 espie 89: * Targ_Silent Return true if we should be silent when
1.31 espie 90: * creating the given target.
1.1 deraadt 91: *
1.32 espie 92: * Targ_Precious Return true if the target is precious and
1.31 espie 93: * should not be removed if we are interrupted.
1.1 deraadt 94: *
95: * Debugging:
1.31 espie 96: * Targ_PrintGraph Print out the entire graphm all variables
97: * and statistics for the directory cache. Should
98: * print something for suffixes, too, but...
1.1 deraadt 99: */
100:
1.34 espie 101: #include <limits.h>
1.32 espie 102: #include <stddef.h>
103: #include <stdio.h>
1.40 espie 104: #include <stdint.h>
1.33 espie 105: #include <string.h>
1.32 espie 106: #include "config.h"
107: #include "defines.h"
108: #include "ohash.h"
109: #include "stats.h"
110: #include "suff.h"
111: #include "var.h"
112: #include "targ.h"
113: #include "memory.h"
114: #include "gnode.h"
115: #include "extern.h"
116: #include "timestamp.h"
117: #include "lst.h"
1.37 espie 118: #ifdef CLEANUP
119: #include <stdlib.h>
120: #endif
1.31 espie 121:
122: static struct ohash targets; /* a hash table of same */
123: static struct ohash_info gnode_info = {
124: offsetof(GNode, name),
1.42 espie 125: NULL, hash_alloc, hash_free, element_alloc
126: };
1.1 deraadt 127:
1.31 espie 128: static void TargPrintOnlySrc(GNode *);
129: static void TargPrintName(void *);
130: static void TargPrintNode(GNode *, int);
1.10 espie 131: #ifdef CLEANUP
1.37 espie 132: static LIST allTargets;
1.31 espie 133: static void TargFreeGN(void *);
1.10 espie 134: #endif
1.1 deraadt 135:
136: /*-
137: *-----------------------------------------------------------------------
138: * Targ_Init --
139: * Initialize this module
140: *
1.31 espie 141: * Side Effects:
1.27 espie 142: * The targets hash table is initialized
1.1 deraadt 143: *-----------------------------------------------------------------------
144: */
145: void
1.39 espie 146: Targ_Init(void)
1.1 deraadt 147: {
1.42 espie 148: /* A small make file already creates 200 targets. */
149: ohash_init(&targets, 10, &gnode_info);
1.37 espie 150: #ifdef CLEANUP
1.42 espie 151: Lst_Init(&allTargets);
1.37 espie 152: #endif
1.1 deraadt 153: }
154:
155: /*-
156: *-----------------------------------------------------------------------
157: * Targ_End --
158: * Finalize this module
159: *
160: * Side Effects:
161: * All lists and gnodes are cleared
162: *-----------------------------------------------------------------------
163: */
1.32 espie 164: #ifdef CLEANUP
1.1 deraadt 165: void
1.39 espie 166: Targ_End(void)
1.1 deraadt 167: {
1.42 espie 168: Lst_Every(&allTargets, TargFreeGN);
169: ohash_delete(&targets);
1.32 espie 170: }
1.10 espie 171: #endif
1.1 deraadt 172:
173: /*-
174: *-----------------------------------------------------------------------
1.32 espie 175: * Targ_NewGNi --
1.1 deraadt 176: * Create and initialize a new graph node
177: *
178: * Results:
179: * An initialized graph node with the name field filled with a copy
180: * of the passed name
181: *
1.37 espie 182: * Side effect:
183: * add targets to list of all targets if CLEANUP
1.1 deraadt 184: *-----------------------------------------------------------------------
185: */
186: GNode *
1.39 espie 187: Targ_NewGNi(const char *name, /* the name to stick in the new node */
188: const char *ename)
1.1 deraadt 189: {
1.42 espie 190: GNode *gn;
1.1 deraadt 191:
1.42 espie 192: gn = ohash_create_entry(&gnode_info, name, &ename);
193: gn->path = NULL;
194: if (name[0] == '-' && name[1] == 'l') {
195: gn->type = OP_LIB;
196: } else {
197: gn->type = 0;
198: }
199: gn->unmade = 0;
200: gn->make = false;
201: gn->made = UNMADE;
202: gn->childMade = false;
203: gn->order = 0;
204: ts_set_out_of_date(gn->mtime);
205: ts_set_out_of_date(gn->cmtime);
206: Lst_Init(&gn->iParents);
207: Lst_Init(&gn->cohorts);
208: Lst_Init(&gn->parents);
209: Lst_Init(&gn->children);
210: Lst_Init(&gn->successors);
211: Lst_Init(&gn->preds);
212: SymTable_Init(&gn->context);
213: gn->lineno = 0;
214: gn->fname = NULL;
215: Lst_Init(&gn->commands);
216: gn->suffix = NULL;
1.1 deraadt 217:
1.31 espie 218: #ifdef STATS_GN_CREATION
1.42 espie 219: STAT_GN_COUNT++;
1.10 espie 220: #endif
1.1 deraadt 221:
1.37 espie 222: #ifdef CLEANUP
1.42 espie 223: Lst_AtEnd(&allTargets, gn);
1.37 espie 224: #endif
1.42 espie 225: return gn;
1.1 deraadt 226: }
227:
1.10 espie 228: #ifdef CLEANUP
1.1 deraadt 229: /*-
230: *-----------------------------------------------------------------------
231: * TargFreeGN --
232: * Destroy a GNode
233: *-----------------------------------------------------------------------
234: */
235: static void
1.39 espie 236: TargFreeGN(void *gnp)
1.1 deraadt 237: {
1.42 espie 238: GNode *gn = (GNode *)gnp;
1.1 deraadt 239:
1.42 espie 240: efree(gn->path);
241: Lst_Destroy(&gn->iParents, NOFREE);
242: Lst_Destroy(&gn->cohorts, NOFREE);
243: Lst_Destroy(&gn->parents, NOFREE);
244: Lst_Destroy(&gn->children, NOFREE);
245: Lst_Destroy(&gn->successors, NOFREE);
246: Lst_Destroy(&gn->preds, NOFREE);
247: Lst_Destroy(&gn->commands, NOFREE);
248: SymTable_Destroy(&gn->context);
249: free(gn);
1.1 deraadt 250: }
1.10 espie 251: #endif
1.1 deraadt 252:
253:
254: /*-
255: *-----------------------------------------------------------------------
1.32 espie 256: * Targ_FindNodei --
1.1 deraadt 257: * Find a node in the list using the given name for matching
258: *
259: * Results:
1.31 espie 260: * The node in the list if it was. If it wasn't, return NULL if
1.1 deraadt 261: * flags was TARG_NOCREATE or the newly created and initialized node
1.31 espie 262: * if flags was TARG_CREATE
1.1 deraadt 263: *
264: * Side Effects:
265: * Sometimes a node is created and added to the list
266: *-----------------------------------------------------------------------
267: */
268: GNode *
1.39 espie 269: Targ_FindNodei(const char *name, const char *ename,
270: int flags) /* flags governing events when target not
1.1 deraadt 271: * found */
272: {
1.42 espie 273: GNode *gn; /* node in that element */
274: unsigned int slot;
1.27 espie 275:
1.42 espie 276: slot = ohash_qlookupi(&targets, name, &ename);
1.27 espie 277:
1.42 espie 278: gn = ohash_find(&targets, slot);
1.31 espie 279:
1.42 espie 280: if (gn == NULL && (flags & TARG_CREATE)) {
281: gn = Targ_NewGNi(name, ename);
282: ohash_insert(&targets, slot, gn);
283: }
1.1 deraadt 284:
1.42 espie 285: return gn;
1.1 deraadt 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: *
1.20 espie 293: * Side Effects:
1.31 espie 294: * Nodes will be created for all names in names which do not yet have graph
1.20 espie 295: * nodes.
1.1 deraadt 296: *
1.31 espie 297: * A complete list of graph nodes corresponding to all instances of all
298: * the names in names is added to nodes.
1.1 deraadt 299: * -----------------------------------------------------------------------
300: */
1.20 espie 301: void
1.39 espie 302: Targ_FindList(Lst nodes, /* result list */
303: Lst names) /* list of names to find */
1.1 deraadt 304: {
1.42 espie 305: LstNode ln; /* name list element */
306: GNode *gn; /* node in tLn */
307: char *name;
308:
309: for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
310: name = (char *)Lst_Datum(ln);
311: gn = Targ_FindNode(name, TARG_CREATE);
312: /* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
313: * are added to the list in the order in which they were
314: * encountered in the makefile. */
315: Lst_AtEnd(nodes, gn);
316: if (gn->type & OP_DOUBLEDEP)
317: Lst_Concat(nodes, &gn->cohorts);
318: }
1.1 deraadt 319: }
320:
321: /*-
322: *-----------------------------------------------------------------------
1.31 espie 323: * Targ_Ignore --
1.1 deraadt 324: * Return true if should ignore errors when creating gn
325: *-----------------------------------------------------------------------
326: */
1.32 espie 327: bool
1.39 espie 328: Targ_Ignore(GNode *gn)
1.1 deraadt 329: {
1.42 espie 330: if (ignoreErrors || gn->type & OP_IGNORE)
331: return true;
332: else
333: return false;
1.1 deraadt 334: }
335:
336: /*-
337: *-----------------------------------------------------------------------
1.31 espie 338: * Targ_Silent --
1.1 deraadt 339: * Return true if be silent when creating gn
340: *-----------------------------------------------------------------------
341: */
1.32 espie 342: bool
1.39 espie 343: Targ_Silent(GNode *gn)
1.1 deraadt 344: {
1.42 espie 345: if (beSilent || gn->type & OP_SILENT)
346: return true;
347: else
348: return false;
1.1 deraadt 349: }
350:
351: /*-
352: *-----------------------------------------------------------------------
353: * Targ_Precious --
354: * See if the given target is precious
355: *-----------------------------------------------------------------------
356: */
1.32 espie 357: bool
1.39 espie 358: Targ_Precious(GNode *gn)
1.1 deraadt 359: {
1.42 espie 360: if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP)))
361: return true;
362: else
363: return false;
1.1 deraadt 364: }
365:
366: /******************* DEBUG INFO PRINTING ****************/
367:
1.42 espie 368: static GNode *mainTarg; /* the main target, as set by Targ_SetMain */
1.5 millert 369: /*-
1.1 deraadt 370: *-----------------------------------------------------------------------
371: * Targ_SetMain --
372: * Set our idea of the main target we'll be creating. Used for
373: * debugging output.
374: *
375: * Side Effects:
376: * "mainTarg" is set to the main target's node.
377: *-----------------------------------------------------------------------
378: */
379: void
1.39 espie 380: Targ_SetMain(GNode *gn)
1.1 deraadt 381: {
1.42 espie 382: mainTarg = gn;
1.1 deraadt 383: }
384:
1.17 espie 385: static void
1.39 espie 386: TargPrintName(void *gnp)
1.1 deraadt 387: {
1.42 espie 388: GNode *gn = (GNode *)gnp;
389: printf("%s ", gn->name);
1.1 deraadt 390: }
391:
392:
1.17 espie 393: void
1.39 espie 394: Targ_PrintCmd(void *cmd)
1.1 deraadt 395: {
1.42 espie 396: printf("\t%s\n", (char *)cmd);
1.1 deraadt 397: }
398:
399: /*-
400: *-----------------------------------------------------------------------
401: * Targ_PrintType --
402: * Print out a type field giving only those attributes the user can
403: * set.
404: *-----------------------------------------------------------------------
405: */
406: void
1.39 espie 407: Targ_PrintType(int type)
1.1 deraadt 408: {
1.42 espie 409: int tbit;
1.5 millert 410:
1.42 espie 411: #define PRINTBIT(attr) case CONCAT(OP_,attr): \
412: printf("." #attr " "); \
413: break
414: #define PRINTDBIT(attr) case CONCAT(OP_,attr): \
415: if (DEBUG(TARG)) \
416: printf("." #attr " "); \
417: break
418:
419: type &= ~OP_OPMASK;
420:
421: while (type) {
422: tbit = 1 << (ffs(type) - 1);
423: type &= ~tbit;
424:
425: switch (tbit) {
426: PRINTBIT(OPTIONAL);
427: PRINTBIT(USE);
428: PRINTBIT(EXEC);
429: PRINTBIT(IGNORE);
430: PRINTBIT(PRECIOUS);
431: PRINTBIT(SILENT);
432: PRINTBIT(MAKE);
433: PRINTBIT(JOIN);
434: PRINTBIT(INVISIBLE);
435: PRINTBIT(NOTMAIN);
436: PRINTDBIT(LIB);
437: /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */
438: case OP_MEMBER:
439: if (DEBUG(TARG))
440: printf(".MEMBER ");
441: break;
442: PRINTDBIT(ARCHV);
443: }
1.1 deraadt 444: }
445: }
446:
447: /*-
448: *-----------------------------------------------------------------------
449: * TargPrintNode --
450: * print the contents of a node
451: *-----------------------------------------------------------------------
452: */
1.17 espie 453: static void
1.39 espie 454: TargPrintNode(GNode *gn, int pass)
1.1 deraadt 455: {
1.42 espie 456: if (OP_NOP(gn->type))
457: return;
1.1 deraadt 458: printf("#\n");
1.31 espie 459: if (gn == mainTarg) {
1.42 espie 460: printf("# *** MAIN TARGET ***\n");
1.31 espie 461: }
1.1 deraadt 462: if (pass == 2) {
1.42 espie 463: if (gn->unmade) {
464: printf("# %d unmade children\n", gn->unmade);
1.31 espie 465: } else {
1.42 espie 466: printf("# No unmade children\n");
467: }
468: if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
469: if (!is_out_of_date(gn->mtime)) {
470: printf("# last modified %s: %s\n",
471: time_to_string(gn->mtime),
472: (gn->made == UNMADE ? "unmade" :
473: (gn->made == MADE ? "made" :
474: (gn->made == UPTODATE ? "up-to-date" :
475: "error when made"))));
476: } else if (gn->made != UNMADE) {
477: printf("# non-existent (maybe): %s\n",
478: (gn->made == MADE ? "made" :
479: (gn->made == UPTODATE ? "up-to-date" :
480: (gn->made == ERROR ? "error when made" :
481: "aborted"))));
482: } else {
483: printf("# unmade\n");
484: }
485: }
486: if (!Lst_IsEmpty(&gn->iParents)) {
487: printf("# implicit parents: ");
488: Lst_Every(&gn->iParents, TargPrintName);
489: fputc('\n', stdout);
1.31 espie 490: }
1.1 deraadt 491: }
1.19 espie 492: if (!Lst_IsEmpty(&gn->parents)) {
1.42 espie 493: printf("# parents: ");
494: Lst_Every(&gn->parents, TargPrintName);
495: fputc('\n', stdout);
1.1 deraadt 496: }
1.5 millert 497:
1.1 deraadt 498: printf("%-16s", gn->name);
499: switch (gn->type & OP_OPMASK) {
1.42 espie 500: case OP_DEPENDS:
1.1 deraadt 501: printf(": "); break;
1.42 espie 502: case OP_FORCE:
1.1 deraadt 503: printf("! "); break;
1.42 espie 504: case OP_DOUBLEDEP:
1.1 deraadt 505: printf(":: "); break;
506: }
1.17 espie 507: Targ_PrintType(gn->type);
1.19 espie 508: Lst_Every(&gn->children, TargPrintName);
1.17 espie 509: fputc('\n', stdout);
1.19 espie 510: Lst_Every(&gn->commands, Targ_PrintCmd);
1.1 deraadt 511: printf("\n\n");
1.27 espie 512: if (gn->type & OP_DOUBLEDEP) {
1.42 espie 513: LstNode ln;
1.31 espie 514:
1.42 espie 515: for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
516: TargPrintNode((GNode *)Lst_Datum(ln), pass);
1.27 espie 517: }
1.1 deraadt 518: }
519:
520: /*-
521: *-----------------------------------------------------------------------
522: * TargPrintOnlySrc --
1.31 espie 523: * Print targets that are just a source.
1.1 deraadt 524: *-----------------------------------------------------------------------
525: */
1.17 espie 526: static void
1.39 espie 527: TargPrintOnlySrc(GNode *gn)
1.1 deraadt 528: {
1.42 espie 529: if (OP_NOP(gn->type))
530: printf("#\t%s [%s]\n", gn->name,
531: gn->path != NULL ? gn->path : gn->name);
1.1 deraadt 532: }
533:
534: /*-
535: *-----------------------------------------------------------------------
536: * Targ_PrintGraph --
1.27 espie 537: * print the entire graph.
1.1 deraadt 538: *-----------------------------------------------------------------------
539: */
540: void
1.39 espie 541: Targ_PrintGraph(int pass) /* Which pass this is. 1 => no processing
1.31 espie 542: * 2 => processing done */
1.1 deraadt 543: {
1.42 espie 544: GNode *gn;
545: unsigned int i;
1.27 espie 546:
1.42 espie 547: printf("#*** Input graph:\n");
548: for (gn = ohash_first(&targets, &i); gn != NULL;
549: gn = ohash_next(&targets, &i))
550: TargPrintNode(gn, pass);
551: printf("\n\n");
552: printf("#\n# Files that are only sources:\n");
553: for (gn = ohash_first(&targets, &i); gn != NULL;
554: gn = ohash_next(&targets, &i))
555: TargPrintOnlySrc(gn);
556: Var_Dump();
557: printf("\n");
558: Suff_PrintAll();
1.1 deraadt 559: }