diff options
author | Simon J. Gerraty <sjg@FreeBSD.org> | 2020-11-07 19:39:21 +0000 |
---|---|---|
committer | Simon J. Gerraty <sjg@FreeBSD.org> | 2020-11-07 19:39:21 +0000 |
commit | 302da1a3d35c15cb29d76e0a939f8bcb13f7ad80 (patch) | |
tree | c2146dca82d530521c4d2cc46a95c26964311a2c /main.c | |
parent | 6bbc783f48498b808e19db4441299dc7d85a278b (diff) | |
download | src-302da1a3d35c15cb29d76e0a939f8bcb13f7ad80.tar.gz src-302da1a3d35c15cb29d76e0a939f8bcb13f7ad80.zip |
Import bmake-20201101vendor/NetBSD/bmake/20201101
Lots of new unit-tests increase code coverage.
Lots of refactoring, cleanup and simlpification to reduce
code size.
Fixes for Bug 223564 and 245807
Updates to dirdeps.mk and meta2deps.py
Notes
Notes:
svn path=/vendor/NetBSD/bmake/dist/; revision=367460
svn path=/vendor/NetBSD/bmake/20201101/; revision=367461; tag=vendor/NetBSD/bmake/20201101
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 1859 |
1 files changed, 961 insertions, 898 deletions
@@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $ */ +/* $NetBSD: main.c,v 1.421 2020/11/01 00:24:57 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -68,24 +68,6 @@ * SUCH DAMAGE. */ -#ifndef MAKE_NATIVE -static char rcsid[] = "$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"; -#else -#include <sys/cdefs.h> -#ifndef lint -__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ - The Regents of the University of California. All rights reserved."); -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; -#else -__RCSID("$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"); -#endif -#endif /* not lint */ -#endif - /*- * main.c -- * The main file for this entire program. Exit routines etc @@ -124,69 +106,47 @@ __RCSID("$NetBSD: main.c,v 1.331 2020/08/30 19:56:02 rillig Exp $"); #include <sys/utsname.h> #include "wait.h" -#include <ctype.h> #include <errno.h> #include <signal.h> #include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> #include <time.h> #include "make.h" -#include "hash.h" #include "dir.h" #include "job.h" #include "pathnames.h" #include "trace.h" -#ifdef USE_IOVEC -#include <sys/uio.h> +/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ +MAKE_RCSID("$NetBSD: main.c,v 1.421 2020/11/01 00:24:57 rillig Exp $"); +#if defined(MAKE_NATIVE) && !defined(lint) +__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " + "The Regents of the University of California. " + "All rights reserved."); #endif #ifndef DEFMAXLOCAL #define DEFMAXLOCAL DEFMAXJOBS -#endif /* DEFMAXLOCAL */ +#endif #ifndef __arraycount # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) #endif -Lst create; /* Targets to be made */ +CmdOpts opts; time_t now; /* Time at start of make */ GNode *DEFAULT; /* .DEFAULT node */ Boolean allPrecious; /* .PRECIOUS given on line by itself */ Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ -static Boolean noBuiltins; /* -r flag */ -static Lst makefiles; /* ordered list of makefiles to read */ -static int printVars; /* -[vV] argument */ -#define COMPAT_VARS 1 -#define EXPAND_VARS 2 -static Lst variables; /* list of variables to print - * (for -v and -V) */ -int maxJobs; /* -j argument */ static int maxJobTokens; /* -j argument */ -Boolean compatMake; /* -B argument */ -int debug; /* -d argument */ -Boolean debugVflag; /* -dV */ -Boolean noExecute; /* -n flag */ -Boolean noRecursiveExecute; /* -N flag */ -Boolean keepgoing; /* -k flag */ -Boolean queryFlag; /* -q flag */ -Boolean touchFlag; /* -t flag */ -Boolean enterFlag; /* -w flag */ Boolean enterFlagObj; /* -w and objdir != srcdir */ -Boolean ignoreErrors; /* -i flag */ -Boolean beSilent; /* -s flag */ + Boolean oldVars; /* variable substitution style */ -Boolean checkEnvFirst; /* -e flag */ -Boolean parseWarnFatal; /* -W flag */ static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ -Boolean varNoExportEnv; /* -X flag */ Boolean doing_depend; /* Set while reading .depend */ static Boolean jobsRunning; /* TRUE if the jobs might be running */ static const char * tracefile; -static void MainParseArgs(int, char **); static int ReadMakefile(const char *); static void usage(void) MAKE_ATTR_DEAD; static void purge_cached_realpaths(void); @@ -199,9 +159,8 @@ char *makeDependfile; pid_t myPid; int makelevel; -FILE *debug_file; - Boolean forceJobs = FALSE; +static int errors = 0; /* * On some systems MACHINE is defined as something other than @@ -212,7 +171,7 @@ Boolean forceJobs = FALSE; # define MACHINE FORCE_MACHINE #endif -extern Lst parseIncPath; +extern SearchPath *parseIncPath; /* * For compatibility with the POSIX version of MAKEFLAGS that includes @@ -229,7 +188,7 @@ explode(const char *flags) return NULL; for (f = flags; *f; f++) - if (!isalpha((unsigned char)*f)) + if (!ch_isalpha(*f)) break; if (*f) @@ -247,118 +206,133 @@ explode(const char *flags) } static void +parse_debug_option_F(const char *modules) +{ + const char *mode; + size_t len; + char *fname; + + if (opts.debug_file != stdout && opts.debug_file != stderr) + fclose(opts.debug_file); + + if (*modules == '+') { + modules++; + mode = "a"; + } else + mode = "w"; + + if (strcmp(modules, "stdout") == 0) { + opts.debug_file = stdout; + return; + } + if (strcmp(modules, "stderr") == 0) { + opts.debug_file = stderr; + return; + } + + len = strlen(modules); + fname = bmake_malloc(len + 20); + memcpy(fname, modules, len + 1); + + /* Let the filename be modified by the pid */ + if (strcmp(fname + len - 3, ".%d") == 0) + snprintf(fname + len - 2, 20, "%d", getpid()); + + opts.debug_file = fopen(fname, mode); + if (!opts.debug_file) { + fprintf(stderr, "Cannot open debug file %s\n", + fname); + usage(); + } + free(fname); +} + +static void parse_debug_options(const char *argvalue) { const char *modules; - const char *mode; - char *fname; - int len; for (modules = argvalue; *modules; ++modules) { switch (*modules) { + case '0': /* undocumented, only intended for tests */ + opts.debug &= DEBUG_LINT; + break; case 'A': - debug = ~(0|DEBUG_LINT); + opts.debug = ~(0|DEBUG_LINT); break; case 'a': - debug |= DEBUG_ARCH; + opts.debug |= DEBUG_ARCH; break; case 'C': - debug |= DEBUG_CWD; + opts.debug |= DEBUG_CWD; break; case 'c': - debug |= DEBUG_COND; + opts.debug |= DEBUG_COND; break; case 'd': - debug |= DEBUG_DIR; + opts.debug |= DEBUG_DIR; break; case 'e': - debug |= DEBUG_ERROR; + opts.debug |= DEBUG_ERROR; break; case 'f': - debug |= DEBUG_FOR; + opts.debug |= DEBUG_FOR; break; case 'g': if (modules[1] == '1') { - debug |= DEBUG_GRAPH1; + opts.debug |= DEBUG_GRAPH1; ++modules; } else if (modules[1] == '2') { - debug |= DEBUG_GRAPH2; + opts.debug |= DEBUG_GRAPH2; ++modules; } else if (modules[1] == '3') { - debug |= DEBUG_GRAPH3; + opts.debug |= DEBUG_GRAPH3; ++modules; } break; case 'h': - debug |= DEBUG_HASH; + opts.debug |= DEBUG_HASH; break; case 'j': - debug |= DEBUG_JOB; + opts.debug |= DEBUG_JOB; break; case 'L': - debug |= DEBUG_LINT; + opts.debug |= DEBUG_LINT; break; case 'l': - debug |= DEBUG_LOUD; + opts.debug |= DEBUG_LOUD; break; case 'M': - debug |= DEBUG_META; + opts.debug |= DEBUG_META; break; case 'm': - debug |= DEBUG_MAKE; + opts.debug |= DEBUG_MAKE; break; case 'n': - debug |= DEBUG_SCRIPT; + opts.debug |= DEBUG_SCRIPT; break; case 'p': - debug |= DEBUG_PARSE; + opts.debug |= DEBUG_PARSE; break; case 's': - debug |= DEBUG_SUFF; + opts.debug |= DEBUG_SUFF; break; case 't': - debug |= DEBUG_TARG; + opts.debug |= DEBUG_TARG; break; case 'V': - debugVflag = TRUE; + opts.debugVflag = TRUE; break; case 'v': - debug |= DEBUG_VAR; + opts.debug |= DEBUG_VAR; break; case 'x': - debug |= DEBUG_SHELL; + opts.debug |= DEBUG_SHELL; break; case 'F': - if (debug_file != stdout && debug_file != stderr) - fclose(debug_file); - if (*++modules == '+') { - modules++; - mode = "a"; - } else - mode = "w"; - if (strcmp(modules, "stdout") == 0) { - debug_file = stdout; - goto debug_setbuf; - } - if (strcmp(modules, "stderr") == 0) { - debug_file = stderr; - goto debug_setbuf; - } - len = strlen(modules); - fname = bmake_malloc(len + 20); - memcpy(fname, modules, len + 1); - /* Let the filename be modified by the pid */ - if (strcmp(fname + len - 3, ".%d") == 0) - snprintf(fname + len - 2, 20, "%d", getpid()); - debug_file = fopen(fname, mode); - if (!debug_file) { - fprintf(stderr, "Cannot open debug file %s\n", - fname); - usage(); - } - free(fname); + parse_debug_option_F(modules + 1); goto debug_setbuf; default: (void)fprintf(stderr, @@ -372,8 +346,8 @@ debug_setbuf: * Make the debug_file unbuffered, and make * stdout line buffered (unless debugfile == stdout). */ - setvbuf(debug_file, NULL, _IONBF, 0); - if (debug_file != stdout) { + setvbuf(opts.debug_file, NULL, _IONBF, 0); + if (opts.debug_file != stdout) { setvbuf(stdout, NULL, _IOLBF, 0); } } @@ -401,48 +375,241 @@ is_relpath(const char *path) return FALSE; } -/*- - * MainParseArgs -- - * Parse a given argument vector. Called from main() and from - * Main_ParseArgLine() when the .MAKEFLAGS target is used. - * - * XXX: Deal with command line overriding .MAKEFLAGS in makefile +static void +MainParseArgChdir(const char *argvalue) +{ + struct stat sa, sb; + + if (chdir(argvalue) == -1) { + (void)fprintf(stderr, "%s: chdir %s: %s\n", + progname, argvalue, strerror(errno)); + exit(1); + } + if (getcwd(curdir, MAXPATHLEN) == NULL) { + (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); + exit(2); + } + if (!is_relpath(argvalue) && + stat(argvalue, &sa) != -1 && + stat(curdir, &sb) != -1 && + sa.st_ino == sb.st_ino && + sa.st_dev == sb.st_dev) + strncpy(curdir, argvalue, MAXPATHLEN); + ignorePWD = TRUE; +} + +static void +MainParseArgJobsInternal(const char *argvalue) +{ + if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { + (void)fprintf(stderr, + "%s: internal error -- J option malformed (%s)\n", + progname, argvalue); + usage(); + } + if ((fcntl(jp_0, F_GETFD, 0) < 0) || + (fcntl(jp_1, F_GETFD, 0) < 0)) { +#if 0 + (void)fprintf(stderr, + "%s: ###### warning -- J descriptors were closed!\n", + progname); + exit(2); +#endif + jp_0 = -1; + jp_1 = -1; + opts.compatMake = TRUE; + } else { + Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + } +} + +static void +MainParseArgJobs(const char *argvalue) +{ + char *p; + + forceJobs = TRUE; + opts.maxJobs = (int)strtol(argvalue, &p, 0); + if (*p != '\0' || opts.maxJobs < 1) { + (void)fprintf(stderr, + "%s: illegal argument to -j -- must be positive integer!\n", + progname); + exit(1); /* XXX: why not 2? */ + } + Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); + maxJobTokens = opts.maxJobs; +} + +static void +MainParseArgSysInc(const char *argvalue) +{ + /* look for magic parent directory search string */ + if (strncmp(".../", argvalue, 4) == 0) { + char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); + if (found_path == NULL) + return; + (void)Dir_AddDir(sysIncPath, found_path); + free(found_path); + } else { + (void)Dir_AddDir(sysIncPath, argvalue); + } + Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); +} + +static Boolean +MainParseArg(char c, const char *argvalue) +{ + switch (c) { + case '\0': + break; + case 'B': + opts.compatMake = TRUE; + Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); + Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); + break; + case 'C': + MainParseArgChdir(argvalue); + break; + case 'D': + if (argvalue[0] == '\0') return FALSE; + Var_Set(argvalue, "1", VAR_GLOBAL); + Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + break; + case 'I': + Parse_AddIncludeDir(argvalue); + Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + break; + case 'J': + MainParseArgJobsInternal(argvalue); + break; + case 'N': + opts.noExecute = TRUE; + opts.noRecursiveExecute = TRUE; + Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); + break; + case 'S': + opts.keepgoing = FALSE; + Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); + break; + case 'T': + tracefile = bmake_strdup(argvalue); + Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + break; + case 'V': + case 'v': + opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; + Lst_Append(opts.variables, bmake_strdup(argvalue)); + /* XXX: Why always -V? */ + Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + break; + case 'W': + opts.parseWarnFatal = TRUE; + break; + case 'X': + opts.varNoExportEnv = TRUE; + Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); + break; + case 'd': + /* If '-d-opts' don't pass to children */ + if (argvalue[0] == '-') + argvalue++; + else { + Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); + Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); + } + parse_debug_options(argvalue); + break; + case 'e': + opts.checkEnvFirst = TRUE; + Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); + break; + case 'f': + Lst_Append(opts.makefiles, bmake_strdup(argvalue)); + break; + case 'i': + opts.ignoreErrors = TRUE; + Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); + break; + case 'j': + MainParseArgJobs(argvalue); + break; + case 'k': + opts.keepgoing = TRUE; + Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); + break; + case 'm': + MainParseArgSysInc(argvalue); + break; + case 'n': + opts.noExecute = TRUE; + Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); + break; + case 'q': + opts.queryFlag = TRUE; + /* Kind of nonsensical, wot? */ + Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); + break; + case 'r': + opts.noBuiltins = TRUE; + Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); + break; + case 's': + opts.beSilent = TRUE; + Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); + break; + case 't': + opts.touchFlag = TRUE; + Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); + break; + case 'w': + opts.enterFlag = TRUE; + Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); + break; + default: + case '?': + usage(); + } + return TRUE; +} + +/* Parse the given arguments. Called from main() and from + * Main_ParseArgLine() when the .MAKEFLAGS target is used. * - * Results: - * None + * The arguments must be treated as read-only and will be freed after the + * call. * - * Side Effects: - * Various global and local flags will be set depending on the flags - * given - */ + * XXX: Deal with command line overriding .MAKEFLAGS in makefile */ static void MainParseArgs(int argc, char **argv) { - char *p; - char c = '?'; + char c; int arginc; char *argvalue; - const char *getopt_def; - struct stat sa, sb; char *optscan; Boolean inOption, dashDash = FALSE; - char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ -#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w" + const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; /* Can't actually use getopt(3) because rescanning is not portable */ - getopt_def = OPTFLAGS; rearg: inOption = FALSE; optscan = NULL; - while(argc > 1) { - char *getopt_spec; - if(!inOption) + while (argc > 1) { + const char *optspec; + if (!inOption) optscan = argv[1]; c = *optscan++; arginc = 0; - if(inOption) { - if(c == '\0') { + if (inOption) { + if (c == '\0') { ++argv; --argc; inOption = FALSE; @@ -455,13 +622,13 @@ rearg: c = *optscan++; } /* '-' found at some earlier point */ - getopt_spec = strchr(getopt_def, c); - if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { + optspec = strchr(optspecs, c); + if (c != '\0' && optspec != NULL && optspec[1] == ':') { /* -<something> found, and <something> should have an arg */ inOption = FALSE; arginc = 1; argvalue = optscan; - if(*argvalue == '\0') { + if (*argvalue == '\0') { if (argc < 3) goto noarg; argvalue = argv[2]; @@ -470,192 +637,17 @@ rearg: } else { argvalue = NULL; } - switch(c) { + switch (c) { case '\0': arginc = 1; inOption = FALSE; break; - case 'B': - compatMake = TRUE; - Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); - Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); - break; - case 'C': - if (chdir(argvalue) == -1) { - (void)fprintf(stderr, - "%s: chdir %s: %s\n", - progname, argvalue, - strerror(errno)); - exit(1); - } - if (getcwd(curdir, MAXPATHLEN) == NULL) { - (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); - exit(2); - } - if (!is_relpath(argvalue) && - stat(argvalue, &sa) != -1 && - stat(curdir, &sb) != -1 && - sa.st_ino == sb.st_ino && - sa.st_dev == sb.st_dev) - strncpy(curdir, argvalue, MAXPATHLEN); - ignorePWD = TRUE; - break; - case 'D': - if (argvalue == NULL || argvalue[0] == 0) goto noarg; - Var_Set(argvalue, "1", VAR_GLOBAL); - Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - break; - case 'I': - if (argvalue == NULL) goto noarg; - Parse_AddIncludeDir(argvalue); - Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - break; - case 'J': - if (argvalue == NULL) goto noarg; - if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { - (void)fprintf(stderr, - "%s: internal error -- J option malformed (%s)\n", - progname, argvalue); - usage(); - } - if ((fcntl(jp_0, F_GETFD, 0) < 0) || - (fcntl(jp_1, F_GETFD, 0) < 0)) { -#if 0 - (void)fprintf(stderr, - "%s: ###### warning -- J descriptors were closed!\n", - progname); - exit(2); -#endif - jp_0 = -1; - jp_1 = -1; - compatMake = TRUE; - } else { - Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - } - break; - case 'N': - noExecute = TRUE; - noRecursiveExecute = TRUE; - Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); - break; - case 'S': - keepgoing = FALSE; - Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); - break; - case 'T': - if (argvalue == NULL) goto noarg; - tracefile = bmake_strdup(argvalue); - Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - break; - case 'V': - case 'v': - if (argvalue == NULL) goto noarg; - printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; - Lst_Append(variables, argvalue); - Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - break; - case 'W': - parseWarnFatal = TRUE; - break; - case 'X': - varNoExportEnv = TRUE; - Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); - break; - case 'd': - if (argvalue == NULL) goto noarg; - /* If '-d-opts' don't pass to children */ - if (argvalue[0] == '-') - argvalue++; - else { - Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - } - parse_debug_options(argvalue); - break; - case 'e': - checkEnvFirst = TRUE; - Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); - break; - case 'f': - if (argvalue == NULL) goto noarg; - Lst_Append(makefiles, argvalue); - break; - case 'i': - ignoreErrors = TRUE; - Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); - break; - case 'j': - if (argvalue == NULL) goto noarg; - forceJobs = TRUE; - maxJobs = strtol(argvalue, &p, 0); - if (*p != '\0' || maxJobs < 1) { - (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", - progname); - exit(1); - } - Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); - maxJobTokens = maxJobs; - break; - case 'k': - keepgoing = TRUE; - Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); - break; - case 'm': - if (argvalue == NULL) goto noarg; - /* look for magic parent directory search string */ - if (strncmp(".../", argvalue, 4) == 0) { - if (!Dir_FindHereOrAbove(curdir, argvalue+4, - found_path, sizeof(found_path))) - break; /* nothing doing */ - (void)Dir_AddDir(sysIncPath, found_path); - } else { - (void)Dir_AddDir(sysIncPath, argvalue); - } - Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); - Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); - break; - case 'n': - noExecute = TRUE; - Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); - break; - case 'q': - queryFlag = TRUE; - /* Kind of nonsensical, wot? */ - Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); - break; - case 'r': - noBuiltins = TRUE; - Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); - break; - case 's': - beSilent = TRUE; - Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); - break; - case 't': - touchFlag = TRUE; - Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); - break; - case 'w': - enterFlag = TRUE; - Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); - break; case '-': dashDash = TRUE; break; default: - case '?': -#ifndef MAKE_NATIVE - fprintf(stderr, "getopt(%s) -> %d (%c)\n", - OPTFLAGS, c, c); -#endif - usage(); + if (!MainParseArg(c, argvalue)) + goto noarg; } argv += arginc; argc -= arginc; @@ -668,16 +660,18 @@ rearg: * perform them if so. Else take them to be targets and stuff them * on the end of the "create" list. */ - for (; argc > 1; ++argv, --argc) - if (Parse_IsVar(argv[1])) { - Parse_DoVar(argv[1], VAR_CMD); + for (; argc > 1; ++argv, --argc) { + VarAssign var; + if (Parse_IsVar(argv[1], &var)) { + Parse_DoVar(&var, VAR_CMDLINE); } else { if (!*argv[1]) Punt("illegal (null) argument."); if (*argv[1] == '-' && !dashDash) goto rearg; - Lst_Append(create, bmake_strdup(argv[1])); + Lst_Append(opts.create, bmake_strdup(argv[1])); } + } return; noarg: @@ -686,29 +680,15 @@ noarg: usage(); } -/*- - * Main_ParseArgLine -- - * Used by the parse module when a .MFLAGS or .MAKEFLAGS target - * is encountered and by main() when reading the .MAKEFLAGS envariable. - * Takes a line of arguments and breaks it into its - * component words and passes those words and the number of them to the - * MainParseArgs function. - * The line should have all its leading whitespace removed. - * - * Input: - * line Line to fracture +/* Break a line of arguments into words and parse them. * - * Results: - * None - * - * Side Effects: - * Only those that come from the various arguments. - */ + * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and + * by main() when reading the MAKEFLAGS environment variable. */ void Main_ParseArgLine(const char *line) { Words words; - char *p1; + void *p1; const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); char *buf; @@ -769,7 +749,9 @@ Main_SetObjdir(const char *fmt, ...) /* look for the directory and try to chdir there */ if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { - if (chdir(path)) { + /* if not .CURDIR it must be writable */ + if ((strcmp(path, curdir) != 0 && access(path, W_OK) != 0) || + chdir(path)) { (void)fprintf(stderr, "make warning: %s: %s.\n", path, strerror(errno)); } else { @@ -779,7 +761,7 @@ Main_SetObjdir(const char *fmt, ...) Dir_InitDot(); purge_cached_realpaths(); rc = TRUE; - if (enterFlag && strcmp(objdir, curdir) != 0) + if (opts.enterFlag && strcmp(objdir, curdir) != 0) enterFlagObj = TRUE; } } @@ -790,8 +772,8 @@ Main_SetObjdir(const char *fmt, ...) static Boolean Main_SetVarObjdir(const char *var, const char *suffix) { - char *path_freeIt; - const char *path = Var_Value(var, VAR_CMD, &path_freeIt); + void *path_freeIt; + const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt); const char *xpath; char *xpath_freeIt; @@ -803,9 +785,11 @@ Main_SetVarObjdir(const char *var, const char *suffix) /* expand variable substitutions */ xpath = path; xpath_freeIt = NULL; - if (strchr(path, '$') != 0) - xpath = xpath_freeIt = Var_Subst(path, VAR_GLOBAL, - VARE_WANTRES); + if (strchr(path, '$') != 0) { + (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt); + /* TODO: handle errors */ + xpath = xpath_freeIt; + } (void)Main_SetObjdir("%s%s", xpath, suffix); @@ -815,23 +799,15 @@ Main_SetVarObjdir(const char *var, const char *suffix) } /* Read and parse the makefile. - * Return TRUE if reading the makefile succeeded, for Lst_Find. */ -static Boolean -ReadMakefileSucceeded(const void *fname, const void *unused) + * Return TRUE if reading the makefile succeeded. */ +static int +ReadMakefileSucceeded(void *fname, void *unused) { return ReadMakefile(fname) == 0; } -/* Read and parse the makefile. - * Return TRUE if reading the makefile failed, for Lst_Find. */ -static Boolean -ReadMakefileFailed(const void *fname, const void *unused) -{ - return ReadMakefile(fname) != 0; -} - int -str2Lst_Append(Lst lp, char *str, const char *sep) +str2Lst_Append(StringList *lp, char *str, const char *sep) { char *cp; int n; @@ -870,13 +846,16 @@ MakeMode(const char *mode) { char *mode_freeIt = NULL; - if (mode == NULL) - mode = mode_freeIt = Var_Subst("${" MAKE_MODE ":tl}", - VAR_GLOBAL, VARE_WANTRES); + if (mode == NULL) { + (void)Var_Subst("${" MAKE_MODE ":tl}", + VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); + /* TODO: handle errors */ + mode = mode_freeIt; + } if (mode[0] != '\0') { if (strstr(mode, "compat")) { - compatMake = TRUE; + opts.compatMake = TRUE; forceJobs = FALSE; } #if USE_META @@ -889,46 +868,56 @@ MakeMode(const char *mode) } static void +PrintVar(const char *varname, Boolean expandVars) +{ + if (strchr(varname, '$')) { + char *evalue; + (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue); + /* TODO: handle errors */ + printf("%s\n", evalue); + bmake_free(evalue); + + } else if (expandVars) { + char *expr = str_concat3("${", varname, "}"); + char *evalue; + (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue); + /* TODO: handle errors */ + free(expr); + printf("%s\n", evalue); + bmake_free(evalue); + + } else { + void *freeIt; + const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt); + printf("%s\n", value ? value : ""); + bmake_free(freeIt); + } +} + +static void doPrintVars(void) { - LstNode ln; + StringListNode *ln; Boolean expandVars; - if (printVars == EXPAND_VARS) + if (opts.printVars == EXPAND_VARS) expandVars = TRUE; - else if (debugVflag) + else if (opts.debugVflag) expandVars = FALSE; else expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); - for (ln = Lst_First(variables); ln != NULL; ln = LstNode_Next(ln)) { - char *var = LstNode_Datum(ln); - const char *value; - char *p1; - - if (strchr(var, '$')) { - value = p1 = Var_Subst(var, VAR_GLOBAL, VARE_WANTRES); - } else if (expandVars) { - char tmp[128]; - int len = snprintf(tmp, sizeof(tmp), "${%s}", var); - - if (len >= (int)sizeof(tmp)) - Fatal("%s: variable name too big: %s", - progname, var); - value = p1 = Var_Subst(tmp, VAR_GLOBAL, VARE_WANTRES); - } else { - value = Var_Value(var, VAR_GLOBAL, &p1); - } - printf("%s\n", value ? value : ""); - bmake_free(p1); + for (ln = opts.variables->first; ln != NULL; ln = ln->next) { + const char *varname = ln->datum; + PrintVar(varname, expandVars); } } static Boolean runTargets(void) { - Lst targs; /* target nodes to create -- passed to Make_Init */ - Boolean outOfDate; /* FALSE if all targets up to date */ + GNodeList *targs; /* target nodes to create -- passed to Make_Init */ + Boolean outOfDate; /* FALSE if all targets up to date */ /* * Have now read the entire graph and need to make a list of @@ -936,12 +925,12 @@ runTargets(void) * we consult the parsing module to find the main target(s) * to create. */ - if (Lst_IsEmpty(create)) + if (Lst_IsEmpty(opts.create)) targs = Parse_MainName(); else - targs = Targ_FindList(create, TARG_CREATE); + targs = Targ_FindList(opts.create); - if (!compatMake) { + if (!opts.compatMake) { /* * Initialize job module before traversing the graph * now that any .BEGIN and .END targets have been read. @@ -949,7 +938,7 @@ runTargets(void) * (to prevent the .BEGIN from being executed should * it exist). */ - if (!queryFlag) { + if (!opts.queryFlag) { Job_Init(); jobsRunning = TRUE; } @@ -968,6 +957,397 @@ runTargets(void) return outOfDate; } +/* + * Set up the .TARGETS variable to contain the list of targets to be + * created. If none specified, make the variable empty -- the parser + * will fill the thing in with the default or .MAIN target. + */ +static void +InitVarTargets(void) +{ + StringListNode *ln; + + if (Lst_IsEmpty(opts.create)) { + Var_Set(".TARGETS", "", VAR_GLOBAL); + return; + } + + for (ln = opts.create->first; ln != NULL; ln = ln->next) { + char *name = ln->datum; + Var_Append(".TARGETS", name, VAR_GLOBAL); + } +} + +static void +InitRandom(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); +} + +static const char * +init_machine(const struct utsname *utsname) +{ +#ifdef FORCE_MACHINE + const char *machine = FORCE_MACHINE; +#else + const char *machine = getenv("MACHINE"); +#endif + if (machine != NULL) + return machine; + +#ifdef MAKE_NATIVE + return utsname->machine; +#else +#ifdef MAKE_MACHINE + return MAKE_MACHINE; +#else + return "unknown"; +#endif +#endif +} + +static const char * +init_machine_arch(void) +{ + const char *env = getenv("MACHINE_ARCH"); + if (env != NULL) + return env; + +#if defined(MAKE_NATIVE) && defined(CTL_HW) + { + struct utsname utsname; + static char machine_arch_buf[sizeof(utsname.machine)]; + const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; + size_t len = sizeof(machine_arch_buf); + + if (sysctl(mib, __arraycount(mib), machine_arch_buf, + &len, NULL, 0) < 0) { + (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, + strerror(errno)); + exit(2); + } + + return machine_arch_buf; + } +#else +#ifndef MACHINE_ARCH +#ifdef MAKE_MACHINE_ARCH + return MAKE_MACHINE_ARCH; +#else + return "unknown"; +#endif +#else + return MACHINE_ARCH; +#endif +#endif +} + +#ifndef NO_PWD_OVERRIDE +/* + * All this code is so that we know where we are when we start up + * on a different machine with pmake. + * + * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX + * since the value of curdir can vary depending on how we got + * here. Ie sitting at a shell prompt (shell that provides $PWD) + * or via subdir.mk in which case its likely a shell which does + * not provide it. + * + * So, to stop it breaking this case only, we ignore PWD if + * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. + */ +static void +HandlePWD(const struct stat *curdir_st) +{ + char *pwd; + void *prefix_freeIt, *makeobjdir_freeIt; + const char *makeobjdir; + struct stat pwd_st; + + if (ignorePWD || (pwd = getenv("PWD")) == NULL) + return; + + if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) { + bmake_free(prefix_freeIt); + return; + } + + makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt); + if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL) + goto ignore_pwd; + + if (stat(pwd, &pwd_st) == 0 && + curdir_st->st_ino == pwd_st.st_ino && + curdir_st->st_dev == pwd_st.st_dev) + (void)strncpy(curdir, pwd, MAXPATHLEN); + +ignore_pwd: + bmake_free(makeobjdir_freeIt); +} +#endif + +/* + * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, + * MAKEOBJDIR is set in the environment, try only that value + * and fall back to .CURDIR if it does not exist. + * + * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, + * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none + * of these paths exist, just use .CURDIR. + */ +static void +InitObjdir(const char *machine, const char *machine_arch) +{ + Dir_InitDir(curdir); + (void)Main_SetObjdir("%s", curdir); + + if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && + !Main_SetVarObjdir("MAKEOBJDIR", "") && + !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && + !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && + !Main_SetObjdir("%s", _PATH_OBJDIR)) + (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); +} + +/* get rid of resource limit on file descriptors */ +static void +UnlimitFiles(void) +{ +#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && + rl.rlim_cur != rl.rlim_max) { + rl.rlim_cur = rl.rlim_max; + (void)setrlimit(RLIMIT_NOFILE, &rl); + } +#endif +} + +static void +CmdOpts_Init(void) +{ + opts.compatMake = FALSE; /* No compat mode */ + opts.debug = 0; /* No debug verbosity, please. */ + /* opts.debug_file has been initialized earlier */ + opts.debugVflag = FALSE; + opts.checkEnvFirst = FALSE; + opts.makefiles = Lst_New(); + opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ + opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ + opts.keepgoing = FALSE; /* Stop on error */ + opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ + opts.noExecute = FALSE; /* Execute all commands */ + opts.queryFlag = FALSE; /* This is not just a check-run */ + opts.noBuiltins = FALSE; /* Read the built-in rules */ + opts.beSilent = FALSE; /* Print commands as executed */ + opts.touchFlag = FALSE; /* Actually update targets */ + opts.printVars = 0; + opts.variables = Lst_New(); + opts.parseWarnFatal = FALSE; + opts.enterFlag = FALSE; + opts.varNoExportEnv = FALSE; + opts.create = Lst_New(); +} + +/* Initialize MAKE and .MAKE to the path of the executable, so that it can be + * found by execvp(3) and the shells, even after a chdir. + * + * If it's a relative path and contains a '/', resolve it to an absolute path. + * Otherwise keep it as is, assuming it will be found in the PATH. */ +static void +InitVarMake(const char *argv0) +{ + const char *make = argv0; + + if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { + char pathbuf[MAXPATHLEN]; + const char *abs = cached_realpath(argv0, pathbuf); + struct stat st; + if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0) + make = abs; + } + + Var_Set("MAKE", make, VAR_GLOBAL); + Var_Set(".MAKE", make, VAR_GLOBAL); +} + +static void +InitDefSysIncPath(char *syspath) +{ + static char defsyspath[] = _PATH_DEFSYSPATH; + char *start, *cp; + + /* + * If no user-supplied system path was given (through the -m option) + * add the directories from the DEFSYSPATH (more than one may be given + * as dir1:...:dirn) to the system include path. + */ + /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ + if (syspath == NULL || syspath[0] == '\0') + syspath = defsyspath; + else + syspath = bmake_strdup(syspath); + + for (start = syspath; *start != '\0'; start = cp) { + for (cp = start; *cp != '\0' && *cp != ':'; cp++) + continue; + if (*cp == ':') { + *cp++ = '\0'; + } + /* look for magic parent directory search string */ + if (strncmp(".../", start, 4) != 0) { + (void)Dir_AddDir(defSysIncPath, start); + } else { + char *dir = Dir_FindHereOrAbove(curdir, start + 4); + if (dir != NULL) { + (void)Dir_AddDir(defSysIncPath, dir); + free(dir); + } + } + } + + if (syspath != defsyspath) + free(syspath); +} + +static void +ReadBuiltinRules(void) +{ + StringList *sysMkPath = Lst_New(); + Dir_Expand(_PATH_DEFSYSMK, + Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, + sysMkPath); + if (Lst_IsEmpty(sysMkPath)) + Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); + if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL)) + Fatal("%s: cannot open %s.", progname, + (char *)sysMkPath->first->datum); + /* XXX: sysMkPath is not freed */ +} + +static void +InitMaxJobs(void) +{ + char *value; + int n; + + if (forceJobs || opts.compatMake || + !Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) + return; + + (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); + /* TODO: handle errors */ + n = (int)strtol(value, NULL, 0); + if (n < 1) { + (void)fprintf(stderr, + "%s: illegal value for .MAKE.JOBS " + "-- must be positive integer!\n", + progname); + exit(1); + } + + if (n != opts.maxJobs) { + Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); + Var_Append(MAKEFLAGS, value, VAR_GLOBAL); + } + + opts.maxJobs = n; + maxJobTokens = opts.maxJobs; + forceJobs = TRUE; + free(value); +} + +/* + * For compatibility, look at the directories in the VPATH variable + * and add them to the search path, if the variable is defined. The + * variable's value is in the same format as the PATH environment + * variable, i.e. <directory>:<directory>:<directory>... + */ +static void +InitVpath(void) +{ + char *vpath, savec, *path; + if (!Var_Exists("VPATH", VAR_CMDLINE)) + return; + + (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath); + /* TODO: handle errors */ + path = vpath; + do { + char *cp; + /* skip to end of directory */ + for (cp = path; *cp != ':' && *cp != '\0'; cp++) + continue; + /* Save terminator character so know when to stop */ + savec = *cp; + *cp = '\0'; + /* Add directory to search path */ + (void)Dir_AddDir(dirSearchPath, path); + *cp = savec; + path = cp + 1; + } while (savec == ':'); + free(vpath); +} + +static void +ReadMakefiles(void) +{ + if (opts.makefiles->first != NULL) { + StringListNode *ln; + + for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) { + if (ReadMakefile(ln->datum) != 0) + Fatal("%s: cannot open %s.", + progname, (char *)ln->datum); + } + } else { + char *p1; + (void)Var_Subst("${" MAKEFILE_PREFERENCE "}", + VAR_CMDLINE, VARE_WANTRES, &p1); + /* TODO: handle errors */ + (void)str2Lst_Append(opts.makefiles, p1, NULL); + (void)Lst_ForEachUntil(opts.makefiles, + ReadMakefileSucceeded, NULL); + free(p1); + } +} + +static void +CleanUp(void) +{ +#ifdef CLEANUP + Lst_Destroy(opts.variables, free); + Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */ + Lst_Destroy(opts.create, free); +#endif + + /* print the graph now it's been processed if the user requested it */ + if (DEBUG(GRAPH2)) + Targ_PrintGraph(2); + + Trace_Log(MAKEEND, 0); + + if (enterFlagObj) + printf("%s: Leaving directory `%s'\n", progname, objdir); + if (opts.enterFlag) + printf("%s: Leaving directory `%s'\n", progname, curdir); + +#ifdef USE_META + meta_finish(); +#endif + Suff_End(); + Targ_End(); + Arch_End(); + Var_End(); + Parse_End(); + Dir_End(); + Job_End(); + Trace_End(); +} + /*- * main -- * The main function, for obvious reasons. Initializes variables @@ -988,55 +1368,28 @@ runTargets(void) int main(int argc, char **argv) { - Boolean outOfDate; /* FALSE if all targets up to date */ - struct stat sb, sa; - char *p1, *path; - char mdpath[MAXPATHLEN]; -#ifdef FORCE_MACHINE - const char *machine = FORCE_MACHINE; -#else - const char *machine = getenv("MACHINE"); -#endif - const char *machine_arch = getenv("MACHINE_ARCH"); + Boolean outOfDate; /* FALSE if all targets up to date */ + struct stat sa; + const char *machine; + const char *machine_arch; char *syspath = getenv("MAKESYSPATH"); - Lst sysMkPath; /* Path of sys.mk */ - char *cp = NULL, *start; - /* avoid faults on read-only strings */ - static char defsyspath[] = _PATH_DEFSYSPATH; - char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ - struct timeval rightnow; /* to initialize random seed */ struct utsname utsname; /* default to writing debug to stderr */ - debug_file = stderr; + opts.debug_file = stderr; #ifdef SIGINFO (void)bmake_signal(SIGINFO, siginfo); #endif - /* - * Set the seed to produce a different random sequence - * on each program execution. - */ - gettimeofday(&rightnow, NULL); - srandom(rightnow.tv_sec + rightnow.tv_usec); + + InitRandom(); if ((progname = strrchr(argv[0], '/')) != NULL) progname++; else progname = argv[0]; -#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) - /* - * get rid of resource limit on file descriptors - */ - { - struct rlimit rl; - if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && - rl.rlim_cur != rl.rlim_max) { - rl.rlim_cur = rl.rlim_max; - (void)setrlimit(RLIMIT_NOFILE, &rl); - } - } -#endif + + UnlimitFiles(); if (uname(&utsname) == -1) { (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, @@ -1052,44 +1405,8 @@ main(int argc, char **argv) * Note that both MACHINE and MACHINE_ARCH are decided at * run-time. */ - if (!machine) { -#ifdef MAKE_NATIVE - machine = utsname.machine; -#else -#ifdef MAKE_MACHINE - machine = MAKE_MACHINE; -#else - machine = "unknown"; -#endif -#endif - } - - if (!machine_arch) { -#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_MACHINE_ARCH) - static char machine_arch_buf[sizeof(utsname.machine)]; - int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; - size_t len = sizeof(machine_arch_buf); - - if (sysctl(mib, __arraycount(mib), machine_arch_buf, - &len, NULL, 0) < 0) { - (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, - strerror(errno)); - exit(2); - } - - machine_arch = machine_arch_buf; -#else -#ifndef MACHINE_ARCH -#ifdef MAKE_MACHINE_ARCH - machine_arch = MAKE_MACHINE_ARCH; -#else - machine_arch = "unknown"; -#endif -#else - machine_arch = MACHINE_ARCH; -#endif -#endif - } + machine = init_machine(&utsname); + machine_arch = init_machine_arch(); myPid = getpid(); /* remember this for vFork() */ @@ -1115,27 +1432,12 @@ main(int argc, char **argv) VAR_GLOBAL); Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); - create = Lst_Init(); - makefiles = Lst_Init(); - printVars = 0; - debugVflag = FALSE; - variables = Lst_Init(); - beSilent = FALSE; /* Print commands as executed */ - ignoreErrors = FALSE; /* Pay attention to non-zero returns */ - noExecute = FALSE; /* Execute all commands */ - noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ - keepgoing = FALSE; /* Stop on error */ + CmdOpts_Init(); allPrecious = FALSE; /* Remove targets when interrupted */ deleteOnError = FALSE; /* Historical default behavior */ - queryFlag = FALSE; /* This is not just a check-run */ - noBuiltins = FALSE; /* Read the built-in rules */ - touchFlag = FALSE; /* Actually update targets */ - debug = 0; /* No debug verbosity, please. */ jobsRunning = FALSE; - maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ - maxJobTokens = maxJobs; - compatMake = FALSE; /* No compat mode */ + maxJobTokens = opts.maxJobs; ignorePWD = FALSE; /* @@ -1151,30 +1453,13 @@ main(int argc, char **argv) * MFLAGS also gets initialized empty, for compatibility. */ Parse_Init(); - if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { - /* - * Leave alone if it is an absolute path, or if it does - * not contain a '/' in which case we need to find it in - * the path, like execvp(3) and the shells do. - */ - p1 = argv[0]; - } else { - /* - * A relative path, canonicalize it. - */ - p1 = cached_realpath(argv[0], mdpath); - if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { - p1 = argv[0]; /* realpath failed */ - } - } - Var_Set("MAKE", p1, VAR_GLOBAL); - Var_Set(".MAKE", p1, VAR_GLOBAL); + InitVarMake(argv[0]); Var_Set(MAKEFLAGS, "", VAR_GLOBAL); Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); Var_Set("MFLAGS", "", VAR_GLOBAL); Var_Set(".ALLTARGETS", "", VAR_GLOBAL); /* some makefiles need to know this */ - Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD); + Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE); /* * Set some other useful macros @@ -1209,9 +1494,11 @@ main(int argc, char **argv) * in a different format). */ #ifdef POSIX - p1 = explode(getenv("MAKEFLAGS")); - Main_ParseArgLine(p1); - free(p1); + { + char *p1 = explode(getenv("MAKEFLAGS")); + Main_ParseArgLine(p1); + free(p1); + } #else Main_ParseArgLine(getenv("MAKE")); #endif @@ -1228,7 +1515,7 @@ main(int argc, char **argv) MainParseArgs(argc, argv); - if (enterFlag) + if (opts.enterFlag) printf("%s: Entering directory `%s'\n", progname, curdir); /* @@ -1240,57 +1527,12 @@ main(int argc, char **argv) exit(2); } - /* - * All this code is so that we know where we are when we start up - * on a different machine with pmake. - * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX - * since the value of curdir can vary depending on how we got - * here. Ie sitting at a shell prompt (shell that provides $PWD) - * or via subdir.mk in which case its likely a shell which does - * not provide it. - * So, to stop it breaking this case only, we ignore PWD if - * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. - */ #ifndef NO_PWD_OVERRIDE - if (!ignorePWD) { - char *pwd, *ptmp1 = NULL, *ptmp2 = NULL; - - if ((pwd = getenv("PWD")) != NULL && - Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &ptmp1) == NULL) { - const char *makeobjdir = Var_Value("MAKEOBJDIR", - VAR_CMD, &ptmp2); - - if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { - if (stat(pwd, &sb) == 0 && - sa.st_ino == sb.st_ino && - sa.st_dev == sb.st_dev) - (void)strncpy(curdir, pwd, MAXPATHLEN); - } - } - bmake_free(ptmp1); - bmake_free(ptmp2); - } + HandlePWD(&sa); #endif Var_Set(".CURDIR", curdir, VAR_GLOBAL); - /* - * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, - * MAKEOBJDIR is set in the environment, try only that value - * and fall back to .CURDIR if it does not exist. - * - * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, - * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none - * of these paths exist, just use .CURDIR. - */ - Dir_InitDir(curdir); - (void)Main_SetObjdir("%s", curdir); - - if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && - !Main_SetVarObjdir("MAKEOBJDIR", "") && - !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && - !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && - !Main_SetObjdir("%s", _PATH_OBJDIR)) - (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); + InitObjdir(machine, machine_arch); /* * Initialize archive, target and suffix modules in preparation for @@ -1306,95 +1548,30 @@ main(int argc, char **argv) Trace_Log(MAKESTART, NULL); - /* - * Set up the .TARGETS variable to contain the list of targets to be - * created. If none specified, make the variable empty -- the parser - * will fill the thing in with the default or .MAIN target. - */ - if (!Lst_IsEmpty(create)) { - LstNode ln; - - for (ln = Lst_First(create); ln != NULL; ln = LstNode_Next(ln)) { - char *name = LstNode_Datum(ln); - Var_Append(".TARGETS", name, VAR_GLOBAL); - } - } else - Var_Set(".TARGETS", "", VAR_GLOBAL); - - - /* - * If no user-supplied system path was given (through the -m option) - * add the directories from the DEFSYSPATH (more than one may be given - * as dir1:...:dirn) to the system include path. - */ - /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ - if (syspath == NULL || syspath[0] == '\0') - syspath = defsyspath; - else - syspath = bmake_strdup(syspath); + InitVarTargets(); - for (start = syspath; *start != '\0'; start = cp) { - for (cp = start; *cp != '\0' && *cp != ':'; cp++) - continue; - if (*cp == ':') { - *cp++ = '\0'; - } - /* look for magic parent directory search string */ - if (strncmp(".../", start, 4) != 0) { - (void)Dir_AddDir(defIncPath, start); - } else { - if (Dir_FindHereOrAbove(curdir, start+4, - found_path, sizeof(found_path))) { - (void)Dir_AddDir(defIncPath, found_path); - } - } - } - if (syspath != defsyspath) - free(syspath); + InitDefSysIncPath(syspath); /* * Read in the built-in rules first, followed by the specified * makefiles, or the default makefile and Makefile, in that order, * if no makefiles were given on the command line. */ - if (!noBuiltins) { - LstNode ln; - - sysMkPath = Lst_Init(); - Dir_Expand(_PATH_DEFSYSMK, - Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, - sysMkPath); - if (Lst_IsEmpty(sysMkPath)) - Fatal("%s: no system rules (%s).", progname, - _PATH_DEFSYSMK); - ln = Lst_Find(sysMkPath, ReadMakefileSucceeded, NULL); - if (ln == NULL) - Fatal("%s: cannot open %s.", progname, - (char *)LstNode_Datum(Lst_First(sysMkPath))); - } - - if (!Lst_IsEmpty(makefiles)) { - LstNode ln; - - ln = Lst_Find(makefiles, ReadMakefileFailed, NULL); - if (ln != NULL) - Fatal("%s: cannot open %s.", progname, - (char *)LstNode_Datum(ln)); - } else { - p1 = Var_Subst("${" MAKEFILE_PREFERENCE "}", - VAR_CMD, VARE_WANTRES); - (void)str2Lst_Append(makefiles, p1, NULL); - (void)Lst_Find(makefiles, ReadMakefileSucceeded, NULL); - free(p1); - } - + if (!opts.noBuiltins) + ReadBuiltinRules(); + ReadMakefiles(); + /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ - if (!noBuiltins || !printVars) { - makeDependfile = Var_Subst("${.MAKE.DEPENDFILE:T}", - VAR_CMD, VARE_WANTRES); - doing_depend = TRUE; - (void)ReadMakefile(makeDependfile); - doing_depend = FALSE; + if (!opts.noBuiltins || !opts.printVars) { + /* ignore /dev/null and anything starting with "no" */ + (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", + VAR_CMDLINE, VARE_WANTRES, &makeDependfile); + if (makeDependfile[0] != '\0') { + /* TODO: handle errors */ + doing_depend = TRUE; + (void)ReadMakefile(makeDependfile); + doing_depend = FALSE; + } } if (enterFlagObj) @@ -1402,81 +1579,33 @@ main(int argc, char **argv) MakeMode(NULL); - Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); - bmake_free(p1); - - if (!forceJobs && !compatMake && - Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) { - char *value; - int n; + { + void *freeIt; + Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), + VAR_GLOBAL); + bmake_free(freeIt); - value = Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES); - n = strtol(value, NULL, 0); - if (n < 1) { - (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n", - progname); - exit(1); - } - if (n != maxJobs) { - Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); - Var_Append(MAKEFLAGS, value, VAR_GLOBAL); - } - maxJobs = n; - maxJobTokens = maxJobs; - forceJobs = TRUE; - free(value); } + InitMaxJobs(); + /* * Be compatible if user did not specify -j and did not explicitly * turned compatibility on */ - if (!compatMake && !forceJobs) { - compatMake = TRUE; + if (!opts.compatMake && !forceJobs) { + opts.compatMake = TRUE; } - if (!compatMake) + if (!opts.compatMake) Job_ServerStart(maxJobTokens, jp_0, jp_1); - if (DEBUG(JOB)) - fprintf(debug_file, - "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", - jp_0, jp_1, maxJobs, maxJobTokens, compatMake ? 1 : 0); + DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", + jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); - if (!printVars) + if (!opts.printVars) Main_ExportMAKEFLAGS(TRUE); /* initial export */ - - /* - * For compatibility, look at the directories in the VPATH variable - * and add them to the search path, if the variable is defined. The - * variable's value is in the same format as the PATH envariable, i.e. - * <directory>:<directory>:<directory>... - */ - if (Var_Exists("VPATH", VAR_CMD)) { - char *vpath, savec; - /* - * GCC stores string constants in read-only memory, but - * Var_Subst will want to write this thing, so store it - * in an array - */ - static char VPATH[] = "${VPATH}"; - - vpath = Var_Subst(VPATH, VAR_CMD, VARE_WANTRES); - path = vpath; - do { - /* skip to end of directory */ - for (cp = path; *cp != ':' && *cp != '\0'; cp++) - continue; - /* Save terminator character so know when to stop */ - savec = *cp; - *cp = '\0'; - /* Add directory to search path */ - (void)Dir_AddDir(dirSearchPath, path); - *cp = savec; - path = cp + 1; - } while (savec == ':'); - free(vpath); - } + InitVpath(); /* * Now that all search paths have been read for suffixes et al, it's @@ -1494,42 +1623,17 @@ main(int argc, char **argv) Targ_PrintGraph(1); /* print the values of any variables requested by the user */ - if (printVars) { + if (opts.printVars) { doPrintVars(); outOfDate = FALSE; } else { outOfDate = runTargets(); } -#ifdef CLEANUP - Lst_Free(variables); - Lst_Free(makefiles); - Lst_Destroy(create, free); -#endif - - /* print the graph now it's been processed if the user requested it */ - if (DEBUG(GRAPH2)) - Targ_PrintGraph(2); - - Trace_Log(MAKEEND, 0); - - if (enterFlagObj) - printf("%s: Leaving directory `%s'\n", progname, objdir); - if (enterFlag) - printf("%s: Leaving directory `%s'\n", progname, curdir); - -#ifdef USE_META - meta_finish(); -#endif - Suff_End(); - Targ_End(); - Arch_End(); - Var_End(); - Parse_End(); - Dir_End(); - Job_End(); - Trace_End(); + CleanUp(); + if (DEBUG(LINT) && (errors > 0 || Parse_GetFatals() > 0)) + return 2; /* Not 1 so -q can distinguish error */ return outOfDate ? 1 : 0; } @@ -1572,9 +1676,11 @@ ReadMakefile(const char *fname) } /* look in -I and system include directories. */ name = Dir_FindFile(fname, parseIncPath); - if (!name) - name = Dir_FindFile(fname, - Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); + if (!name) { + SearchPath *sysInc = Lst_IsEmpty(sysIncPath) + ? defSysIncPath : sysIncPath; + name = Dir_FindFile(fname, sysInc); + } if (!name || (fd = open(name, O_RDONLY)) == -1) { free(name); free(path); @@ -1613,10 +1719,10 @@ found: char * Cmd_Exec(const char *cmd, const char **errfmt) { - const char *args[4]; /* Args for invoking the shell */ - int fds[2]; /* Pipe streams */ - int cpid; /* Child PID */ - int pid; /* PID from wait() */ + const char *args[4]; /* Args for invoking the shell */ + int fds[2]; /* Pipe streams */ + int cpid; /* Child PID */ + int pid; /* PID from wait() */ WAIT_T status; /* command exit status */ Buffer buf; /* buffer to store the result */ ssize_t bytes_read; @@ -1704,7 +1810,7 @@ Cmd_Exec(const char *cmd, const char **errfmt) JobReapChild(pid, status, FALSE); continue; } - res_len = Buf_Size(&buf); + res_len = Buf_Len(&buf); res = Buf_Destroy(&buf, FALSE); if (savederr != 0) @@ -1728,24 +1834,17 @@ bad: return bmake_strdup(""); } -/*- - * Error -- - * Print an error message given its format. +/* Print a printf-style error message. * - * Results: - * None. - * - * Side Effects: - * The message is printed. - */ -/* VARARGS */ + * This error message has no consequences, in particular it does not affect + * the exit status. */ void Error(const char *fmt, ...) { va_list ap; FILE *err_file; - err_file = debug_file; + err_file = opts.debug_file; if (err_file == stdout) err_file = stderr; (void)fflush(stdout); @@ -1760,20 +1859,12 @@ Error(const char *fmt, ...) break; err_file = stderr; } + errors++; } -/*- - * Fatal -- - * Produce a Fatal error message. If jobs are running, waits for them - * to finish. - * - * Results: - * None +/* Produce a Fatal error message, then exit immediately. * - * Side Effects: - * The program exits - */ -/* VARARGS */ + * If jobs are running, wait for them to finish. */ void Fatal(const char *fmt, ...) { @@ -1797,18 +1888,8 @@ Fatal(const char *fmt, ...) exit(2); /* Not 1 so -q can distinguish error */ } -/* - * Punt -- - * Major exception once jobs are being created. Kills all jobs, prints - * a message and exits. - * - * Results: - * None - * - * Side Effects: - * All children are killed indiscriminately and the program Lib_Exits - */ -/* VARARGS */ +/* Major exception once jobs are being created. + * Kills all jobs, prints a message and exits. */ void Punt(const char *fmt, ...) { @@ -1827,16 +1908,7 @@ Punt(const char *fmt, ...) DieHorribly(); } -/*- - * DieHorribly -- - * Exit without giving a message. - * - * Results: - * None - * - * Side Effects: - * A big one... - */ +/* Exit without giving a message. */ void DieHorribly(void) { @@ -1848,24 +1920,15 @@ DieHorribly(void) exit(2); /* Not 1, so -q can distinguish error */ } -/* - * Finish -- - * Called when aborting due to errors in child shell to signal - * abnormal exit. - * - * Results: - * None - * - * Side Effects: - * The program exits - */ +/* Called when aborting due to errors in child shell to signal abnormal exit. + * The program exits. + * Errors is the number of errors encountered in Make_Make. */ void -Finish(int errors) - /* number of errors encountered in Make_Make */ +Finish(int errs) { if (dieQuietly(NULL, -1)) exit(2); - Fatal("%d error%s", errors, errors == 1 ? "" : "s"); + Fatal("%d error%s", errs, errs == 1 ? "" : "s"); } /* @@ -1887,37 +1950,45 @@ eunlink(const char *file) return unlink(file); } +static void +write_all(int fd, const void *data, size_t n) +{ + const char *mem = data; + + while (n > 0) { + ssize_t written = write(fd, mem, n); + if (written == -1 && errno == EAGAIN) + continue; + if (written == -1) + break; + mem += written; + n -= (size_t)written; + } +} + /* - * execError -- + * execDie -- * Print why exec failed, avoiding stdio. */ -void -execError(const char *af, const char *av) +void MAKE_ATTR_DEAD +execDie(const char *af, const char *av) { -#ifdef USE_IOVEC - int i = 0; - struct iovec iov[8]; -#define IOADD(s) \ - (void)(iov[i].iov_base = UNCONST(s), \ - iov[i].iov_len = strlen(iov[i].iov_base), \ - i++) -#else -#define IOADD(s) (void)write(2, s, strlen(s)) -#endif + Buffer buf; - IOADD(progname); - IOADD(": "); - IOADD(af); - IOADD("("); - IOADD(av); - IOADD(") failed ("); - IOADD(strerror(errno)); - IOADD(")\n"); - -#ifdef USE_IOVEC - while (writev(2, iov, 8) == -1 && errno == EAGAIN) - continue; -#endif + Buf_Init(&buf, 0); + Buf_AddStr(&buf, progname); + Buf_AddStr(&buf, ": "); + Buf_AddStr(&buf, af); + Buf_AddStr(&buf, "("); + Buf_AddStr(&buf, av); + Buf_AddStr(&buf, ") failed ("); + Buf_AddStr(&buf, strerror(errno)); + Buf_AddStr(&buf, ")\n"); + + write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf)); + + Buf_Destroy(&buf, TRUE); + _exit(1); } /* @@ -1964,16 +2035,17 @@ static void purge_cached_realpaths(void) { GNode *cache = get_cached_realpaths(); - Hash_Entry *he, *nhe; - Hash_Search hs; - - he = Hash_EnumFirst(&cache->context, &hs); - while (he) { - nhe = Hash_EnumNext(&hs); - if (he->name[0] != '/') { + HashEntry *he, *nhe; + HashIter hi; + + HashIter_Init(&hi, &cache->context); + he = HashIter_Next(&hi); + while (he != NULL) { + nhe = HashIter_Next(&hi); + if (he->key[0] != '/') { if (DEBUG(DIR)) - fprintf(stderr, "cached_realpath: purging %s\n", he->name); - Hash_DeleteEntry(&cache->context, he); + fprintf(stderr, "cached_realpath: purging %s\n", he->key); + HashTable_DeleteEntry(&cache->context, he); } he = nhe; } @@ -1984,41 +2056,24 @@ cached_realpath(const char *pathname, char *resolved) { GNode *cache; const char *rp; - char *cp; + void *freeIt; if (!pathname || !pathname[0]) return NULL; cache = get_cached_realpaths(); - if ((rp = Var_Value(pathname, cache, &cp)) != NULL) { + if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) { /* a hit */ strlcpy(resolved, rp, MAXPATHLEN); } else if ((rp = realpath(pathname, resolved)) != NULL) { Var_Set(pathname, rp, cache); } /* else should we negative-cache? */ - bmake_free(cp); + bmake_free(freeIt); return rp ? resolved : NULL; } -int -PrintAddr(void *a, void *b) -{ - printf("%lx ", (unsigned long) a); - return b ? 0 : 0; -} - - -static int -addErrorCMD(void *cmdp, void *gnp MAKE_ATTR_UNUSED) -{ - if (cmdp == NULL) - return 1; /* stop */ - Var_Append(".ERROR_CMD", cmdp, VAR_GLOBAL); - return 0; -} - /* * Return true if we should die without noise. * For example our failing child was a sub-make @@ -2030,16 +2085,36 @@ dieQuietly(GNode *gn, int bf) static int quietly = -1; if (quietly < 0) { - if (DEBUG(JOB) || getBoolean(".MAKE.DIE_QUIETLY", 1) == 0) + if (DEBUG(JOB) || !getBoolean(".MAKE.DIE_QUIETLY", TRUE)) quietly = 0; else if (bf >= 0) quietly = bf; else - quietly = (gn) ? ((gn->type & (OP_MAKE)) != 0) : 0; + quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0; } return quietly; } +static void +SetErrorVars(GNode *gn) +{ + StringListNode *ln; + + /* + * We can print this even if there is no .ERROR target. + */ + Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); + Var_Delete(".ERROR_CMD", VAR_GLOBAL); + + for (ln = gn->commands->first; ln != NULL; ln = ln->next) { + const char *cmd = ln->datum; + + if (cmd == NULL) + break; + Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); + } +} + void PrintOnError(GNode *gn, const char *s) { @@ -2063,16 +2138,11 @@ PrintOnError(GNode *gn, const char *s) if (en) return; /* we've been here! */ - if (gn) { - /* - * We can print this even if there is no .ERROR target. - */ - Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); - Var_Delete(".ERROR_CMD", VAR_GLOBAL); - Lst_ForEach(gn->commands, addErrorCMD, gn); - } + if (gn) + SetErrorVars(gn); expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; - cp = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); + (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); + /* TODO: handle errors */ printf("%s", cp); free(cp); fflush(stdout); @@ -2080,7 +2150,7 @@ PrintOnError(GNode *gn, const char *s) /* * Finally, see if there is a .ERROR target, and run it if so. */ - en = Targ_FindNode(".ERROR", TARG_NOCREATE); + en = Targ_FindNode(".ERROR"); if (en) { en->type |= OP_SPECIAL; Compat_Make(en, en); @@ -2099,7 +2169,8 @@ Main_ExportMAKEFLAGS(Boolean first) once = FALSE; expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; - s = Var_Subst(expr, VAR_CMD, VARE_WANTRES); + (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); + /* TODO: handle errors */ if (s[0] != '\0') { #ifdef POSIX setenv("MAKEFLAGS", s, 1); @@ -2121,8 +2192,9 @@ getTmpdir(void) * Honor $TMPDIR but only if it is valid. * Ensure it ends with /. */ - tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, - VARE_WANTRES); + (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, + VARE_WANTRES, &tmpdir); + /* TODO: handle errors */ if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { free(tmpdir); tmpdir = bmake_strdup(_PATH_TMP); @@ -2133,19 +2205,19 @@ getTmpdir(void) /* * Create and open a temp file using "pattern". - * If "fnamep" is provided set it to a copy of the filename created. + * If out_fname is provided, set it to a copy of the filename created. * Otherwise unlink the file once open. */ int -mkTempFile(const char *pattern, char **fnamep) +mkTempFile(const char *pattern, char **out_fname) { static char *tmpdir = NULL; char tfile[MAXPATHLEN]; int fd; - if (!pattern) + if (pattern != NULL) pattern = TMPPAT; - if (!tmpdir) + if (tmpdir == NULL) tmpdir = getTmpdir(); if (pattern[0] == '/') { snprintf(tfile, sizeof(tfile), "%s", pattern); @@ -2154,8 +2226,8 @@ mkTempFile(const char *pattern, char **fnamep) } if ((fd = mkstemp(tfile)) < 0) Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); - if (fnamep) { - *fnamep = bmake_strdup(tfile); + if (out_fname) { + *out_fname = bmake_strdup(tfile); } else { unlink(tfile); /* we just want the descriptor */ } @@ -2170,50 +2242,41 @@ mkTempFile(const char *pattern, char **fnamep) Boolean s2Boolean(const char *s, Boolean bf) { - if (s) { - switch(*s) { - case '\0': /* not set - the default wins */ - break; - case '0': - case 'F': - case 'f': - case 'N': - case 'n': - bf = FALSE; - break; - case 'O': - case 'o': - switch (s[1]) { - case 'F': - case 'f': - bf = FALSE; - break; - default: - bf = TRUE; - break; - } - break; - default: - bf = TRUE; - break; - } + switch(s[0]) { + case '\0': /* not set - the default wins */ + break; + case '0': + case 'F': + case 'f': + case 'N': + case 'n': + return FALSE; + case 'O': + case 'o': + return s[1] != 'F' && s[1] != 'f'; + default: + return TRUE; } return bf; } /* - * Return a Boolean based on setting of a knob. + * Return a Boolean based on a variable. * - * If the knob is not set, the supplied default is the return value. - * If set, anything that looks or smells like "No", "False", "Off", "0" etc, + * If the knob is not set, return the fallback. + * If set, anything that looks or smells like "No", "False", "Off", "0", etc. * is FALSE, otherwise TRUE. */ Boolean -getBoolean(const char *name, Boolean fallback) +getBoolean(const char *varname, Boolean fallback) { - char *expr = str_concat3("${", name, ":U:tl}"); - char *value = Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES); - Boolean res = s2Boolean(value, fallback); + char *expr = str_concat3("${", varname, ":U}"); + char *value; + Boolean res; + + (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); + /* TODO: handle errors */ + res = s2Boolean(value, fallback); free(value); free(expr); return res; |