summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c1412
1 files changed, 699 insertions, 713 deletions
diff --git a/main.c b/main.c
index 729c225d4bc4..6e97a9a12541 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.421 2020/11/01 00:24:57 rillig Exp $ */
+/* $NetBSD: main.c,v 1.476 2020/11/16 22:08:20 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -68,31 +68,22 @@
* SUCH DAMAGE.
*/
-/*-
- * main.c --
- * The main file for this entire program. Exit routines etc
- * reside here.
+/* The main file for this entire program. Exit routines etc. reside here.
*
* Utility functions defined in this file:
- * Main_ParseArgLine Takes a line of arguments, breaks them and
- * treats them as if they were given when first
- * invoked. Used by the parse module to implement
- * the .MFLAGS target.
*
- * Error Print a tagged error message. The global
- * MAKE variable must have been defined. This
- * takes a format string and optional arguments
- * for it.
+ * Main_ParseArgLine Parse and process command line arguments from
+ * a single string. Used to implement the
+ * special targets .MFLAGS and .MAKEFLAGS.
+ *
+ * Error Print a tagged error message.
*
- * Fatal Print an error message and exit. Also takes
- * a format string and arguments for it.
+ * Fatal Print an error message and exit.
*
- * Punt Aborts all jobs and exits with a message. Also
- * takes a format string and arguments for it.
+ * Punt Abort all jobs and exit with a message.
*
* Finish Finish things up by printing the number of
- * errors which occurred, as passed to it, and
- * exiting.
+ * errors which occurred, and exit.
*/
#include <sys/types.h>
@@ -118,15 +109,15 @@
#include "trace.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 $");
+MAKE_RCSID("$NetBSD: main.c,v 1.476 2020/11/16 22:08:20 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
+#ifndef DEFMAXLOCAL
+#define DEFMAXLOCAL DEFMAXJOBS
#endif
#ifndef __arraycount
@@ -134,202 +125,208 @@ __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
#endif
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 int maxJobTokens; /* -j argument */
-Boolean enterFlagObj; /* -w and objdir != srcdir */
-
-Boolean oldVars; /* variable substitution style */
-static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
-Boolean doing_depend; /* Set while reading .depend */
-static Boolean jobsRunning; /* TRUE if the jobs might be running */
-static const char * tracefile;
-static int ReadMakefile(const char *);
-static void usage(void) MAKE_ATTR_DEAD;
-static void purge_cached_realpaths(void);
-
-static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
-static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
-char curdir[MAXPATHLEN + 1]; /* Startup directory */
-char *progname; /* the program name */
+time_t now; /* Time at start of make */
+GNode *defaultNode; /* .DEFAULT node */
+Boolean allPrecious; /* .PRECIOUS given on line by itself */
+Boolean deleteOnError; /* .DELETE_ON_ERROR: set */
+
+static int maxJobTokens; /* -j argument */
+Boolean enterFlagObj; /* -w and objdir != srcdir */
+
+Boolean preserveUndefined;
+static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
+Boolean doing_depend; /* Set while reading .depend */
+static Boolean jobsRunning; /* TRUE if the jobs might be running */
+static const char *tracefile;
+static int ReadMakefile(const char *);
+static void purge_relative_cached_realpaths(void);
+
+static Boolean ignorePWD; /* if we use -C, PWD is meaningless */
+static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */
+char curdir[MAXPATHLEN + 1]; /* Startup directory */
+char *progname; /* the program name */
char *makeDependfile;
pid_t myPid;
int makelevel;
Boolean forceJobs = FALSE;
static int errors = 0;
-
-/*
- * On some systems MACHINE is defined as something other than
- * what we want.
- */
-#ifdef FORCE_MACHINE
-# undef MACHINE
-# define MACHINE FORCE_MACHINE
-#endif
-
-extern SearchPath *parseIncPath;
+static HashTable cached_realpaths;
/*
* For compatibility with the POSIX version of MAKEFLAGS that includes
- * all the options with out -, 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;
+ size_t len;
+ char *nf, *st;
+ const char *f;
- if (flags == NULL)
- return NULL;
+ if (flags == NULL)
+ return NULL;
+
+ for (f = flags; *f; f++)
+ if (!ch_isalpha(*f))
+ break;
+
+ if (*f)
+ return bmake_strdup(flags);
- for (f = flags; *f; f++)
- if (!ch_isalpha(*f))
- break;
-
- if (*f)
- return bmake_strdup(flags);
-
- len = strlen(flags);
- st = nf = bmake_malloc(len * 3 + 1);
- while (*flags) {
- *nf++ = '-';
- *nf++ = *flags++;
- *nf++ = ' ';
- }
- *nf = '\0';
- return st;
+ len = strlen(flags);
+ st = nf = bmake_malloc(len * 3 + 1);
+ while (*flags) {
+ *nf++ = '-';
+ *nf++ = *flags++;
+ *nf++ = ' ';
+ }
+ *nf = '\0';
+ return st;
+}
+
+/*
+ * usage --
+ * exit with usage message
+ */
+MAKE_ATTR_DEAD static void
+usage(void)
+{
+ size_t prognameLen = strcspn(progname, "[");
+
+ (void)fprintf(stderr,
+"usage: %.*s [-BeikNnqrSstWwX]\n"
+" [-C directory] [-D variable] [-d flags] [-f makefile]\n"
+" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
+" [-V variable] [-v variable] [variable=value] [target ...]\n",
+ (int)prognameLen, progname);
+ exit(2);
}
static void
parse_debug_option_F(const char *modules)
{
- const char *mode;
- size_t len;
- char *fname;
+ const char *mode;
+ size_t len;
+ char *fname;
- if (opts.debug_file != stdout && opts.debug_file != stderr)
- fclose(opts.debug_file);
+ if (opts.debug_file != stdout && opts.debug_file != stderr)
+ fclose(opts.debug_file);
- if (*modules == '+') {
- modules++;
- mode = "a";
- } else
- mode = "w";
+ 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;
- }
+ 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);
+ 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());
+ /* 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);
+ opts.debug_file = fopen(fname, mode);
+ if (opts.debug_file == NULL) {
+ fprintf(stderr, "Cannot open debug file %s\n",
+ fname);
+ usage();
+ }
+ free(fname);
}
static void
parse_debug_options(const char *argvalue)
{
const char *modules;
+ DebugFlags debug = opts.debug;
for (modules = argvalue; *modules; ++modules) {
switch (*modules) {
case '0': /* undocumented, only intended for tests */
- opts.debug &= DEBUG_LINT;
+ debug = DEBUG_NONE;
break;
case 'A':
- opts.debug = ~(0|DEBUG_LINT);
+ debug = DEBUG_ALL;
break;
case 'a':
- opts.debug |= DEBUG_ARCH;
+ debug |= DEBUG_ARCH;
break;
case 'C':
- opts.debug |= DEBUG_CWD;
+ debug |= DEBUG_CWD;
break;
case 'c':
- opts.debug |= DEBUG_COND;
+ debug |= DEBUG_COND;
break;
case 'd':
- opts.debug |= DEBUG_DIR;
+ debug |= DEBUG_DIR;
break;
case 'e':
- opts.debug |= DEBUG_ERROR;
+ debug |= DEBUG_ERROR;
break;
case 'f':
- opts.debug |= DEBUG_FOR;
+ debug |= DEBUG_FOR;
break;
case 'g':
if (modules[1] == '1') {
- opts.debug |= DEBUG_GRAPH1;
- ++modules;
- }
- else if (modules[1] == '2') {
- opts.debug |= DEBUG_GRAPH2;
- ++modules;
- }
- else if (modules[1] == '3') {
- opts.debug |= DEBUG_GRAPH3;
- ++modules;
+ debug |= DEBUG_GRAPH1;
+ modules++;
+ } else if (modules[1] == '2') {
+ debug |= DEBUG_GRAPH2;
+ modules++;
+ } else if (modules[1] == '3') {
+ debug |= DEBUG_GRAPH3;
+ modules++;
}
break;
case 'h':
- opts.debug |= DEBUG_HASH;
+ debug |= DEBUG_HASH;
break;
case 'j':
- opts.debug |= DEBUG_JOB;
+ debug |= DEBUG_JOB;
break;
case 'L':
- opts.debug |= DEBUG_LINT;
+ opts.lint = TRUE;
break;
case 'l':
- opts.debug |= DEBUG_LOUD;
+ debug |= DEBUG_LOUD;
break;
case 'M':
- opts.debug |= DEBUG_META;
+ debug |= DEBUG_META;
break;
case 'm':
- opts.debug |= DEBUG_MAKE;
+ debug |= DEBUG_MAKE;
break;
case 'n':
- opts.debug |= DEBUG_SCRIPT;
+ debug |= DEBUG_SCRIPT;
break;
case 'p':
- opts.debug |= DEBUG_PARSE;
+ debug |= DEBUG_PARSE;
break;
case 's':
- opts.debug |= DEBUG_SUFF;
+ debug |= DEBUG_SUFF;
break;
case 't':
- opts.debug |= DEBUG_TARG;
+ debug |= DEBUG_TARG;
break;
case 'V':
opts.debugVflag = TRUE;
break;
case 'v':
- opts.debug |= DEBUG_VAR;
+ debug |= DEBUG_VAR;
break;
case 'x':
- opts.debug |= DEBUG_SHELL;
+ debug |= DEBUG_SHELL;
break;
case 'F':
parse_debug_option_F(modules + 1);
@@ -341,7 +338,10 @@ parse_debug_options(const char *argvalue)
usage();
}
}
+
debug_setbuf:
+ opts.debug = debug;
+
/*
* Make the debug_file unbuffered, and make
* stdout line buffered (unless debugfile == stdout).
@@ -365,12 +365,10 @@ is_relpath(const char *path)
cp = path;
while ((cp = strstr(cp, "/.")) != NULL) {
cp += 2;
+ if (*cp == '.')
+ cp++;
if (cp[0] == '/' || cp[0] == '\0')
return TRUE;
- else if (cp[0] == '.') {
- if (cp[1] == '/' || cp[1] == '\0')
- return TRUE;
- }
}
return FALSE;
}
@@ -401,10 +399,11 @@ MainParseArgChdir(const char *argvalue)
static void
MainParseArgJobsInternal(const char *argvalue)
{
- if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) {
+ char end;
+ if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) {
(void)fprintf(stderr,
- "%s: internal error -- J option malformed (%s)\n",
- progname, argvalue);
+ "%s: internal error -- J option malformed (%s)\n",
+ progname, argvalue);
usage();
}
if ((fcntl(jp_0, F_GETFD, 0) < 0) ||
@@ -504,7 +503,7 @@ MainParseArg(char c, const char *argvalue)
break;
case 'V':
case 'v':
- opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS;
+ opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED;
Lst_Append(opts.variables, bmake_strdup(argvalue));
/* XXX: Why always -V? */
Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);
@@ -512,6 +511,7 @@ MainParseArg(char c, const char *argvalue)
break;
case 'W':
opts.parseWarnFatal = TRUE;
+ /* XXX: why no Var_Append? */
break;
case 'X':
opts.varNoExportEnv = TRUE;
@@ -547,6 +547,7 @@ MainParseArg(char c, const char *argvalue)
break;
case 'm':
MainParseArgSysInc(argvalue);
+ /* XXX: why no Var_Append? */
break;
case 'n':
opts.noExecute = TRUE;
@@ -610,8 +611,8 @@ rearg:
arginc = 0;
if (inOption) {
if (c == '\0') {
- ++argv;
- --argc;
+ argv++;
+ argc--;
inOption = FALSE;
continue;
}
@@ -653,8 +654,6 @@ rearg:
argc -= arginc;
}
- oldVars = TRUE;
-
/*
* See if the rest of the arguments are variable assignments and
* perform them if so. Else take them to be targets and stuff them
@@ -665,9 +664,9 @@ rearg:
if (Parse_IsVar(argv[1], &var)) {
Parse_DoVar(&var, VAR_CMDLINE);
} else {
- if (!*argv[1])
+ if (argv[1][0] == '\0')
Punt("illegal (null) argument.");
- if (*argv[1] == '-' && !dashDash)
+ if (argv[1][0] == '-' && !dashDash)
goto rearg;
Lst_Append(opts.create, bmake_strdup(argv[1]));
}
@@ -688,15 +687,13 @@ void
Main_ParseArgLine(const char *line)
{
Words words;
- void *p1;
- const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1);
char *buf;
if (line == NULL)
return;
for (; *line == ' '; ++line)
continue;
- if (!*line)
+ if (line[0] == '\0')
return;
#ifndef POSIX
@@ -713,8 +710,12 @@ Main_ParseArgLine(const char *line)
return;
}
#endif
- buf = str_concat3(argv0, " ", line);
- free(p1);
+ {
+ void *freeIt;
+ const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &freeIt);
+ buf = str_concat3(argv0, " ", line);
+ free(freeIt);
+ }
words = Str_Words(buf, TRUE);
if (words.words == NULL) {
@@ -729,7 +730,7 @@ Main_ParseArgLine(const char *line)
}
Boolean
-Main_SetObjdir(const char *fmt, ...)
+Main_SetObjdir(Boolean writable, const char *fmt, ...)
{
struct stat sb;
char *path;
@@ -749,17 +750,16 @@ 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 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));
+ 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);
Var_Set(".OBJDIR", objdir, VAR_GLOBAL);
setenv("PWD", objdir, 1);
Dir_InitDot();
- purge_cached_realpaths();
+ purge_relative_cached_realpaths();
rc = TRUE;
if (opts.enterFlag && strcmp(objdir, curdir) != 0)
enterFlagObj = TRUE;
@@ -770,7 +770,7 @@ Main_SetObjdir(const char *fmt, ...)
}
static Boolean
-Main_SetVarObjdir(const char *var, const char *suffix)
+SetVarObjdir(Boolean writable, const char *var, const char *suffix)
{
void *path_freeIt;
const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt);
@@ -791,35 +791,28 @@ Main_SetVarObjdir(const char *var, const char *suffix)
xpath = xpath_freeIt;
}
- (void)Main_SetObjdir("%s%s", xpath, suffix);
+ (void)Main_SetObjdir(writable, "%s%s", xpath, suffix);
bmake_free(xpath_freeIt);
bmake_free(path_freeIt);
return TRUE;
}
-/* Read and parse the makefile.
- * Return TRUE if reading the makefile succeeded. */
-static int
-ReadMakefileSucceeded(void *fname, void *unused)
-{
- return ReadMakefile(fname) == 0;
-}
-
+/* Splits str into words, adding them to the list.
+ * The string must be kept alive as long as the list. */
int
-str2Lst_Append(StringList *lp, char *str, const char *sep)
+str2Lst_Append(StringList *lp, char *str)
{
- char *cp;
- int n;
+ char *cp;
+ int n;
- if (!sep)
- sep = " \t";
+ const char *sep = " \t";
- for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) {
- Lst_Append(lp, cp);
- n++;
- }
- return n;
+ for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) {
+ Lst_Append(lp, cp);
+ n++;
+ }
+ return n;
}
#ifdef SIGINFO
@@ -830,9 +823,9 @@ siginfo(int signo MAKE_ATTR_UNUSED)
char dir[MAXPATHLEN];
char str[2 * MAXPATHLEN];
int len;
- if (getcwd(dir, sizeof(dir)) == NULL)
+ if (getcwd(dir, sizeof dir) == NULL)
return;
- len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir);
+ len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir);
if (len > 0)
(void)write(STDERR_FILENO, str, (size_t)len);
}
@@ -844,27 +837,27 @@ siginfo(int signo MAKE_ATTR_UNUSED)
void
MakeMode(const char *mode)
{
- char *mode_freeIt = NULL;
-
- if (mode == NULL) {
- (void)Var_Subst("${" MAKE_MODE ":tl}",
- VAR_GLOBAL, VARE_WANTRES, &mode_freeIt);
- /* TODO: handle errors */
- mode = mode_freeIt;
- }
+ char *mode_freeIt = NULL;
- if (mode[0] != '\0') {
- if (strstr(mode, "compat")) {
- opts.compatMake = TRUE;
- forceJobs = FALSE;
+ 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")) {
+ opts.compatMake = TRUE;
+ forceJobs = FALSE;
+ }
#if USE_META
- if (strstr(mode, "meta"))
- meta_mode_init(mode);
+ if (strstr(mode, "meta"))
+ meta_mode_init(mode);
#endif
- }
+ }
- free(mode_freeIt);
+ free(mode_freeIt);
}
static void
@@ -894,18 +887,40 @@ PrintVar(const char *varname, Boolean expandVars)
}
}
+/*
+ * Return a Boolean based on a variable.
+ *
+ * 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
+GetBooleanVar(const char *varname, Boolean fallback)
+{
+ char *expr = str_concat3("${", varname, ":U}");
+ char *value;
+ Boolean res;
+
+ (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value);
+ /* TODO: handle errors */
+ res = ParseBoolean(value, fallback);
+ free(value);
+ free(expr);
+ return res;
+}
+
static void
doPrintVars(void)
{
StringListNode *ln;
Boolean expandVars;
- if (opts.printVars == EXPAND_VARS)
+ if (opts.printVars == PVM_EXPANDED)
expandVars = TRUE;
else if (opts.debugVflag)
expandVars = FALSE;
else
- expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE);
+ expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE);
for (ln = opts.variables->first; ln != NULL; ln = ln->next) {
const char *varname = ln->datum;
@@ -916,7 +931,7 @@ doPrintVars(void)
static Boolean
runTargets(void)
{
- GNodeList *targs; /* target nodes to create -- passed to Make_Init */
+ GNodeList *targs; /* target nodes to create */
Boolean outOfDate; /* FALSE if all targets up to date */
/*
@@ -988,20 +1003,19 @@ InitRandom(void)
}
static const char *
-init_machine(const struct utsname *utsname)
+InitVarMachine(const struct utsname *utsname)
{
#ifdef FORCE_MACHINE
- const char *machine = FORCE_MACHINE;
+ return FORCE_MACHINE;
#else
const char *machine = getenv("MACHINE");
-#endif
+
if (machine != NULL)
return machine;
-#ifdef MAKE_NATIVE
+#if defined(MAKE_NATIVE)
return utsname->machine;
-#else
-#ifdef MAKE_MACHINE
+#elif defined(MAKE_MACHINE)
return MAKE_MACHINE;
#else
return "unknown";
@@ -1010,8 +1024,11 @@ init_machine(const struct utsname *utsname)
}
static const char *
-init_machine_arch(void)
+InitVarMachineArch(void)
{
+#ifdef FORCE_MACHINE_ARCH
+ return FORCE_MACHINE_ARCH;
+#else
const char *env = getenv("MACHINE_ARCH");
if (env != NULL)
return env;
@@ -1019,9 +1036,9 @@ init_machine_arch(void)
#if defined(MAKE_NATIVE) && defined(CTL_HW)
{
struct utsname utsname;
- static char machine_arch_buf[sizeof(utsname.machine)];
+ static char machine_arch_buf[sizeof utsname.machine];
const int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
- size_t len = sizeof(machine_arch_buf);
+ size_t len = sizeof machine_arch_buf;
if (sysctl(mib, __arraycount(mib), machine_arch_buf,
&len, NULL, 0) < 0) {
@@ -1032,16 +1049,13 @@ init_machine_arch(void)
return machine_arch_buf;
}
-#else
-#ifndef MACHINE_ARCH
-#ifdef MAKE_MACHINE_ARCH
+#elif defined(MACHINE_ARCH)
+ return MACHINE_ARCH;
+#elif defined(MAKE_MACHINE_ARCH)
return MAKE_MACHINE_ARCH;
#else
return "unknown";
#endif
-#else
- return MACHINE_ARCH;
-#endif
#endif
}
@@ -1070,7 +1084,8 @@ HandlePWD(const struct stat *curdir_st)
if (ignorePWD || (pwd = getenv("PWD")) == NULL)
return;
- if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) {
+ if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) !=
+ NULL) {
bmake_free(prefix_freeIt);
return;
}
@@ -1101,15 +1116,18 @@ ignore_pwd:
static void
InitObjdir(const char *machine, const char *machine_arch)
{
+ Boolean writable;
+
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);
+ writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE);
+ (void)Main_SetObjdir(FALSE, "%s", curdir);
+
+ if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) &&
+ !SetVarObjdir(writable, "MAKEOBJDIR", "") &&
+ !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) &&
+ !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) &&
+ !Main_SetObjdir(writable, "%s", _PATH_OBJDIR))
+ (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir);
}
/* get rid of resource limit on file descriptors */
@@ -1132,6 +1150,7 @@ CmdOpts_Init(void)
opts.compatMake = FALSE; /* No compat mode */
opts.debug = 0; /* No debug verbosity, please. */
/* opts.debug_file has been initialized earlier */
+ opts.lint = FALSE;
opts.debugVflag = FALSE;
opts.checkEnvFirst = FALSE;
opts.makefiles = Lst_New();
@@ -1144,7 +1163,7 @@ CmdOpts_Init(void)
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.printVars = PVM_NONE;
opts.variables = Lst_New();
opts.parseWarnFatal = FALSE;
opts.enterFlag = FALSE;
@@ -1174,6 +1193,8 @@ InitVarMake(const char *argv0)
Var_Set(".MAKE", make, VAR_GLOBAL);
}
+/* Add the directories from the colon-separated syspath to defSysIncPath.
+ * After returning, the contents of syspath is unspecified. */
static void
InitDefSysIncPath(char *syspath)
{
@@ -1185,7 +1206,6 @@ InitDefSysIncPath(char *syspath)
* 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
@@ -1194,18 +1214,18 @@ InitDefSysIncPath(char *syspath)
for (start = syspath; *start != '\0'; start = cp) {
for (cp = start; *cp != '\0' && *cp != ':'; cp++)
continue;
- if (*cp == ':') {
+ if (*cp == ':')
*cp++ = '\0';
- }
+
/* look for magic parent directory search string */
- if (strncmp(".../", start, 4) != 0) {
- (void)Dir_AddDir(defSysIncPath, start);
- } else {
+ if (strncmp(start, ".../", 4) == 0) {
char *dir = Dir_FindHereOrAbove(curdir, start + 4);
if (dir != NULL) {
(void)Dir_AddDir(defSysIncPath, dir);
free(dir);
}
+ } else {
+ (void)Dir_AddDir(defSysIncPath, start);
}
}
@@ -1216,16 +1236,26 @@ InitDefSysIncPath(char *syspath)
static void
ReadBuiltinRules(void)
{
+ StringListNode *ln;
StringList *sysMkPath = Lst_New();
+
Dir_Expand(_PATH_DEFSYSMK,
- Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath,
- sysMkPath);
+ 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 */
+
+ for (ln = sysMkPath->first; ln != NULL; ln = ln->next)
+ if (ReadMakefile(ln->datum) == 0)
+ break;
+
+ if (ln == NULL)
+ Fatal("%s: cannot open %s.",
+ progname, (const char *)sysMkPath->first->datum);
+
+ /* Free the list but not the actual filenames since these may still
+ * be used in GNodes. */
+ Lst_Free(sysMkPath);
}
static void
@@ -1243,9 +1273,9 @@ InitMaxJobs(void)
n = (int)strtol(value, NULL, 0);
if (n < 1) {
(void)fprintf(stderr,
- "%s: illegal value for .MAKE.JOBS "
- "-- must be positive integer!\n",
- progname);
+ "%s: illegal value for .MAKE.JOBS "
+ "-- must be positive integer!\n",
+ progname);
exit(1);
}
@@ -1293,82 +1323,46 @@ InitVpath(void)
}
static void
-ReadMakefiles(void)
+ReadAllMakefiles(StringList *makefiles)
{
- if (opts.makefiles->first != NULL) {
- StringListNode *ln;
+ 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);
+ for (ln = makefiles->first; ln != NULL; ln = ln->next) {
+ const char *fname = ln->datum;
+ if (ReadMakefile(fname) != 0)
+ Fatal("%s: cannot open %s.", progname, fname);
}
}
static void
-CleanUp(void)
+ReadFirstDefaultMakefile(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
+ StringListNode *ln;
+ char *prefs;
- /* print the graph now it's been processed if the user requested it */
- if (DEBUG(GRAPH2))
- Targ_PrintGraph(2);
+ (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}",
+ VAR_CMDLINE, VARE_WANTRES, &prefs);
+ /* TODO: handle errors */
- Trace_Log(MAKEEND, 0);
+ /* 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);
- if (enterFlagObj)
- printf("%s: Leaving directory `%s'\n", progname, objdir);
- if (opts.enterFlag)
- printf("%s: Leaving directory `%s'\n", progname, curdir);
+ for (ln = opts.makefiles->first; ln != NULL; ln = ln->next)
+ if (ReadMakefile(ln->datum) == 0)
+ break;
-#ifdef USE_META
- meta_finish();
-#endif
- Suff_End();
- Targ_End();
- Arch_End();
- Var_End();
- Parse_End();
- Dir_End();
- Job_End();
- Trace_End();
+ free(prefs);
}
-/*-
- * main --
- * The main function, for obvious reasons. Initializes variables
- * and a few modules, then parses the arguments give it in the
- * environment and on the command line. Reads the system makefile
- * followed by either Makefile, makefile or the file given by the
- * -f argument. Sets the .MAKEFLAGS PMake variable based on all the
- * flags it has received by then uses either the Make or the Compat
- * module to create the initial list of targets.
- *
- * Results:
- * If -q was given, exits -1 if anything was out-of-date. Else it exits
- * 0.
- *
- * Side Effects:
- * The program exits when done. Targets are created. etc. etc. etc.
- */
-int
-main(int argc, char **argv)
+/* Initialize variables such as MAKE, MACHINE, .MAKEFLAGS.
+ * Initialize a few modules.
+ * Parse the arguments from MAKEFLAGS and the command line. */
+static void
+main_Init(int argc, char **argv)
{
- Boolean outOfDate; /* FALSE if all targets up to date */
struct stat sa;
const char *machine;
const char *machine_arch;
@@ -1378,6 +1372,8 @@ main(int argc, char **argv)
/* default to writing debug to stderr */
opts.debug_file = stderr;
+ HashTable_Init(&cached_realpaths);
+
#ifdef SIGINFO
(void)bmake_signal(SIGINFO, siginfo);
#endif
@@ -1392,9 +1388,9 @@ main(int argc, char **argv)
UnlimitFiles();
if (uname(&utsname) == -1) {
- (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
- strerror(errno));
- exit(2);
+ (void)fprintf(stderr, "%s: uname failed (%s).\n", progname,
+ strerror(errno));
+ exit(2);
}
/*
@@ -1405,16 +1401,16 @@ main(int argc, char **argv)
* Note that both MACHINE and MACHINE_ARCH are decided at
* run-time.
*/
- machine = init_machine(&utsname);
- machine_arch = init_machine_arch();
+ machine = InitVarMachine(&utsname);
+ machine_arch = InitVarMachineArch();
- myPid = getpid(); /* remember this for vFork() */
+ myPid = getpid(); /* remember this for vFork() */
/*
* Just in case MAKEOBJDIR wants us to do something tricky.
*/
- Var_Init(); /* Initialize the lists of variables for
- * parsing arguments */
+ Targ_Init();
+ Var_Init();
Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL);
Var_Set("MACHINE", machine, VAR_GLOBAL);
Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);
@@ -1428,13 +1424,12 @@ main(int argc, char **argv)
#ifndef MAKEFILE_PREFERENCE_LIST
# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
#endif
- Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST,
- VAR_GLOBAL);
+ Var_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, VAR_GLOBAL);
Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL);
CmdOpts_Init();
- allPrecious = FALSE; /* Remove targets when interrupted */
- deleteOnError = FALSE; /* Historical default behavior */
+ allPrecious = FALSE; /* Remove targets when interrupted */
+ deleteOnError = FALSE; /* Historical default behavior */
jobsRunning = FALSE;
maxJobTokens = opts.maxJobs;
@@ -1461,25 +1456,23 @@ main(int argc, char **argv)
/* some makefiles need to know this */
Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE);
- /*
- * Set some other useful macros
- */
+ /* Set some other useful variables. */
{
- char tmp[64], *ep;
-
- makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0;
- if (makelevel < 0)
- makelevel = 0;
- snprintf(tmp, sizeof(tmp), "%d", makelevel);
- Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
- snprintf(tmp, sizeof(tmp), "%u", myPid);
- Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
- snprintf(tmp, sizeof(tmp), "%u", getppid());
- Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
+ char tmp[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);
+ Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL);
+ snprintf(tmp, sizeof tmp, "%u", myPid);
+ Var_Set(".MAKE.PID", tmp, VAR_GLOBAL);
+ snprintf(tmp, sizeof tmp, "%u", getppid());
+ Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL);
}
if (makelevel > 0) {
char pn[1024];
- snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel);
+ snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel);
progname = bmake_strdup(pn);
}
@@ -1495,9 +1488,9 @@ main(int argc, char **argv)
*/
#ifdef POSIX
{
- char *p1 = explode(getenv("MAKEFLAGS"));
- Main_ParseArgLine(p1);
- free(p1);
+ char *p1 = explode(getenv("MAKEFLAGS"));
+ Main_ParseArgLine(p1);
+ free(p1);
}
#else
Main_ParseArgLine(getenv("MAKE"));
@@ -1522,9 +1515,9 @@ main(int argc, char **argv)
* Verify that cwd is sane.
*/
if (stat(curdir, &sa) == -1) {
- (void)fprintf(stderr, "%s: %s: %s.\n",
- progname, curdir, strerror(errno));
- exit(2);
+ (void)fprintf(stderr, "%s: %s: %s.\n",
+ progname, curdir, strerror(errno));
+ exit(2);
}
#ifndef NO_PWD_OVERRIDE
@@ -1539,11 +1532,10 @@ main(int argc, char **argv)
* parsing the makefile(s)
*/
Arch_Init();
- Targ_Init();
Suff_Init();
Trace_Init(tracefile);
- DEFAULT = NULL;
+ defaultNode = NULL;
(void)time(&now);
Trace_Log(MAKESTART, NULL);
@@ -1551,27 +1543,38 @@ main(int argc, char **argv)
InitVarTargets();
InitDefSysIncPath(syspath);
+}
+
+/* Read the system makefile followed by either makefile, Makefile or the
+ * files given by the -f option. Exit on parse errors. */
+static void
+main_ReadFiles(void)
+{
- /*
- * 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 (!opts.noBuiltins)
ReadBuiltinRules();
- ReadMakefiles();
-
+
+ if (!Lst_IsEmpty(opts.makefiles))
+ ReadAllMakefiles(opts.makefiles);
+ else
+ ReadFirstDefaultMakefile();
+}
+
+/* Compute the dependency graph. */
+static void
+main_PrepareMaking(void)
+{
/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
- 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 (!opts.noBuiltins || opts.printVars == PVM_NONE) {
+ /* 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)
@@ -1580,30 +1583,28 @@ main(int argc, char **argv)
MakeMode(NULL);
{
- void *freeIt;
- Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt),
- VAR_GLOBAL);
- bmake_free(freeIt);
-
+ void *freeIt;
+ Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt),
+ VAR_GLOBAL);
+ bmake_free(freeIt);
}
InitMaxJobs();
/*
- * Be compatible if user did not specify -j and did not explicitly
- * turned compatibility on
+ * Be compatible if the user did not specify -j and did not explicitly
+ * turn compatibility on.
*/
- if (!opts.compatMake && !forceJobs) {
- opts.compatMake = TRUE;
- }
+ if (!opts.compatMake && !forceJobs)
+ opts.compatMake = TRUE;
if (!opts.compatMake)
- Job_ServerStart(maxJobTokens, jp_0, jp_1);
+ Job_ServerStart(maxJobTokens, jp_0, jp_1);
DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n",
- jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
+ jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0);
- if (!opts.printVars)
- Main_ExportMAKEFLAGS(TRUE); /* initial export */
+ if (opts.printVars == PVM_NONE)
+ Main_ExportMAKEFLAGS(TRUE); /* initial export */
InitVpath();
@@ -1621,22 +1622,79 @@ main(int argc, char **argv)
/* print the initial graph, if the user requested it */
if (DEBUG(GRAPH1))
Targ_PrintGraph(1);
+}
- /* print the values of any variables requested by the user */
- if (opts.printVars) {
+/* Make the targets.
+ * If the -v or -V options are given, print variables instead.
+ * Return whether any of the targets is out-of-date. */
+static Boolean
+main_Run(void)
+{
+ if (opts.printVars != PVM_NONE) {
+ /* print the values of any variables requested by the user */
doPrintVars();
- outOfDate = FALSE;
+ return FALSE;
} else {
- outOfDate = runTargets();
+ return runTargets();
}
+}
- CleanUp();
+/* Clean up after making the targets. */
+static void
+main_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, NULL);
+
+ 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();
+}
- if (DEBUG(LINT) && (errors > 0 || Parse_GetFatals() > 0))
- return 2; /* Not 1 so -q can distinguish error */
+/* Determine the exit code. */
+static int
+main_Exit(Boolean outOfDate)
+{
+ if (opts.lint && (errors > 0 || Parse_GetFatals() > 0))
+ return 2; /* Not 1 so -q can distinguish error */
return outOfDate ? 1 : 0;
}
+int
+main(int argc, char **argv)
+{
+ Boolean outOfDate;
+
+ main_Init(argc, argv);
+ main_ReadFiles();
+ main_PrepareMaking();
+ outOfDate = main_Run();
+ main_CleanUp();
+ return main_Exit(outOfDate);
+}
+
/* Open and parse the given makefile, with all its side effects.
*
* Results:
@@ -1648,12 +1706,12 @@ ReadMakefile(const char *fname)
int fd;
char *name, *path = NULL;
- if (!strcmp(fname, "-")) {
+ if (strcmp(fname, "-") == 0) {
Parse_File(NULL /*stdin*/, -1);
Var_Set("MAKEFILE", "", VAR_INTERNAL);
} else {
/* if we've chdir'd, rebuild the path name */
- if (strcmp(curdir, objdir) && *fname != '/') {
+ if (strcmp(curdir, objdir) != 0 && *fname != '/') {
path = str_concat3(curdir, "/", fname);
fd = open(path, O_RDONLY);
if (fd != -1) {
@@ -1676,12 +1734,12 @@ ReadMakefile(const char *fname)
}
/* look in -I and system include directories. */
name = Dir_FindFile(fname, parseIncPath);
- if (!name) {
+ if (name == NULL) {
SearchPath *sysInc = Lst_IsEmpty(sysIncPath)
? defSysIncPath : sysIncPath;
name = Dir_FindFile(fname, sysInc);
}
- if (!name || (fd = open(name, O_RDONLY)) == -1) {
+ if (name == NULL || (fd = open(name, O_RDONLY)) == -1) {
free(name);
free(path);
return -1;
@@ -1701,8 +1759,6 @@ found:
return 0;
}
-
-
/*-
* Cmd_Exec --
* Execute the command in cmd, and return the output of that command
@@ -1719,125 +1775,114 @@ 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() */
- WAIT_T 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;
-
- if (!shellName)
- Shell_Init();
- /*
- * Set up arguments for shell
- */
- args[0] = shellName;
- args[1] = "-c";
- args[2] = cmd;
- args[3] = NULL;
-
- /*
- * Open a pipe for fetching its output
- */
- if (pipe(fds) == -1) {
- *errfmt = "Couldn't create pipe for \"%s\"";
- goto bad;
- }
-
- /*
- * Fork
- */
- switch (cpid = vFork()) {
- case 0:
+ const char *args[4]; /* Args for invoking the shell */
+ int fds[2]; /* Pipe streams */
+ 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;
+
+ if (!shellName)
+ Shell_Init();
/*
- * Close input side of pipe
+ * Set up arguments for shell
*/
- (void)close(fds[0]);
+ args[0] = shellName;
+ args[1] = "-c";
+ args[2] = cmd;
+ args[3] = NULL;
/*
- * 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?
+ * Open a pipe for fetching its output
*/
- (void)dup2(fds[1], 1);
- (void)close(fds[1]);
-
- Var_ExportVars();
-
- (void)execv(shellPath, UNCONST(args));
- _exit(1);
- /*NOTREACHED*/
-
- case -1:
- *errfmt = "Couldn't exec \"%s\"";
- goto bad;
+ if (pipe(fds) == -1) {
+ *errfmt = "Couldn't create pipe for \"%s\"";
+ goto bad;
+ }
- default:
/*
- * No need for the writing half
+ * Fork
*/
- (void)close(fds[1]);
+ switch (cpid = vFork()) {
+ case 0:
+ (void)close(fds[0]); /* Close input side of pipe */
- savederr = 0;
- Buf_Init(&buf, 0);
+ /*
+ * 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(fds[1], 1);
+ (void)close(fds[1]);
- do {
- char result[BUFSIZ];
- bytes_read = read(fds[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;
+ Var_ExportVars();
- /*
- * Close the input side of the pipe.
- */
- (void)close(fds[0]);
+ (void)execv(shellPath, UNCONST(args));
+ _exit(1);
+ /*NOTREACHED*/
- /*
- * Wait for the process to exit.
- */
- while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) {
- JobReapChild(pid, status, FALSE);
- continue;
- }
- res_len = Buf_Len(&buf);
- res = Buf_Destroy(&buf, FALSE);
-
- 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;
- }
- return res;
+ case -1:
+ *errfmt = "Couldn't exec \"%s\"";
+ goto bad;
+
+ default:
+ (void)close(fds[1]); /* No need for the writing half */
+
+ savederr = 0;
+ Buf_Init(&buf);
+
+ do {
+ char result[BUFSIZ];
+ bytes_read = read(fds[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(
+ fds[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(&buf);
+ res = Buf_Destroy(&buf, FALSE);
+
+ 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;
+ }
+ return res;
bad:
- return bmake_strdup("");
+ return bmake_strdup("");
}
/* Print a printf-style error message.
*
- * This error message has no consequences, in particular it does not affect
- * the exit status. */
+ * 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. */
void
Error(const char *fmt, ...)
{
@@ -1862,19 +1907,21 @@ Error(const char *fmt, ...)
errors++;
}
-/* Produce a Fatal error message, then exit immediately.
+/* Wait for any running jobs to finish, then produce an error message,
+ * finally exit immediately.
*
- * If jobs are running, wait for them to finish. */
+ * Exiting immediately differs from Parse_Error, which exits only after the
+ * current top-level makefile has been parsed completely. */
void
Fatal(const char *fmt, ...)
{
va_list ap;
- va_start(ap, fmt);
if (jobsRunning)
Job_Wait();
(void)fflush(stdout);
+ va_start(ap, fmt);
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
@@ -1884,7 +1931,7 @@ Fatal(const char *fmt, ...)
if (DEBUG(GRAPH2) || DEBUG(GRAPH3))
Targ_PrintGraph(2);
- Trace_Log(MAKEERROR, 0);
+ Trace_Log(MAKEERROR, NULL);
exit(2); /* Not 1 so -q can distinguish error */
}
@@ -1916,7 +1963,7 @@ DieHorribly(void)
Job_AbortAll();
if (DEBUG(GRAPH2))
Targ_PrintGraph(2);
- Trace_Log(MAKEERROR, 0);
+ Trace_Log(MAKEERROR, NULL);
exit(2); /* Not 1, so -q can distinguish error */
}
@@ -1926,7 +1973,7 @@ DieHorribly(void)
void
Finish(int errs)
{
- if (dieQuietly(NULL, -1))
+ if (shouldDieQuietly(NULL, -1))
exit(2);
Fatal("%d error%s", errs, errs == 1 ? "" : "s");
}
@@ -1975,7 +2022,7 @@ execDie(const char *af, const char *av)
{
Buffer buf;
- Buf_Init(&buf, 0);
+ Buf_Init(&buf);
Buf_AddStr(&buf, progname);
Buf_AddStr(&buf, ": ");
Buf_AddStr(&buf, af);
@@ -1991,216 +2038,183 @@ execDie(const char *af, const char *av)
_exit(1);
}
-/*
- * usage --
- * exit with usage message
- */
-static void
-usage(void)
-{
- char *p;
- if ((p = strchr(progname, '[')) != NULL)
- *p = '\0';
-
- (void)fprintf(stderr,
-"usage: %s [-BeikNnqrstWwX] \n"
-" [-C directory] [-D variable] [-d flags] [-f makefile]\n"
-" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n"
-" [-V variable] [-v variable] [variable=value] [target ...]\n",
- progname);
- exit(2);
-}
-
-/*
- * realpath(3) can get expensive, cache results...
- */
-static GNode *cached_realpaths = NULL;
-
-static GNode *
-get_cached_realpaths(void)
-{
-
- if (!cached_realpaths) {
- cached_realpaths = Targ_NewGN("Realpath");
-#ifndef DEBUG_REALPATH_CACHE
- cached_realpaths->flags = INTERNAL;
-#endif
- }
-
- return cached_realpaths;
-}
-
/* purge any relative paths */
static void
-purge_cached_realpaths(void)
+purge_relative_cached_realpaths(void)
{
- GNode *cache = get_cached_realpaths();
- 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->key);
- HashTable_DeleteEntry(&cache->context, he);
- }
- he = nhe;
- }
+ HashEntry *he, *nhe;
+ HashIter hi;
+
+ HashIter_Init(&hi, &cached_realpaths);
+ he = HashIter_Next(&hi);
+ while (he != NULL) {
+ nhe = 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. */
+ }
+ he = nhe;
+ }
}
char *
cached_realpath(const char *pathname, char *resolved)
{
- GNode *cache;
- const char *rp;
- void *freeIt;
+ const char *rp;
- if (!pathname || !pathname[0])
- return NULL;
+ if (pathname == NULL || pathname[0] == '\0')
+ return NULL;
- cache = get_cached_realpaths();
+ rp = HashTable_FindValue(&cached_realpaths, pathname);
+ if (rp != NULL) {
+ /* a hit */
+ strncpy(resolved, rp, MAXPATHLEN);
+ resolved[MAXPATHLEN - 1] = '\0';
+ return resolved;
+ }
- 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? */
+ rp = realpath(pathname, resolved);
+ if (rp != NULL) {
+ HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp));
+ DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp);
+ return resolved;
+ }
- bmake_free(freeIt);
- return rp ? resolved : NULL;
+ /* should we negative-cache? */
+ return NULL;
}
/*
* Return true if we should die without noise.
- * For example our failing child was a sub-make
- * or failure happend elsewhere.
+ * For example our failing child was a sub-make or failure happened elsewhere.
*/
-int
-dieQuietly(GNode *gn, int bf)
+Boolean
+shouldDieQuietly(GNode *gn, int bf)
{
- static int quietly = -1;
-
- if (quietly < 0) {
- if (DEBUG(JOB) || !getBoolean(".MAKE.DIE_QUIETLY", TRUE))
- quietly = 0;
- else if (bf >= 0)
- quietly = bf;
- else
- quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0;
- }
- return quietly;
+ static int quietly = -1;
+
+ if (quietly < 0) {
+ if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE))
+ quietly = 0;
+ else if (bf >= 0)
+ quietly = bf;
+ else
+ quietly = gn != NULL && (gn->type & OP_MAKE);
+ }
+ return quietly;
}
static void
SetErrorVars(GNode *gn)
{
- StringListNode *ln;
+ 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);
+ /*
+ * 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;
+ 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);
- }
+ if (cmd == NULL)
+ break;
+ Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL);
+ }
}
+/* Print some helpful information in case of an error.
+ * The caller should exit soon after calling this function. */
void
-PrintOnError(GNode *gn, const char *s)
+PrintOnError(GNode *gn, const char *msg)
{
- static GNode *en = NULL;
- const char *expr;
- char *cp;
+ static GNode *errorNode = NULL;
- if (DEBUG(HASH)) {
- Targ_Stats();
- Var_Stats();
- }
+ if (DEBUG(HASH)) {
+ Targ_Stats();
+ Var_Stats();
+ }
- /* we generally want to keep quiet if a sub-make died */
- if (dieQuietly(gn, -1))
- return;
+ /* we generally want to keep quiet if a sub-make died */
+ if (shouldDieQuietly(gn, -1))
+ return;
+
+ if (msg != NULL)
+ printf("%s", msg);
+ printf("\n%s: stopped in %s\n", progname, curdir);
- if (s)
- printf("%s", s);
-
- printf("\n%s: stopped in %s\n", progname, curdir);
-
- if (en)
- return; /* we've been here! */
- if (gn)
- SetErrorVars(gn);
- expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}";
- (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp);
- /* TODO: handle errors */
- printf("%s", cp);
- free(cp);
- fflush(stdout);
-
- /*
- * Finally, see if there is a .ERROR target, and run it if so.
- */
- en = Targ_FindNode(".ERROR");
- if (en) {
- en->type |= OP_SPECIAL;
- Compat_Make(en, en);
- }
+ if (errorNode != NULL)
+ return; /* we've been here! */
+
+ if (gn != NULL)
+ SetErrorVars(gn);
+
+ {
+ char *errorVarsValues;
+ (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
+ VAR_GLOBAL, VARE_WANTRES, &errorVarsValues);
+ /* TODO: handle errors */
+ printf("%s", errorVarsValues);
+ free(errorVarsValues);
+ }
+
+ fflush(stdout);
+
+ /*
+ * Finally, see if there is a .ERROR target, and run it if so.
+ */
+ errorNode = Targ_FindNode(".ERROR");
+ if (errorNode != NULL) {
+ errorNode->type |= OP_SPECIAL;
+ Compat_Make(errorNode, errorNode);
+ }
}
void
Main_ExportMAKEFLAGS(Boolean first)
{
- static Boolean once = TRUE;
- const char *expr;
- char *s;
+ static Boolean once = TRUE;
+ const char *expr;
+ char *s;
- if (once != first)
- return;
- once = FALSE;
+ if (once != first)
+ return;
+ once = FALSE;
- expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
- (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s);
- /* TODO: handle errors */
- if (s[0] != '\0') {
+ expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}";
+ (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s);
+ /* TODO: handle errors */
+ if (s[0] != '\0') {
#ifdef POSIX
- setenv("MAKEFLAGS", s, 1);
+ setenv("MAKEFLAGS", s, 1);
#else
- setenv("MAKE", s, 1);
+ setenv("MAKE", s, 1);
#endif
- }
+ }
}
char *
getTmpdir(void)
{
- static char *tmpdir = NULL;
-
- if (!tmpdir) {
+ static char *tmpdir = NULL;
struct stat st;
- /*
- * Honor $TMPDIR but only if it is valid.
- * Ensure it ends with /.
- */
- (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL,
- VARE_WANTRES, &tmpdir);
+ 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 "}/",
+ 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);
+ free(tmpdir);
+ tmpdir = bmake_strdup(_PATH_TMP);
}
- }
- return tmpdir;
+ return tmpdir;
}
/*
@@ -2211,73 +2225,45 @@ getTmpdir(void)
int
mkTempFile(const char *pattern, char **out_fname)
{
- static char *tmpdir = NULL;
- char tfile[MAXPATHLEN];
- int fd;
-
- if (pattern != NULL)
- pattern = TMPPAT;
- if (tmpdir == NULL)
- tmpdir = getTmpdir();
- if (pattern[0] == '/') {
- snprintf(tfile, sizeof(tfile), "%s", pattern);
- } else {
- snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern);
- }
- if ((fd = mkstemp(tfile)) < 0)
- Punt("Could not create temporary file %s: %s", tfile, strerror(errno));
- if (out_fname) {
- *out_fname = bmake_strdup(tfile);
- } else {
- unlink(tfile); /* we just want the descriptor */
- }
- return fd;
-}
+ static char *tmpdir = NULL;
+ char tfile[MAXPATHLEN];
+ int fd;
-/*
- * Convert a string representation of a boolean.
- * Anything that looks like "No", "False", "Off", "0" etc,
- * is FALSE, otherwise TRUE.
- */
-Boolean
-s2Boolean(const char *s, Boolean bf)
-{
- 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;
+ if (pattern == NULL)
+ pattern = TMPPAT;
+ if (tmpdir == NULL)
+ tmpdir = getTmpdir();
+ if (pattern[0] == '/') {
+ snprintf(tfile, sizeof tfile, "%s", pattern);
+ } else {
+ snprintf(tfile, sizeof tfile, "%s%s", tmpdir, pattern);
+ }
+ if ((fd = mkstemp(tfile)) < 0)
+ Punt("Could not create temporary file %s: %s", tfile,
+ strerror(errno));
+ if (out_fname) {
+ *out_fname = bmake_strdup(tfile);
+ } else {
+ unlink(
+ tfile); /* we just want the descriptor */
+ }
+ return fd;
}
/*
- * Return a Boolean based on a variable.
- *
- * 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.
+ * Convert a string representation of a boolean into a boolean value.
+ * Anything that looks like "No", "False", "Off", "0" etc. is FALSE,
+ * the empty string is the fallback, everything else is TRUE.
*/
Boolean
-getBoolean(const char *varname, Boolean fallback)
+ParseBoolean(const char *s, Boolean 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;
+ char ch = ch_tolower(s[0]);
+ if (ch == '\0')
+ return fallback;
+ if (ch == '0' || ch == 'f' || ch == 'n')
+ return FALSE;
+ if (ch == 'o')
+ return ch_tolower(s[1]) != 'f';
+ return TRUE;
}