aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2020-11-07 19:39:21 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2020-11-07 19:39:21 +0000
commit302da1a3d35c15cb29d76e0a939f8bcb13f7ad80 (patch)
treec2146dca82d530521c4d2cc46a95c26964311a2c /main.c
parent6bbc783f48498b808e19db4441299dc7d85a278b (diff)
downloadsrc-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.c1859
1 files changed, 961 insertions, 898 deletions
diff --git a/main.c b/main.c
index f27320c57451..729c225d4bc4 100644
--- a/main.c
+++ b/main.c
@@ -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;