aboutsummaryrefslogtreecommitdiff
path: root/contrib/bmake/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bmake/main.c')
-rw-r--r--contrib/bmake/main.c843
1 files changed, 387 insertions, 456 deletions
diff --git a/contrib/bmake/main.c b/contrib/bmake/main.c
index 85a8a1cce7a1..ea834bf669ed 100644
--- a/contrib/bmake/main.c
+++ b/contrib/bmake/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.540 2021/06/18 12:54:17 rillig Exp $ */
+/* $NetBSD: main.c,v 1.614 2024/04/30 16:13:33 sjg Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -111,8 +111,8 @@
#include "trace.h"
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: main.c,v 1.540 2021/06/18 12:54:17 rillig Exp $");
-#if defined(MAKE_NATIVE) && !defined(lint)
+MAKE_RCSID("$NetBSD: main.c,v 1.614 2024/04/30 16:13:33 sjg Exp $");
+#if defined(MAKE_NATIVE)
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
"The Regents of the University of California. "
"All rights reserved.");
@@ -125,20 +125,20 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
CmdOpts opts;
time_t now; /* Time at start of make */
GNode *defaultNode; /* .DEFAULT node */
-bool allPrecious; /* .PRECIOUS given on line by itself */
+bool allPrecious; /* .PRECIOUS given on a line by itself */
bool deleteOnError; /* .DELETE_ON_ERROR: set */
static int maxJobTokens; /* -j argument */
-bool enterFlagObj; /* -w and objdir != srcdir */
+static bool enterFlagObj; /* -w and objdir != srcdir */
static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
bool doing_depend; /* Set while reading .depend */
static bool jobsRunning; /* true if the jobs might be running */
static const char *tracefile;
-static int ReadMakefile(const char *);
+static bool ReadMakefile(const char *);
static void purge_relative_cached_realpaths(void);
-static bool ignorePWD; /* if we use -C, PWD is meaningless */
+static bool ignorePWD; /* if we use -C, PWD is meaningless */
static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
char curdir[MAXPATHLEN + 1]; /* Startup directory */
const char *progname;
@@ -152,40 +152,31 @@ static HashTable cached_realpaths;
/*
* For compatibility with the POSIX version of MAKEFLAGS that includes
- * all the options without '-', convert 'flags' to '-f -l -a -g -s'.
+ * all the options without '-', convert 'flags' to '-f -l -a -g -s '.
*/
static char *
explode(const char *flags)
{
- size_t len;
- char *nf, *st;
- const char *f;
+ char *exploded, *ep;
+ const char *p;
if (flags == NULL)
return NULL;
- for (f = flags; *f != '\0'; f++)
- if (!ch_isalpha(*f))
- break;
-
- if (*f != '\0')
- return bmake_strdup(flags);
+ for (p = flags; *p != '\0'; p++)
+ if (!ch_isalpha(*p))
+ return bmake_strdup(flags);
- len = strlen(flags);
- st = nf = bmake_malloc(len * 3 + 1);
- while (*flags != '\0') {
- *nf++ = '-';
- *nf++ = *flags++;
- *nf++ = ' ';
+ exploded = bmake_malloc((size_t)(p - flags) * 3 + 1);
+ for (p = flags, ep = exploded; *p != '\0'; p++) {
+ *ep++ = '-';
+ *ep++ = *p;
+ *ep++ = ' ';
}
- *nf = '\0';
- return st;
+ *ep = '\0';
+ return exploded;
}
-/*
- * usage --
- * exit with usage message
- */
MAKE_ATTR_DEAD static void
usage(void)
{
@@ -229,15 +220,14 @@ MainParseArgDebugFile(const char *arg)
fname = bmake_malloc(len + 20);
memcpy(fname, arg, len + 1);
- /* Let the filename be modified by the pid */
- if (strcmp(fname + len - 3, ".%d") == 0)
+ /* Replace the trailing '%d' after '.%d' with the pid. */
+ if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0)
snprintf(fname + len - 2, 20, "%d", getpid());
opts.debug_file = fopen(fname, mode);
if (opts.debug_file == NULL) {
- fprintf(stderr, "Cannot open debug file %s\n",
- fname);
- usage();
+ fprintf(stderr, "Cannot open debug file \"%s\"\n", fname);
+ exit(2);
}
free(fname);
}
@@ -251,83 +241,83 @@ MainParseArgDebug(const char *argvalue)
for (modules = argvalue; *modules != '\0'; modules++) {
switch (*modules) {
case '0': /* undocumented, only intended for tests */
- debug = DEBUG_NONE;
+ memset(&debug, 0, sizeof(debug));
break;
case 'A':
- debug = DEBUG_ALL;
+ memset(&debug, ~0, sizeof(debug));
break;
case 'a':
- debug |= DEBUG_ARCH;
+ debug.DEBUG_ARCH = true;
break;
case 'C':
- debug |= DEBUG_CWD;
+ debug.DEBUG_CWD = true;
break;
case 'c':
- debug |= DEBUG_COND;
+ debug.DEBUG_COND = true;
break;
case 'd':
- debug |= DEBUG_DIR;
+ debug.DEBUG_DIR = true;
break;
case 'e':
- debug |= DEBUG_ERROR;
+ debug.DEBUG_ERROR = true;
break;
case 'f':
- debug |= DEBUG_FOR;
+ debug.DEBUG_FOR = true;
break;
case 'g':
if (modules[1] == '1') {
- debug |= DEBUG_GRAPH1;
+ debug.DEBUG_GRAPH1 = true;
modules++;
} else if (modules[1] == '2') {
- debug |= DEBUG_GRAPH2;
+ debug.DEBUG_GRAPH2 = true;
modules++;
} else if (modules[1] == '3') {
- debug |= DEBUG_GRAPH3;
+ debug.DEBUG_GRAPH3 = true;
modules++;
}
break;
case 'h':
- debug |= DEBUG_HASH;
+ debug.DEBUG_HASH = true;
break;
case 'j':
- debug |= DEBUG_JOB;
+ debug.DEBUG_JOB = true;
break;
case 'L':
opts.strict = true;
break;
case 'l':
- debug |= DEBUG_LOUD;
+ debug.DEBUG_LOUD = true;
break;
case 'M':
- debug |= DEBUG_META;
+ debug.DEBUG_META = true;
break;
case 'm':
- debug |= DEBUG_MAKE;
+ debug.DEBUG_MAKE = true;
break;
case 'n':
- debug |= DEBUG_SCRIPT;
+ debug.DEBUG_SCRIPT = true;
break;
case 'p':
- debug |= DEBUG_PARSE;
+ debug.DEBUG_PARSE = true;
break;
case 's':
- debug |= DEBUG_SUFF;
+ debug.DEBUG_SUFF = true;
break;
case 't':
- debug |= DEBUG_TARG;
+ debug.DEBUG_TARG = true;
break;
case 'V':
opts.debugVflag = true;
break;
case 'v':
- debug |= DEBUG_VAR;
+ debug.DEBUG_VAR = true;
break;
case 'x':
- debug |= DEBUG_SHELL;
+ debug.DEBUG_SHELL = true;
break;
case 'F':
MainParseArgDebugFile(modules + 1);
- goto debug_setbuf;
+ goto finish;
default:
(void)fprintf(stderr,
"%s: illegal argument to d option -- %c\n",
@@ -336,20 +326,15 @@ MainParseArgDebug(const char *argvalue)
}
}
-debug_setbuf:
+finish:
opts.debug = debug;
- /*
- * Make the debug_file unbuffered, and make
- * stdout line buffered (unless debugfile == stdout).
- */
setvbuf(opts.debug_file, NULL, _IONBF, 0);
- if (opts.debug_file != stdout) {
+ if (opts.debug_file != stdout)
setvbuf(stdout, NULL, _IOLBF, 0);
- }
}
-/* Is path relative, or does it contain any relative component "." or ".."? */
+/* Is path relative or does it contain any relative component "." or ".."? */
static bool
IsRelativePath(const char *path)
{
@@ -403,12 +388,6 @@ MainParseArgJobsInternal(const char *argvalue)
}
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;
@@ -419,29 +398,51 @@ MainParseArgJobsInternal(const char *argvalue)
}
static void
-MainParseArgJobs(const char *argvalue)
+MainParseArgJobs(const char *arg)
{
- char *p;
+ const char *p;
+ char *end;
+ char v[12];
forceJobs = true;
- opts.maxJobs = (int)strtol(argvalue, &p, 0);
+ opts.maxJobs = (int)strtol(arg, &end, 0);
+ p = end;
+#ifdef _SC_NPROCESSORS_ONLN
+ if (*p != '\0') {
+ double d;
+
+ if (*p == 'C')
+ d = (opts.maxJobs > 0) ? opts.maxJobs : 1;
+ else if (*p == '.') {
+ d = strtod(arg, &end);
+ p = end;
+ } else
+ d = 0.0;
+ if (d > 0.0) {
+ p = "";
+ opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN);
+ opts.maxJobs = (int)(d * (double)opts.maxJobs);
+ }
+ }
+#endif
if (*p != '\0' || opts.maxJobs < 1) {
(void)fprintf(stderr,
- "%s: illegal argument to -j -- must be positive integer!\n",
- progname);
+ "%s: argument '%s' to option '-j' "
+ "must be a positive number\n",
+ progname, arg);
exit(2); /* Not 1 so -q can distinguish error */
}
+ snprintf(v, sizeof(v), "%d", opts.maxJobs);
Global_Append(MAKEFLAGS, "-j");
- Global_Append(MAKEFLAGS, argvalue);
- Global_Set(".MAKE.JOBS", argvalue);
+ Global_Append(MAKEFLAGS, v);
+ Global_Set(".MAKE.JOBS", v);
maxJobTokens = opts.maxJobs;
}
static void
MainParseArgSysInc(const char *argvalue)
{
- /* look for magic parent directory search string */
- if (strncmp(".../", argvalue, 4) == 0) {
+ if (strncmp(argvalue, ".../", 4) == 0) {
char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4);
if (found_path == NULL)
return;
@@ -452,10 +453,11 @@ MainParseArgSysInc(const char *argvalue)
}
Global_Append(MAKEFLAGS, "-m");
Global_Append(MAKEFLAGS, argvalue);
+ Dir_SetSYSPATH();
}
static bool
-MainParseArg(char c, const char *argvalue)
+MainParseOption(char c, const char *argvalue)
{
switch (c) {
case '\0':
@@ -463,19 +465,20 @@ MainParseArg(char c, const char *argvalue)
case 'B':
opts.compatMake = true;
Global_Append(MAKEFLAGS, "-B");
- Global_Set(MAKE_MODE, "compat");
+ Global_Set(".MAKE.MODE", "compat");
break;
case 'C':
MainParseArgChdir(argvalue);
break;
case 'D':
- if (argvalue[0] == '\0') return false;
- Global_SetExpand(argvalue, "1");
+ if (argvalue[0] == '\0')
+ return false;
+ Var_SetExpand(SCOPE_GLOBAL, argvalue, "1");
Global_Append(MAKEFLAGS, "-D");
Global_Append(MAKEFLAGS, argvalue);
break;
case 'I':
- Parse_AddIncludeDir(argvalue);
+ SearchPath_Add(parseIncPath, argvalue);
Global_Append(MAKEFLAGS, "-I");
Global_Append(MAKEFLAGS, argvalue);
break;
@@ -506,7 +509,7 @@ MainParseArg(char c, const char *argvalue)
break;
case 'W':
opts.parseWarnFatal = true;
- /* XXX: why no Var_Append? */
+ /* XXX: why no Global_Append? */
break;
case 'X':
opts.varNoExportEnv = true;
@@ -549,7 +552,7 @@ MainParseArg(char c, const char *argvalue)
Global_Append(MAKEFLAGS, "-n");
break;
case 'q':
- opts.queryFlag = true;
+ opts.query = true;
/* Kind of nonsensical, wot? */
Global_Append(MAKEFLAGS, "-q");
break;
@@ -558,11 +561,11 @@ MainParseArg(char c, const char *argvalue)
Global_Append(MAKEFLAGS, "-r");
break;
case 's':
- opts.beSilent = true;
+ opts.silent = true;
Global_Append(MAKEFLAGS, "-s");
break;
case 't':
- opts.touchFlag = true;
+ opts.touch = true;
Global_Append(MAKEFLAGS, "-t");
break;
case 'w':
@@ -570,7 +573,6 @@ MainParseArg(char c, const char *argvalue)
Global_Append(MAKEFLAGS, "-w");
break;
default:
- case '?':
usage();
}
return true;
@@ -622,7 +624,10 @@ rearg:
/* '-' found at some earlier point */
optspec = strchr(optspecs, c);
if (c != '\0' && optspec != NULL && optspec[1] == ':') {
- /* -<something> found, and <something> should have an arg */
+ /*
+ * -<something> found, and <something> should have an
+ * argument
+ */
inOption = false;
arginc = 1;
argvalue = optscan;
@@ -644,7 +649,7 @@ rearg:
dashDash = true;
break;
default:
- if (!MainParseArg(c, argvalue))
+ if (!MainParseOption(c, argvalue))
goto noarg;
}
argv += arginc;
@@ -657,10 +662,7 @@ rearg:
* on the end of the "create" list.
*/
for (; argc > 1; argv++, argc--) {
- VarAssign var;
- if (Parse_IsVar(argv[1], &var)) {
- Parse_Var(&var, SCOPE_CMDLINE);
- } else {
+ if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) {
if (argv[1][0] == '\0')
Punt("illegal (null) argument.");
if (argv[1][0] == '-' && !dashDash)
@@ -687,32 +689,18 @@ Main_ParseArgLine(const char *line)
{
Words words;
char *buf;
+ const char *p;
if (line == NULL)
return;
- /* XXX: don't use line as an iterator variable */
- for (; *line == ' '; line++)
+ for (p = line; *p == ' '; p++)
continue;
- if (line[0] == '\0')
+ if (p[0] == '\0')
return;
-#ifndef POSIX
- {
- /*
- * $MAKE may simply be naming the make(1) binary
- */
- char *cp;
-
- if (!(cp = strrchr(line, '/')))
- cp = line;
- if ((cp = strstr(cp, "make")) &&
- strcmp(cp, "make") == 0)
- return;
- }
-#endif
{
FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE");
- buf = str_concat3(argv0.str, " ", line);
+ buf = str_concat3(argv0.str, " ", p);
FStr_Done(&argv0);
}
@@ -735,7 +723,6 @@ Main_SetObjdir(bool writable, const char *fmt, ...)
char *path;
char buf[MAXPATHLEN + 1];
char buf2[MAXPATHLEN + 1];
- bool rc = false;
va_list ap;
va_start(ap, fmt);
@@ -743,75 +730,62 @@ Main_SetObjdir(bool writable, const char *fmt, ...)
va_end(ap);
if (path[0] != '/') {
- snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path);
- path = buf2;
+ if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN)
+ path = buf2;
+ else
+ return false;
}
/* look for the directory and try to chdir there */
- if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
- if ((writable && access(path, W_OK) != 0) ||
- (chdir(path) != 0)) {
- (void)fprintf(stderr, "%s warning: %s: %s.\n",
- progname, path, strerror(errno));
- } else {
- snprintf(objdir, sizeof objdir, "%s", path);
- Global_Set(".OBJDIR", objdir);
- setenv("PWD", objdir, 1);
- Dir_InitDot();
- purge_relative_cached_realpaths();
- rc = true;
- if (opts.enterFlag && strcmp(objdir, curdir) != 0)
- enterFlagObj = true;
- }
+ if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
+ return false;
+
+ if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
+ (void)fprintf(stderr, "%s: warning: %s: %s.\n",
+ progname, path, strerror(errno));
+ return false;
}
- return rc;
+ snprintf(objdir, sizeof objdir, "%s", path);
+ Global_Set(".OBJDIR", objdir);
+ setenv("PWD", objdir, 1);
+ Dir_InitDot();
+ purge_relative_cached_realpaths();
+ if (opts.enterFlag && strcmp(objdir, curdir) != 0)
+ enterFlagObj = true;
+ return true;
}
static bool
SetVarObjdir(bool writable, const char *var, const char *suffix)
{
FStr path = Var_Value(SCOPE_CMDLINE, var);
- FStr xpath;
if (path.str == NULL || path.str[0] == '\0') {
FStr_Done(&path);
return false;
}
- /* expand variable substitutions */
- xpath = FStr_InitRefer(path.str);
- if (strchr(path.str, '$') != 0) {
- char *expanded;
- (void)Var_Subst(path.str, SCOPE_GLOBAL, VARE_WANTRES, &expanded);
- /* TODO: handle errors */
- xpath = FStr_InitOwn(expanded);
- }
+ Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES);
- (void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix);
+ (void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
- FStr_Done(&xpath);
FStr_Done(&path);
return true;
}
/*
- * Splits str into words, adding them to the list.
+ * Splits str into words (in-place, modifying it), adding them to the list.
* The string must be kept alive as long as the list.
*/
-int
-str2Lst_Append(StringList *lp, char *str)
+void
+AppendWords(StringList *lp, char *str)
{
- char *cp;
- int n;
-
+ char *p;
const char *sep = " \t";
- for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) {
- Lst_Append(lp, cp);
- n++;
- }
- return n;
+ for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep))
+ Lst_Append(lp, p);
}
#ifdef SIGINFO
@@ -834,9 +808,8 @@ siginfo(int signo MAKE_ATTR_UNUSED)
static void
MakeMode(void)
{
- char *mode;
-
- (void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode);
+ char *mode = Var_Subst("${.MAKE.MODE:tl}",
+ SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
if (mode[0] != '\0') {
@@ -848,6 +821,8 @@ MakeMode(void)
if (strstr(mode, "meta") != NULL)
meta_mode_init(mode);
#endif
+ if (strstr(mode, "randomize-targets") != NULL)
+ opts.randomizeTargets = true;
}
free(mode);
@@ -857,20 +832,18 @@ static void
PrintVar(const char *varname, bool expandVars)
{
if (strchr(varname, '$') != NULL) {
- char *evalue;
- (void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
+ char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
printf("%s\n", evalue);
- bmake_free(evalue);
+ free(evalue);
} else if (expandVars) {
char *expr = str_concat3("${", varname, "}");
- char *evalue;
- (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
+ char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
free(expr);
printf("%s\n", evalue);
- bmake_free(evalue);
+ free(evalue);
} else {
FStr value = Var_Value(SCOPE_GLOBAL, varname);
@@ -892,7 +865,7 @@ GetBooleanExpr(const char *expr, bool fallback)
char *value;
bool res;
- (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value);
+ value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
res = ParseBoolean(value, fallback);
free(value);
@@ -923,7 +896,7 @@ static bool
runTargets(void)
{
GNodeList targs = LST_INIT; /* target nodes to create */
- bool outOfDate; /* false if all targets up to date */
+ bool outOfDate; /* false if all targets up to date */
/*
* Have now read the entire graph and need to make a list of
@@ -944,7 +917,7 @@ runTargets(void)
* (to prevent the .BEGIN from being executed should
* it exist).
*/
- if (!opts.queryFlag) {
+ if (!opts.query) {
Job_Init();
jobsRunning = true;
}
@@ -952,11 +925,7 @@ runTargets(void)
/* Traverse the graph, checking on all the targets */
outOfDate = Make_Run(&targs);
} else {
- /*
- * Compat_Init will take care of creating all the
- * targets as well as initializing the module.
- */
- Compat_Run(&targs);
+ Compat_MakeAll(&targs);
outOfDate = false;
}
Lst_Done(&targs); /* Don't free the targets themselves. */
@@ -964,9 +933,9 @@ runTargets(void)
}
/*
- * 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.
+ * Set up the .TARGETS variable to contain the list of targets to be created.
+ * If none specified, make the variable empty for now, the parser will fill
+ * in the default or .MAIN target later.
*/
static void
InitVarTargets(void)
@@ -1052,36 +1021,27 @@ InitVarMachineArch(void)
#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.
- *
- * XXX: Make no longer has "local" and "remote" mode. Is this code still
- * necessary?
- *
* 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
+ * here. That is, sitting at a shell prompt (shell that provides $PWD)
+ * or via subdir.mk, in which case it's 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.
+ * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression.
*/
static void
HandlePWD(const struct stat *curdir_st)
{
char *pwd;
- FStr prefix, makeobjdir;
+ FStr makeobjdir;
struct stat pwd_st;
if (ignorePWD || (pwd = getenv("PWD")) == NULL)
return;
- prefix = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX");
- if (prefix.str != NULL) {
- FStr_Done(&prefix);
+ if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"))
return;
- }
makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR");
if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL)
@@ -1098,13 +1058,13 @@ ignore_pwd:
#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.
+ * 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.
+ * 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)
@@ -1127,10 +1087,15 @@ InitObjdir(const char *machine, const char *machine_arch)
static void
UnlimitFiles(void)
{
-#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE))
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
rl.rlim_cur != rl.rlim_max) {
+#ifdef BMAKE_NOFILE_MAX
+ if (BMAKE_NOFILE_MAX < rl.rlim_max)
+ rl.rlim_cur = BMAKE_NOFILE_MAX;
+ else
+#endif
rl.rlim_cur = rl.rlim_max;
(void)setrlimit(RLIMIT_NOFILE, &rl);
}
@@ -1141,7 +1106,7 @@ static void
CmdOpts_Init(void)
{
opts.compatMake = false;
- opts.debug = DEBUG_NONE;
+ memset(&opts.debug, 0, sizeof(opts.debug));
/* opts.debug_file has already been initialized earlier */
opts.strict = false;
opts.debugVflag = false;
@@ -1152,10 +1117,10 @@ CmdOpts_Init(void)
opts.keepgoing = false; /* Stop on error */
opts.noRecursiveExecute = false; /* Execute all .MAKE targets */
opts.noExecute = false; /* Execute all commands */
- opts.queryFlag = false;
+ opts.query = false;
opts.noBuiltins = false; /* Read the built-in rules */
- opts.beSilent = false; /* Print commands as executed */
- opts.touchFlag = false;
+ opts.silent = false; /* Print commands as executed */
+ opts.touch = false;
opts.printVars = PVM_NONE;
Lst_Init(&opts.variables);
opts.parseWarnFatal = false;
@@ -1197,7 +1162,7 @@ static void
InitDefSysIncPath(char *syspath)
{
static char defsyspath[] = _PATH_DEFSYSPATH;
- char *start, *cp;
+ char *start, *p;
/*
* If no user-supplied system path was given (through the -m option)
@@ -1209,11 +1174,13 @@ InitDefSysIncPath(char *syspath)
else
syspath = bmake_strdup(syspath);
- for (start = syspath; *start != '\0'; start = cp) {
- for (cp = start; *cp != '\0' && *cp != ':'; cp++)
+ /* do NOT search .CURDIR first for .include <makefile> */
+ SearchPath_Add(defSysIncPath, ".DOTLAST");
+ for (start = syspath; *start != '\0'; start = p) {
+ for (p = start; *p != '\0' && *p != ':'; p++)
continue;
- if (*cp == ':')
- *cp++ = '\0';
+ if (*p == ':')
+ *p++ = '\0';
/* look for magic parent directory search string */
if (strncmp(start, ".../", 4) == 0) {
@@ -1245,16 +1212,14 @@ ReadBuiltinRules(void)
Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK);
for (ln = sysMkFiles.first; ln != NULL; ln = ln->next)
- if (ReadMakefile(ln->datum) == 0)
+ if (ReadMakefile(ln->datum))
break;
if (ln == NULL)
Fatal("%s: cannot open %s.",
progname, (const char *)sysMkFiles.first->datum);
- /* Free the list nodes but not the actual filenames since these may
- * still be used in GNodes. */
- Lst_Done(&sysMkFiles);
+ Lst_DoneFree(&sysMkFiles);
}
static void
@@ -1267,7 +1232,7 @@ InitMaxJobs(void)
!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
return;
- (void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value);
+ value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
n = (int)strtol(value, NULL, 0);
if (n < 1) {
@@ -1302,33 +1267,33 @@ InitVpath(void)
if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
return;
- (void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath);
+ vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
path = vpath;
do {
- char *cp;
+ char *p;
/* skip to end of directory */
- for (cp = path; *cp != ':' && *cp != '\0'; cp++)
+ for (p = path; *p != ':' && *p != '\0'; p++)
continue;
/* Save terminator character so know when to stop */
- savec = *cp;
- *cp = '\0';
+ savec = *p;
+ *p = '\0';
/* Add directory to search path */
(void)SearchPath_Add(&dirSearchPath, path);
- *cp = savec;
- path = cp + 1;
+ *p = savec;
+ path = p + 1;
} while (savec == ':');
free(vpath);
}
static void
-ReadAllMakefiles(StringList *makefiles)
+ReadAllMakefiles(const StringList *makefiles)
{
StringListNode *ln;
for (ln = makefiles->first; ln != NULL; ln = ln->next) {
const char *fname = ln->datum;
- if (ReadMakefile(fname) != 0)
+ if (!ReadMakefile(fname))
Fatal("%s: cannot open %s.", progname, fname);
}
}
@@ -1336,23 +1301,19 @@ ReadAllMakefiles(StringList *makefiles)
static void
ReadFirstDefaultMakefile(void)
{
+ StringList makefiles = LST_INIT;
StringListNode *ln;
- char *prefs;
-
- (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}",
- SCOPE_CMDLINE, VARE_WANTRES, &prefs);
+ char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
+ SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
- /* XXX: This should use a local list instead of opts.makefiles
- * since these makefiles do not come from the command line. They
- * also have different semantics in that only the first file that
- * is found is processed. See ReadAllMakefiles. */
- (void)str2Lst_Append(&opts.makefiles, prefs);
+ AppendWords(&makefiles, prefs);
- for (ln = opts.makefiles.first; ln != NULL; ln = ln->next)
- if (ReadMakefile(ln->datum) == 0)
+ for (ln = makefiles.first; ln != NULL; ln = ln->next)
+ if (ReadMakefile(ln->datum))
break;
+ Lst_Done(&makefiles);
free(prefs);
}
@@ -1373,6 +1334,7 @@ main_Init(int argc, char **argv)
/* default to writing debug to stderr */
opts.debug_file = stderr;
+ Str_Intern_Init();
HashTable_Init(&cached_realpaths);
#ifdef SIGINFO
@@ -1391,39 +1353,37 @@ main_Init(int argc, char **argv)
exit(2);
}
- /*
- * Get the name of this type of MACHINE from utsname
- * so we can share an executable for similar machines.
- * (i.e. m68k: amiga hp300, mac68k, sun3, ...)
- *
- * Note that both MACHINE and MACHINE_ARCH are decided at
- * run-time.
- */
machine = InitVarMachine(&utsname);
machine_arch = InitVarMachineArch();
myPid = getpid(); /* remember this for vFork() */
- /*
- * Just in case MAKEOBJDIR wants us to do something tricky.
- */
+ /* Just in case MAKEOBJDIR wants us to do something tricky. */
Targ_Init();
Var_Init();
- Global_Set(".MAKE.OS", utsname.sysname);
+#ifdef FORCE_MAKE_OS
+ Global_Set_ReadOnly(".MAKE.OS", FORCE_MAKE_OS);
+#else
+ Global_Set_ReadOnly(".MAKE.OS", utsname.sysname);
+#endif
Global_Set("MACHINE", machine);
Global_Set("MACHINE_ARCH", machine_arch);
#ifdef MAKE_VERSION
Global_Set("MAKE_VERSION", MAKE_VERSION);
#endif
- Global_Set(".newline", "\n"); /* handy for :@ loops */
- /*
- * This is the traditional preference for makefiles.
- */
+ Global_Set_ReadOnly(".newline", "\n");
#ifndef MAKEFILE_PREFERENCE_LIST
+ /* This is the traditional preference for makefiles. */
# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
#endif
- Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST);
- Global_Set(MAKE_DEPENDFILE, ".depend");
+ Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
+ Global_Set(".MAKE.DEPENDFILE", ".depend");
+ /* Tell makefiles like jobs.mk whether we support -jC */
+#ifdef _SC_NPROCESSORS_ONLN
+ Global_Set_ReadOnly(".MAKE.JOBS.C", "yes");
+#else
+ Global_Set_ReadOnly(".MAKE.JOBS.C", "no");
+#endif
CmdOpts_Init();
allPrecious = false; /* Remove targets when interrupted */
@@ -1448,29 +1408,28 @@ main_Init(int argc, char **argv)
Parse_Init();
InitVarMake(argv[0]);
Global_Set(MAKEFLAGS, "");
- Global_Set(MAKEOVERRIDES, "");
+ Global_Set(".MAKEOVERRIDES", "");
Global_Set("MFLAGS", "");
Global_Set(".ALLTARGETS", "");
- /* some makefiles need to know this */
- Var_Set(SCOPE_CMDLINE, MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV);
+ Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
/* Set some other useful variables. */
{
- char tmp[64], *ep = getenv(MAKE_LEVEL_ENV);
+ char buf[64], *ep = getenv(MAKE_LEVEL_ENV);
makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0;
if (makelevel < 0)
makelevel = 0;
- snprintf(tmp, sizeof tmp, "%d", makelevel);
- Global_Set(MAKE_LEVEL, tmp);
- snprintf(tmp, sizeof tmp, "%u", myPid);
- Global_Set(".MAKE.PID", tmp);
- snprintf(tmp, sizeof tmp, "%u", getppid());
- Global_Set(".MAKE.PPID", tmp);
- snprintf(tmp, sizeof tmp, "%u", getuid());
- Global_Set(".MAKE.UID", tmp);
- snprintf(tmp, sizeof tmp, "%u", getgid());
- Global_Set(".MAKE.GID", tmp);
+ snprintf(buf, sizeof buf, "%d", makelevel);
+ Global_Set(".MAKE.LEVEL", buf);
+ snprintf(buf, sizeof buf, "%u", myPid);
+ Global_Set_ReadOnly(".MAKE.PID", buf);
+ snprintf(buf, sizeof buf, "%u", getppid());
+ Global_Set_ReadOnly(".MAKE.PPID", buf);
+ snprintf(buf, sizeof buf, "%u", getuid());
+ Global_Set_ReadOnly(".MAKE.UID", buf);
+ snprintf(buf, sizeof buf, "%u", getgid());
+ Global_Set_ReadOnly(".MAKE.GID", buf);
}
if (makelevel > 0) {
char pn[1024];
@@ -1483,25 +1442,12 @@ main_Init(int argc, char **argv)
#endif
Dir_Init();
- /*
- * First snag any flags out of the MAKE environment variable.
- * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's
- * in a different format).
- */
-#ifdef POSIX
{
- char *p1 = explode(getenv("MAKEFLAGS"));
- Main_ParseArgLine(p1);
- free(p1);
+ char *makeflags = explode(getenv("MAKEFLAGS"));
+ Main_ParseArgLine(makeflags);
+ free(makeflags);
}
-#else
- Main_ParseArgLine(getenv("MAKE"));
-#endif
- /*
- * Find where we are (now).
- * We take care of PWD for the automounter below...
- */
if (getcwd(curdir, MAXPATHLEN) == NULL) {
(void)fprintf(stderr, "%s: getcwd: %s.\n",
progname, strerror(errno));
@@ -1513,9 +1459,6 @@ main_Init(int argc, char **argv)
if (opts.enterFlag)
printf("%s: Entering directory `%s'\n", progname, curdir);
- /*
- * Verify that cwd is sane.
- */
if (stat(curdir, &sa) == -1) {
(void)fprintf(stderr, "%s: %s: %s.\n",
progname, curdir, strerror(errno));
@@ -1529,10 +1472,6 @@ main_Init(int argc, char **argv)
InitObjdir(machine, machine_arch);
- /*
- * Initialize archive, target and suffix modules in preparation for
- * parsing the makefile(s)
- */
Arch_Init();
Suff_Init();
Trace_Init(tracefile);
@@ -1555,9 +1494,14 @@ static void
main_ReadFiles(void)
{
+ if (Lst_IsEmpty(&sysIncPath->dirs))
+ SearchPath_AddAll(sysIncPath, defSysIncPath);
+
+ Dir_SetSYSPATH();
if (!opts.noBuiltins)
ReadBuiltinRules();
+ posix_state = PS_MAYBE_NEXT_LINE;
if (!Lst_IsEmpty(&opts.makefiles))
ReadAllMakefiles(&opts.makefiles);
else
@@ -1570,8 +1514,8 @@ main_PrepareMaking(void)
{
/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
- (void)Var_Subst("${.MAKE.DEPENDFILE}",
- SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile);
+ makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
+ SCOPE_CMDLINE, VARE_WANTRES);
if (makeDependfile[0] != '\0') {
/* TODO: handle errors */
doing_depend = true;
@@ -1593,10 +1537,6 @@ main_PrepareMaking(void)
InitMaxJobs();
- /*
- * Be compatible if the user did not specify -j and did not explicitly
- * turn compatibility on.
- */
if (!opts.compatMake && !forceJobs)
opts.compatMake = true;
@@ -1648,16 +1588,11 @@ static void
main_CleanUp(void)
{
#ifdef CLEANUP
- Lst_DoneCall(&opts.variables, free);
- /*
- * Don't free the actual strings from opts.makefiles, they may be
- * used in GNodes.
- */
- Lst_Done(&opts.makefiles);
- Lst_DoneCall(&opts.create, free);
+ Lst_DoneFree(&opts.variables);
+ Lst_DoneFree(&opts.makefiles);
+ Lst_DoneFree(&opts.create);
#endif
- /* print the graph now it's been processed if the user requested it */
if (DEBUG(GRAPH2))
Targ_PrintGraph(2);
@@ -1679,13 +1614,14 @@ main_CleanUp(void)
Dir_End();
Job_End();
Trace_End();
+ Str_Intern_End();
}
/* Determine the exit code. */
static int
main_Exit(bool outOfDate)
{
- if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0))
+ if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0))
return 2; /* Not 1 so -q can distinguish error */
return outOfDate ? 1 : 0;
}
@@ -1705,18 +1641,16 @@ main(int argc, char **argv)
/*
* Open and parse the given makefile, with all its side effects.
- *
- * Results:
- * 0 if ok. -1 if couldn't open file.
+ * Return false if the file could not be opened.
*/
-static int
+static bool
ReadMakefile(const char *fname)
{
int fd;
char *name, *path = NULL;
if (strcmp(fname, "-") == 0) {
- Parse_File(NULL /*stdin*/, -1);
+ Parse_File("(stdin)", -1);
Var_Set(SCOPE_INTERNAL, "MAKEFILE", "");
} else {
/* if we've chdir'd, rebuild the path name */
@@ -1745,13 +1679,13 @@ ReadMakefile(const char *fname)
name = Dir_FindFile(fname, parseIncPath);
if (name == NULL) {
SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs)
- ? defSysIncPath : sysIncPath;
+ ? defSysIncPath : sysIncPath;
name = Dir_FindFile(fname, sysInc);
}
if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
free(name);
free(path);
- return -1;
+ return false;
}
fname = name;
/*
@@ -1765,154 +1699,153 @@ found:
Parse_File(fname, fd);
}
free(path);
- return 0;
+ return true;
}
/*
- * Cmd_Exec --
- * Execute the command in cmd, and return the output of that command
- * in a string. In the output, newlines are replaced with spaces.
- *
- * Results:
- * A string containing the output of the command, or the empty string.
- * *errfmt returns a format string describing the command failure,
- * if any, using a single %s conversion specification.
- *
- * Side Effects:
- * The string must be freed by the caller.
+ * Execute the command in cmd, and return its output (only stdout, not
+ * stderr, possibly empty). In the output, replace newlines with spaces.
*/
char *
-Cmd_Exec(const char *cmd, const char **errfmt)
+Cmd_Exec(const char *cmd, char **error)
{
- const char *args[4]; /* Args for invoking the shell */
+ const char *args[4]; /* Arguments for invoking the shell */
int pipefds[2];
int cpid; /* Child PID */
int pid; /* PID from wait() */
int status; /* command exit status */
Buffer buf; /* buffer to store the result */
ssize_t bytes_read;
- char *res; /* result */
- size_t res_len;
- char *cp;
- int savederr; /* saved errno */
-
- *errfmt = NULL;
+ char *output;
+ char *p;
+ int saved_errno;
+ char cmd_file[MAXPATHLEN];
+ size_t cmd_len;
+ int cmd_fd = -1;
- if (shellName == NULL)
+ if (shellPath == NULL)
Shell_Init();
- /*
- * Set up arguments for shell
- */
+
+ cmd_len = strlen(cmd);
+ if (cmd_len > 1000) {
+ cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file));
+ if (cmd_fd >= 0) {
+ ssize_t n;
+
+ n = write(cmd_fd, cmd, cmd_len);
+ close(cmd_fd);
+ if (n < (ssize_t)cmd_len) {
+ unlink(cmd_file);
+ cmd_fd = -1;
+ }
+ }
+ }
+
args[0] = shellName;
- args[1] = "-c";
- args[2] = cmd;
- args[3] = NULL;
+ if (cmd_fd >= 0) {
+ args[1] = cmd_file;
+ args[2] = NULL;
+ } else {
+ cmd_file[0] = '\0';
+ args[1] = "-c";
+ args[2] = cmd;
+ args[3] = NULL;
+ }
+ DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
- /*
- * Open a pipe for fetching its output
- */
if (pipe(pipefds) == -1) {
- *errfmt = "Couldn't create pipe for \"%s\"";
- goto bad;
+ *error = str_concat3(
+ "Couldn't create pipe for \"", cmd, "\"");
+ return bmake_strdup("");
}
- Var_ReexportVars();
+ Var_ReexportVars(SCOPE_GLOBAL);
- /*
- * Fork
- */
switch (cpid = vfork()) {
case 0:
- (void)close(pipefds[0]); /* Close input side of pipe */
-
- /*
- * Duplicate the output stream to the shell's output, then
- * shut the extra thing down. Note we don't fetch the error
- * stream...why not? Why?
- */
- (void)dup2(pipefds[1], 1);
+ (void)close(pipefds[0]);
+ (void)dup2(pipefds[1], STDOUT_FILENO);
(void)close(pipefds[1]);
(void)execv(shellPath, UNCONST(args));
_exit(1);
- /*NOTREACHED*/
+ /* NOTREACHED */
case -1:
- *errfmt = "Couldn't exec \"%s\"";
- goto bad;
-
- default:
- (void)close(pipefds[1]); /* No need for the writing half */
-
- savederr = 0;
- Buf_Init(&buf);
-
- do {
- char result[BUFSIZ];
- bytes_read = read(pipefds[0], result, sizeof result);
- if (bytes_read > 0)
- Buf_AddBytes(&buf, result, (size_t)bytes_read);
- } while (bytes_read > 0 ||
- (bytes_read == -1 && errno == EINTR));
- if (bytes_read == -1)
- savederr = errno;
-
- (void)close(pipefds[0]); /* Close the input side of the pipe. */
-
- /* Wait for the process to exit. */
- while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
- JobReapChild(pid, status, false);
-
- res_len = buf.len;
- res = Buf_DoneData(&buf);
-
- if (savederr != 0)
- *errfmt = "Couldn't read shell's output for \"%s\"";
-
- if (WIFSIGNALED(status))
- *errfmt = "\"%s\" exited on a signal";
- else if (WEXITSTATUS(status) != 0)
- *errfmt = "\"%s\" returned non-zero status";
-
- /* Convert newlines to spaces. A final newline is just stripped */
- if (res_len > 0 && res[res_len - 1] == '\n')
- res[res_len - 1] = '\0';
- for (cp = res; *cp != '\0'; cp++)
- if (*cp == '\n')
- *cp = ' ';
- break;
+ *error = str_concat3("Couldn't exec \"", cmd, "\"");
+ return bmake_strdup("");
}
- return res;
-bad:
- return bmake_strdup("");
+
+ (void)close(pipefds[1]); /* No need for the writing half */
+
+ saved_errno = 0;
+ Buf_Init(&buf);
+
+ do {
+ char result[BUFSIZ];
+ bytes_read = read(pipefds[0], result, sizeof result);
+ if (bytes_read > 0)
+ Buf_AddBytes(&buf, result, (size_t)bytes_read);
+ } while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR));
+ if (bytes_read == -1)
+ saved_errno = errno;
+
+ (void)close(pipefds[0]); /* Close the input side of the pipe. */
+
+ while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0)
+ JobReapChild(pid, status, false);
+
+ if (Buf_EndsWith(&buf, '\n'))
+ buf.data[buf.len - 1] = '\0';
+
+ output = Buf_DoneData(&buf);
+ for (p = output; *p != '\0'; p++)
+ if (*p == '\n')
+ *p = ' ';
+
+ if (WIFSIGNALED(status))
+ *error = str_concat3("\"", cmd, "\" exited on a signal");
+ else if (WEXITSTATUS(status) != 0)
+ *error = str_concat3(
+ "\"", cmd, "\" returned non-zero status");
+ else if (saved_errno != 0)
+ *error = str_concat3(
+ "Couldn't read shell's output for \"", cmd, "\"");
+ else
+ *error = NULL;
+ if (cmd_file[0] != '\0')
+ unlink(cmd_file);
+ return output;
}
/*
* Print a printf-style error message.
*
- * In default mode, this error message has no consequences, in particular it
- * does not affect the exit status. Only in lint mode (-dL) it does.
+ * In default mode, this error message has no consequences, for compatibility
+ * reasons, in particular it does not affect the exit status. Only in lint
+ * mode (-dL) it does.
*/
void
Error(const char *fmt, ...)
{
va_list ap;
- FILE *err_file;
+ FILE *f;
- err_file = opts.debug_file;
- if (err_file == stdout)
- err_file = stderr;
+ f = opts.debug_file;
+ if (f == stdout)
+ f = stderr;
(void)fflush(stdout);
+
for (;;) {
+ fprintf(f, "%s: ", progname);
va_start(ap, fmt);
- fprintf(err_file, "%s: ", progname);
- (void)vfprintf(err_file, fmt, ap);
+ (void)vfprintf(f, fmt, ap);
va_end(ap);
- (void)fprintf(err_file, "\n");
- (void)fflush(err_file);
- if (err_file == stderr)
+ (void)fprintf(f, "\n");
+ (void)fflush(f);
+ if (f == stderr)
break;
- err_file = stderr;
+ f = stderr;
}
main_errors++;
}
@@ -1933,13 +1866,15 @@ Fatal(const char *fmt, ...)
Job_Wait();
(void)fflush(stdout);
+ fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
+ PrintStackTrace(true);
- PrintOnError(NULL, NULL);
+ PrintOnError(NULL, "\n");
if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
Targ_PrintGraph(2);
@@ -1956,15 +1891,15 @@ Punt(const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
(void)fflush(stdout);
(void)fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt);
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
- PrintOnError(NULL, NULL);
+ PrintOnError(NULL, "\n");
DieHorribly();
}
@@ -1994,12 +1929,8 @@ Finish(int errs)
Fatal("%d error%s", errs, errs == 1 ? "" : "s");
}
-/*
- * eunlink --
- * Remove a file carefully, avoiding directories.
- */
int
-eunlink(const char *file)
+unlink_file(const char *file)
{
struct stat st;
@@ -2007,6 +1938,10 @@ eunlink(const char *file)
return -1;
if (S_ISDIR(st.st_mode)) {
+ /*
+ * POSIX says for unlink: "The path argument shall not name
+ * a directory unless [...]".
+ */
errno = EISDIR;
return -1;
}
@@ -2020,6 +1955,7 @@ write_all(int fd, const void *data, size_t n)
while (n > 0) {
ssize_t written = write(fd, mem, n);
+ /* XXX: Should this EAGAIN be EINTR? */
if (written == -1 && errno == EAGAIN)
continue;
if (written == -1)
@@ -2029,10 +1965,7 @@ write_all(int fd, const void *data, size_t n)
}
}
-/*
- * execDie --
- * Print why exec failed, avoiding stdio.
- */
+/* Print why exec failed, avoiding stdio. */
void MAKE_ATTR_DEAD
execDie(const char *af, const char *av)
{
@@ -2054,28 +1987,29 @@ execDie(const char *af, const char *av)
_exit(1);
}
-/* purge any relative paths */
static void
purge_relative_cached_realpaths(void)
{
- HashEntry *he, *nhe;
+ HashEntry *he, *next;
HashIter hi;
HashIter_Init(&hi, &cached_realpaths);
he = HashIter_Next(&hi);
while (he != NULL) {
- nhe = HashIter_Next(&hi);
+ next = HashIter_Next(&hi);
if (he->key[0] != '/') {
DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
HashTable_DeleteEntry(&cached_realpaths, he);
- /* XXX: What about the allocated he->value? Either
- * free them or document why they cannot be freed. */
+ /*
+ * XXX: What about the allocated he->value? Either
+ * free them or document why they cannot be freed.
+ */
}
- he = nhe;
+ he = next;
}
}
-char *
+const char *
cached_realpath(const char *pathname, char *resolved)
{
const char *rp;
@@ -2127,10 +2061,13 @@ static void
SetErrorVars(GNode *gn)
{
StringListNode *ln;
+ char sts[16];
/*
* We can print this even if there is no .ERROR target.
*/
+ snprintf(sts, sizeof(sts), "%d", gn->exit_status);
+ Global_Set(".ERROR_EXIT", sts);
Global_Set(".ERROR_TARGET", gn->name);
Global_Delete(".ERROR_CMD");
@@ -2160,9 +2097,7 @@ PrintOnError(GNode *gn, const char *msg)
if (errorNode != NULL)
return; /* we've been here! */
- if (msg != NULL)
- printf("%s", msg);
- printf("\n%s: stopped in %s\n", progname, curdir);
+ printf("%s%s: stopped in %s\n", msg, progname, curdir);
/* we generally want to keep quiet if a sub-make died */
if (shouldDieQuietly(gn, -1))
@@ -2172,9 +2107,9 @@ PrintOnError(GNode *gn, const char *msg)
SetErrorVars(gn);
{
- char *errorVarsValues;
- (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
- SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues);
+ char *errorVarsValues = Var_Subst(
+ "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
+ SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
printf("%s", errorVarsValues);
free(errorVarsValues);
@@ -2196,23 +2131,18 @@ void
Main_ExportMAKEFLAGS(bool first)
{
static bool once = true;
- const char *expr;
- char *s;
+ char *flags;
if (once != first)
return;
once = false;
- expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
- (void)Var_Subst(expr, SCOPE_CMDLINE, VARE_WANTRES, &s);
+ flags = Var_Subst(
+ "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
+ SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
- if (s[0] != '\0') {
-#ifdef POSIX
- setenv("MAKEFLAGS", s, 1);
-#else
- setenv("MAKE", s, 1);
-#endif
- }
+ if (flags[0] != '\0')
+ setenv("MAKEFLAGS", flags, 1);
}
char *
@@ -2224,9 +2154,9 @@ getTmpdir(void)
if (tmpdir != NULL)
return tmpdir;
- /* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */
- (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
- SCOPE_GLOBAL, VARE_WANTRES, &tmpdir);
+ /* Honor $TMPDIR if it is valid, strip a trailing '/'. */
+ tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
+ SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
@@ -2238,7 +2168,7 @@ getTmpdir(void)
/*
* Create and open a temp file using "pattern".
- * If out_fname is provided, set it to a copy of the filename created.
+ * If tfile is provided, set it to a copy of the filename created.
* Otherwise unlink the file once open.
*/
int
@@ -2253,20 +2183,21 @@ mkTempFile(const char *pattern, char *tfile, size_t tfile_sz)
if (tmpdir == NULL)
tmpdir = getTmpdir();
if (tfile == NULL) {
- tfile = tbuf;
- tfile_sz = sizeof tbuf;
+ tfile = tbuf;
+ tfile_sz = sizeof tbuf;
}
- if (pattern[0] == '/') {
+
+ if (pattern[0] == '/')
snprintf(tfile, tfile_sz, "%s", pattern);
- } else {
+ else
snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern);
- }
+
if ((fd = mkstemp(tfile)) < 0)
Punt("Could not create temporary file %s: %s", tfile,
strerror(errno));
- if (tfile == tbuf) {
+ if (tfile == tbuf)
unlink(tfile); /* we just want the descriptor */
- }
+
return fd;
}