Annotation of src/usr.bin/make/targ.c, Revision 1.42
1.31 espie 1: /* $OpenPackages$ */
1.42 ! espie 2: /* $OpenBSD: targ.c,v 1.41 2007/09/16 12:09:36 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");
1.32 espie 558: #ifdef DEBUG_DIRECTORY_CACHE
1.42 ! espie 559: Dir_PrintDirectories();
! 560: printf("\n");
1.32 espie 561: #endif
1.42 ! espie 562: Suff_PrintAll();
1.1 deraadt 563: }