diff options
Diffstat (limited to 'contrib/bmake/main.c')
-rw-r--r-- | contrib/bmake/main.c | 843 |
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; } |