1*c59c3bf3SSimon J. Gerraty /* $NetBSD: main.c,v 1.612 2024/03/10 02:53:37 sjg Exp $ */ 23955d011SMarcel Moolenaar 33955d011SMarcel Moolenaar /* 43955d011SMarcel Moolenaar * Copyright (c) 1988, 1989, 1990, 1993 53955d011SMarcel Moolenaar * The Regents of the University of California. All rights reserved. 63955d011SMarcel Moolenaar * 73955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 83955d011SMarcel Moolenaar * Adam de Boor. 93955d011SMarcel Moolenaar * 103955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 113955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 123955d011SMarcel Moolenaar * are met: 133955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 143955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 153955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 163955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 173955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 183955d011SMarcel Moolenaar * 3. Neither the name of the University nor the names of its contributors 193955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 203955d011SMarcel Moolenaar * without specific prior written permission. 213955d011SMarcel Moolenaar * 223955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 233955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 243955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 253955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 263955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 273955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 283955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 293955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 303955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 313955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323955d011SMarcel Moolenaar * SUCH DAMAGE. 333955d011SMarcel Moolenaar */ 343955d011SMarcel Moolenaar 353955d011SMarcel Moolenaar /* 363955d011SMarcel Moolenaar * Copyright (c) 1989 by Berkeley Softworks 373955d011SMarcel Moolenaar * All rights reserved. 383955d011SMarcel Moolenaar * 393955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 403955d011SMarcel Moolenaar * Adam de Boor. 413955d011SMarcel Moolenaar * 423955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 433955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 443955d011SMarcel Moolenaar * are met: 453955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 463955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 473955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 483955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 493955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 503955d011SMarcel Moolenaar * 3. All advertising materials mentioning features or use of this software 513955d011SMarcel Moolenaar * must display the following acknowledgement: 523955d011SMarcel Moolenaar * This product includes software developed by the University of 533955d011SMarcel Moolenaar * California, Berkeley and its contributors. 543955d011SMarcel Moolenaar * 4. Neither the name of the University nor the names of its contributors 553955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 563955d011SMarcel Moolenaar * without specific prior written permission. 573955d011SMarcel Moolenaar * 583955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 593955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 603955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 613955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 623955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 633955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 643955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 653955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 663955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 673955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 683955d011SMarcel Moolenaar * SUCH DAMAGE. 693955d011SMarcel Moolenaar */ 703955d011SMarcel Moolenaar 7106b9b3e0SSimon J. Gerraty /* 7206b9b3e0SSimon J. Gerraty * The main file for this entire program. Exit routines etc. reside here. 733955d011SMarcel Moolenaar * 743955d011SMarcel Moolenaar * Utility functions defined in this file: 753955d011SMarcel Moolenaar * 76dba7b0efSSimon J. Gerraty * Main_ParseArgLine 77dba7b0efSSimon J. Gerraty * Parse and process command line arguments from a 78dba7b0efSSimon J. Gerraty * single string. Used to implement the special targets 79dba7b0efSSimon J. Gerraty * .MFLAGS and .MAKEFLAGS. 803955d011SMarcel Moolenaar * 81e2eeea75SSimon J. Gerraty * Error Print a tagged error message. 823955d011SMarcel Moolenaar * 83e2eeea75SSimon J. Gerraty * Fatal Print an error message and exit. 84e2eeea75SSimon J. Gerraty * 85e2eeea75SSimon J. Gerraty * Punt Abort all jobs and exit with a message. 863955d011SMarcel Moolenaar * 87dba7b0efSSimon J. Gerraty * Finish Finish things up by printing the number of errors 88dba7b0efSSimon J. Gerraty * that occurred, and exit. 893955d011SMarcel Moolenaar */ 903955d011SMarcel Moolenaar 913955d011SMarcel Moolenaar #include <sys/types.h> 923955d011SMarcel Moolenaar #include <sys/time.h> 933955d011SMarcel Moolenaar #include <sys/param.h> 943955d011SMarcel Moolenaar #include <sys/resource.h> 953955d011SMarcel Moolenaar #include <sys/stat.h> 960dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 970dede8b0SSimon J. Gerraty #include <sys/sysctl.h> 980dede8b0SSimon J. Gerraty #endif 993955d011SMarcel Moolenaar #include <sys/utsname.h> 1003955d011SMarcel Moolenaar #include "wait.h" 1013955d011SMarcel Moolenaar 1023955d011SMarcel Moolenaar #include <errno.h> 10351ee2c1cSSimon J. Gerraty #include <signal.h> 1043955d011SMarcel Moolenaar #include <stdarg.h> 1053955d011SMarcel Moolenaar #include <time.h> 1063955d011SMarcel Moolenaar 1073955d011SMarcel Moolenaar #include "make.h" 1083955d011SMarcel Moolenaar #include "dir.h" 1093955d011SMarcel Moolenaar #include "job.h" 1103955d011SMarcel Moolenaar #include "pathnames.h" 1113955d011SMarcel Moolenaar #include "trace.h" 1123955d011SMarcel Moolenaar 113956e45f6SSimon J. Gerraty /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 114*c59c3bf3SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.612 2024/03/10 02:53:37 sjg Exp $"); 115d5e0a182SSimon J. Gerraty #if defined(MAKE_NATIVE) 116956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 117956e45f6SSimon J. Gerraty "The Regents of the University of California. " 118956e45f6SSimon J. Gerraty "All rights reserved."); 1193955d011SMarcel Moolenaar #endif 1203955d011SMarcel Moolenaar 1210dede8b0SSimon J. Gerraty #ifndef __arraycount 1220dede8b0SSimon J. Gerraty # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 1230dede8b0SSimon J. Gerraty #endif 1240dede8b0SSimon J. Gerraty 125956e45f6SSimon J. Gerraty CmdOpts opts; 1263955d011SMarcel Moolenaar time_t now; /* Time at start of make */ 127e2eeea75SSimon J. Gerraty GNode *defaultNode; /* .DEFAULT node */ 128d5e0a182SSimon J. Gerraty bool allPrecious; /* .PRECIOUS given on a line by itself */ 129b0c40a00SSimon J. Gerraty bool deleteOnError; /* .DELETE_ON_ERROR: set */ 1303955d011SMarcel Moolenaar 1313955d011SMarcel Moolenaar static int maxJobTokens; /* -j argument */ 1328c973ee2SSimon J. Gerraty static bool enterFlagObj; /* -w and objdir != srcdir */ 133956e45f6SSimon J. Gerraty 1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 135b0c40a00SSimon J. Gerraty bool doing_depend; /* Set while reading .depend */ 136b0c40a00SSimon J. Gerraty static bool jobsRunning; /* true if the jobs might be running */ 1373955d011SMarcel Moolenaar static const char *tracefile; 1389f45a3c8SSimon J. Gerraty static bool ReadMakefile(const char *); 139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void); 1403955d011SMarcel Moolenaar 141b0c40a00SSimon J. Gerraty static bool ignorePWD; /* if we use -C, PWD is meaningless */ 1423955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 1433955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1]; /* Startup directory */ 14406b9b3e0SSimon J. Gerraty const char *progname; 1453955d011SMarcel Moolenaar char *makeDependfile; 1463955d011SMarcel Moolenaar pid_t myPid; 14751ee2c1cSSimon J. Gerraty int makelevel; 1483955d011SMarcel Moolenaar 149b0c40a00SSimon J. Gerraty bool forceJobs = false; 15006b9b3e0SSimon J. Gerraty static int main_errors = 0; 151e2eeea75SSimon J. Gerraty static HashTable cached_realpaths; 1523955d011SMarcel Moolenaar 15351ee2c1cSSimon J. Gerraty /* 15451ee2c1cSSimon J. Gerraty * For compatibility with the POSIX version of MAKEFLAGS that includes 155e2eeea75SSimon J. Gerraty * all the options without '-', convert 'flags' to '-f -l -a -g -s '. 15651ee2c1cSSimon J. Gerraty */ 15751ee2c1cSSimon J. Gerraty static char * 15851ee2c1cSSimon J. Gerraty explode(const char *flags) 15951ee2c1cSSimon J. Gerraty { 1609f45a3c8SSimon J. Gerraty char *exploded, *ep; 1619f45a3c8SSimon J. Gerraty const char *p; 16251ee2c1cSSimon J. Gerraty 16351ee2c1cSSimon J. Gerraty if (flags == NULL) 16451ee2c1cSSimon J. Gerraty return NULL; 16551ee2c1cSSimon J. Gerraty 1669f45a3c8SSimon J. Gerraty for (p = flags; *p != '\0'; p++) 1679f45a3c8SSimon J. Gerraty if (!ch_isalpha(*p)) 16851ee2c1cSSimon J. Gerraty return bmake_strdup(flags); 16951ee2c1cSSimon J. Gerraty 1709f45a3c8SSimon J. Gerraty exploded = bmake_malloc((size_t)(p - flags) * 3 + 1); 1719f45a3c8SSimon J. Gerraty for (p = flags, ep = exploded; *p != '\0'; p++) { 1729f45a3c8SSimon J. Gerraty *ep++ = '-'; 1739f45a3c8SSimon J. Gerraty *ep++ = *p; 1749f45a3c8SSimon J. Gerraty *ep++ = ' '; 17551ee2c1cSSimon J. Gerraty } 1769f45a3c8SSimon J. Gerraty *ep = '\0'; 1779f45a3c8SSimon J. Gerraty return exploded; 17851ee2c1cSSimon J. Gerraty } 17951ee2c1cSSimon J. Gerraty 180e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void 181e2eeea75SSimon J. Gerraty usage(void) 182e2eeea75SSimon J. Gerraty { 183e2eeea75SSimon J. Gerraty size_t prognameLen = strcspn(progname, "["); 184e2eeea75SSimon J. Gerraty 185e2eeea75SSimon J. Gerraty (void)fprintf(stderr, 186e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n" 187e2eeea75SSimon J. Gerraty " [-C directory] [-D variable] [-d flags] [-f makefile]\n" 188e2eeea75SSimon J. Gerraty " [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 189e2eeea75SSimon J. Gerraty " [-V variable] [-v variable] [variable=value] [target ...]\n", 190e2eeea75SSimon J. Gerraty (int)prognameLen, progname); 191e2eeea75SSimon J. Gerraty exit(2); 192e2eeea75SSimon J. Gerraty } 193e2eeea75SSimon J. Gerraty 1943955d011SMarcel Moolenaar static void 195dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg) 1963955d011SMarcel Moolenaar { 1973955d011SMarcel Moolenaar const char *mode; 198956e45f6SSimon J. Gerraty size_t len; 1993955d011SMarcel Moolenaar char *fname; 2003955d011SMarcel Moolenaar 201956e45f6SSimon J. Gerraty if (opts.debug_file != stdout && opts.debug_file != stderr) 202956e45f6SSimon J. Gerraty fclose(opts.debug_file); 203956e45f6SSimon J. Gerraty 204dba7b0efSSimon J. Gerraty if (*arg == '+') { 205dba7b0efSSimon J. Gerraty arg++; 2063955d011SMarcel Moolenaar mode = "a"; 2073955d011SMarcel Moolenaar } else 2083955d011SMarcel Moolenaar mode = "w"; 209956e45f6SSimon J. Gerraty 210dba7b0efSSimon J. Gerraty if (strcmp(arg, "stdout") == 0) { 211956e45f6SSimon J. Gerraty opts.debug_file = stdout; 212956e45f6SSimon J. Gerraty return; 2133955d011SMarcel Moolenaar } 214dba7b0efSSimon J. Gerraty if (strcmp(arg, "stderr") == 0) { 215956e45f6SSimon J. Gerraty opts.debug_file = stderr; 216956e45f6SSimon J. Gerraty return; 2173955d011SMarcel Moolenaar } 218956e45f6SSimon J. Gerraty 219dba7b0efSSimon J. Gerraty len = strlen(arg); 220e1cee40dSSimon J. Gerraty fname = bmake_malloc(len + 20); 221dba7b0efSSimon J. Gerraty memcpy(fname, arg, len + 1); 222956e45f6SSimon J. Gerraty 2239f45a3c8SSimon J. Gerraty /* Replace the trailing '%d' after '.%d' with the pid. */ 2249f45a3c8SSimon J. Gerraty if (len >= 3 && memcmp(fname + len - 3, ".%d", 3) == 0) 2253955d011SMarcel Moolenaar snprintf(fname + len - 2, 20, "%d", getpid()); 226956e45f6SSimon J. Gerraty 227956e45f6SSimon J. Gerraty opts.debug_file = fopen(fname, mode); 228e2eeea75SSimon J. Gerraty if (opts.debug_file == NULL) { 229d5e0a182SSimon J. Gerraty fprintf(stderr, "Cannot open debug file \"%s\"\n", fname); 2309f45a3c8SSimon J. Gerraty exit(2); 2313955d011SMarcel Moolenaar } 2323955d011SMarcel Moolenaar free(fname); 233956e45f6SSimon J. Gerraty } 234956e45f6SSimon J. Gerraty 235956e45f6SSimon J. Gerraty static void 236dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue) 237956e45f6SSimon J. Gerraty { 238956e45f6SSimon J. Gerraty const char *modules; 239e2eeea75SSimon J. Gerraty DebugFlags debug = opts.debug; 240956e45f6SSimon J. Gerraty 241dba7b0efSSimon J. Gerraty for (modules = argvalue; *modules != '\0'; modules++) { 242956e45f6SSimon J. Gerraty switch (*modules) { 243956e45f6SSimon J. Gerraty case '0': /* undocumented, only intended for tests */ 2449f45a3c8SSimon J. Gerraty memset(&debug, 0, sizeof(debug)); 245956e45f6SSimon J. Gerraty break; 246956e45f6SSimon J. Gerraty case 'A': 2479f45a3c8SSimon J. Gerraty memset(&debug, ~0, sizeof(debug)); 248956e45f6SSimon J. Gerraty break; 249956e45f6SSimon J. Gerraty case 'a': 2509f45a3c8SSimon J. Gerraty debug.DEBUG_ARCH = true; 251956e45f6SSimon J. Gerraty break; 252956e45f6SSimon J. Gerraty case 'C': 2539f45a3c8SSimon J. Gerraty debug.DEBUG_CWD = true; 254956e45f6SSimon J. Gerraty break; 255956e45f6SSimon J. Gerraty case 'c': 2569f45a3c8SSimon J. Gerraty debug.DEBUG_COND = true; 257956e45f6SSimon J. Gerraty break; 258956e45f6SSimon J. Gerraty case 'd': 2599f45a3c8SSimon J. Gerraty debug.DEBUG_DIR = true; 260956e45f6SSimon J. Gerraty break; 261956e45f6SSimon J. Gerraty case 'e': 2629f45a3c8SSimon J. Gerraty debug.DEBUG_ERROR = true; 263956e45f6SSimon J. Gerraty break; 264956e45f6SSimon J. Gerraty case 'f': 2659f45a3c8SSimon J. Gerraty debug.DEBUG_FOR = true; 266956e45f6SSimon J. Gerraty break; 267956e45f6SSimon J. Gerraty case 'g': 268956e45f6SSimon J. Gerraty if (modules[1] == '1') { 2699f45a3c8SSimon J. Gerraty debug.DEBUG_GRAPH1 = true; 270e2eeea75SSimon J. Gerraty modules++; 271e2eeea75SSimon J. Gerraty } else if (modules[1] == '2') { 2729f45a3c8SSimon J. Gerraty debug.DEBUG_GRAPH2 = true; 273e2eeea75SSimon J. Gerraty modules++; 274e2eeea75SSimon J. Gerraty } else if (modules[1] == '3') { 2759f45a3c8SSimon J. Gerraty debug.DEBUG_GRAPH3 = true; 276e2eeea75SSimon J. Gerraty modules++; 277956e45f6SSimon J. Gerraty } 278956e45f6SSimon J. Gerraty break; 279956e45f6SSimon J. Gerraty case 'h': 2809f45a3c8SSimon J. Gerraty debug.DEBUG_HASH = true; 281956e45f6SSimon J. Gerraty break; 282956e45f6SSimon J. Gerraty case 'j': 2839f45a3c8SSimon J. Gerraty debug.DEBUG_JOB = true; 284956e45f6SSimon J. Gerraty break; 285956e45f6SSimon J. Gerraty case 'L': 286b0c40a00SSimon J. Gerraty opts.strict = true; 287956e45f6SSimon J. Gerraty break; 288956e45f6SSimon J. Gerraty case 'l': 2899f45a3c8SSimon J. Gerraty debug.DEBUG_LOUD = true; 290956e45f6SSimon J. Gerraty break; 291956e45f6SSimon J. Gerraty case 'M': 2929f45a3c8SSimon J. Gerraty debug.DEBUG_META = true; 293956e45f6SSimon J. Gerraty break; 294956e45f6SSimon J. Gerraty case 'm': 2959f45a3c8SSimon J. Gerraty debug.DEBUG_MAKE = true; 296956e45f6SSimon J. Gerraty break; 297956e45f6SSimon J. Gerraty case 'n': 2989f45a3c8SSimon J. Gerraty debug.DEBUG_SCRIPT = true; 299956e45f6SSimon J. Gerraty break; 300956e45f6SSimon J. Gerraty case 'p': 3019f45a3c8SSimon J. Gerraty debug.DEBUG_PARSE = true; 302956e45f6SSimon J. Gerraty break; 303956e45f6SSimon J. Gerraty case 's': 3049f45a3c8SSimon J. Gerraty debug.DEBUG_SUFF = true; 305956e45f6SSimon J. Gerraty break; 306956e45f6SSimon J. Gerraty case 't': 3079f45a3c8SSimon J. Gerraty debug.DEBUG_TARG = true; 308956e45f6SSimon J. Gerraty break; 309956e45f6SSimon J. Gerraty case 'V': 310b0c40a00SSimon J. Gerraty opts.debugVflag = true; 311956e45f6SSimon J. Gerraty break; 312956e45f6SSimon J. Gerraty case 'v': 3139f45a3c8SSimon J. Gerraty debug.DEBUG_VAR = true; 314956e45f6SSimon J. Gerraty break; 315956e45f6SSimon J. Gerraty case 'x': 3169f45a3c8SSimon J. Gerraty debug.DEBUG_SHELL = true; 317956e45f6SSimon J. Gerraty break; 318956e45f6SSimon J. Gerraty case 'F': 319dba7b0efSSimon J. Gerraty MainParseArgDebugFile(modules + 1); 3201d3f2ddcSSimon J. Gerraty goto finish; 3213955d011SMarcel Moolenaar default: 3223955d011SMarcel Moolenaar (void)fprintf(stderr, 3233955d011SMarcel Moolenaar "%s: illegal argument to d option -- %c\n", 3243955d011SMarcel Moolenaar progname, *modules); 3253955d011SMarcel Moolenaar usage(); 3263955d011SMarcel Moolenaar } 3273955d011SMarcel Moolenaar } 328e2eeea75SSimon J. Gerraty 3291d3f2ddcSSimon J. Gerraty finish: 330e2eeea75SSimon J. Gerraty opts.debug = debug; 331e2eeea75SSimon J. Gerraty 332956e45f6SSimon J. Gerraty setvbuf(opts.debug_file, NULL, _IONBF, 0); 3331d3f2ddcSSimon J. Gerraty if (opts.debug_file != stdout) 3343955d011SMarcel Moolenaar setvbuf(stdout, NULL, _IOLBF, 0); 3353955d011SMarcel Moolenaar } 3363955d011SMarcel Moolenaar 3371d3f2ddcSSimon J. Gerraty /* Is path relative or does it contain any relative component "." or ".."? */ 338b0c40a00SSimon J. Gerraty static bool 339dba7b0efSSimon J. Gerraty IsRelativePath(const char *path) 340e1cee40dSSimon J. Gerraty { 341b0c40a00SSimon J. Gerraty const char *p; 342e1cee40dSSimon J. Gerraty 343e1cee40dSSimon J. Gerraty if (path[0] != '/') 344b0c40a00SSimon J. Gerraty return true; 345b0c40a00SSimon J. Gerraty p = path; 346b0c40a00SSimon J. Gerraty while ((p = strstr(p, "/.")) != NULL) { 347b0c40a00SSimon J. Gerraty p += 2; 348b0c40a00SSimon J. Gerraty if (*p == '.') 349b0c40a00SSimon J. Gerraty p++; 350b0c40a00SSimon J. Gerraty if (*p == '/' || *p == '\0') 351b0c40a00SSimon J. Gerraty return true; 3522c3632d1SSimon J. Gerraty } 353b0c40a00SSimon J. Gerraty return false; 354e1cee40dSSimon J. Gerraty } 355e1cee40dSSimon J. Gerraty 356956e45f6SSimon J. Gerraty static void 357956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue) 358956e45f6SSimon J. Gerraty { 359956e45f6SSimon J. Gerraty struct stat sa, sb; 360956e45f6SSimon J. Gerraty 361956e45f6SSimon J. Gerraty if (chdir(argvalue) == -1) { 362956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: chdir %s: %s\n", 363956e45f6SSimon J. Gerraty progname, argvalue, strerror(errno)); 36406b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 365956e45f6SSimon J. Gerraty } 366956e45f6SSimon J. Gerraty if (getcwd(curdir, MAXPATHLEN) == NULL) { 367956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 368956e45f6SSimon J. Gerraty exit(2); 369956e45f6SSimon J. Gerraty } 370dba7b0efSSimon J. Gerraty if (!IsRelativePath(argvalue) && 371956e45f6SSimon J. Gerraty stat(argvalue, &sa) != -1 && 372956e45f6SSimon J. Gerraty stat(curdir, &sb) != -1 && 373956e45f6SSimon J. Gerraty sa.st_ino == sb.st_ino && 374956e45f6SSimon J. Gerraty sa.st_dev == sb.st_dev) 375956e45f6SSimon J. Gerraty strncpy(curdir, argvalue, MAXPATHLEN); 376b0c40a00SSimon J. Gerraty ignorePWD = true; 377956e45f6SSimon J. Gerraty } 378956e45f6SSimon J. Gerraty 379956e45f6SSimon J. Gerraty static void 380956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue) 381956e45f6SSimon J. Gerraty { 382e2eeea75SSimon J. Gerraty char end; 383e2eeea75SSimon J. Gerraty if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { 384956e45f6SSimon J. Gerraty (void)fprintf(stderr, 385956e45f6SSimon J. Gerraty "%s: internal error -- J option malformed (%s)\n", 386956e45f6SSimon J. Gerraty progname, argvalue); 387956e45f6SSimon J. Gerraty usage(); 388956e45f6SSimon J. Gerraty } 389956e45f6SSimon J. Gerraty if ((fcntl(jp_0, F_GETFD, 0) < 0) || 390956e45f6SSimon J. Gerraty (fcntl(jp_1, F_GETFD, 0) < 0)) { 391956e45f6SSimon J. Gerraty jp_0 = -1; 392956e45f6SSimon J. Gerraty jp_1 = -1; 393b0c40a00SSimon J. Gerraty opts.compatMake = true; 394956e45f6SSimon J. Gerraty } else { 395dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-J"); 396dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 397956e45f6SSimon J. Gerraty } 398956e45f6SSimon J. Gerraty } 399956e45f6SSimon J. Gerraty 400956e45f6SSimon J. Gerraty static void 40198875883SSimon J. Gerraty MainParseArgJobs(const char *arg) 402956e45f6SSimon J. Gerraty { 40398875883SSimon J. Gerraty const char *p; 40498875883SSimon J. Gerraty char *end; 40598875883SSimon J. Gerraty char v[12]; 406956e45f6SSimon J. Gerraty 407b0c40a00SSimon J. Gerraty forceJobs = true; 40898875883SSimon J. Gerraty opts.maxJobs = (int)strtol(arg, &end, 0); 409d5e0a182SSimon J. Gerraty p = end; 41098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN 41198875883SSimon J. Gerraty if (*p != '\0') { 41298875883SSimon J. Gerraty double d; 41398875883SSimon J. Gerraty 414d5e0a182SSimon J. Gerraty if (*p == 'C') 41598875883SSimon J. Gerraty d = (opts.maxJobs > 0) ? opts.maxJobs : 1; 416d5e0a182SSimon J. Gerraty else if (*p == '.') { 41798875883SSimon J. Gerraty d = strtod(arg, &end); 418d5e0a182SSimon J. Gerraty p = end; 41998875883SSimon J. Gerraty } else 420d5e0a182SSimon J. Gerraty d = 0.0; 421d5e0a182SSimon J. Gerraty if (d > 0.0) { 42298875883SSimon J. Gerraty p = ""; 42398875883SSimon J. Gerraty opts.maxJobs = (int)sysconf(_SC_NPROCESSORS_ONLN); 42498875883SSimon J. Gerraty opts.maxJobs = (int)(d * (double)opts.maxJobs); 42598875883SSimon J. Gerraty } 42698875883SSimon J. Gerraty } 42798875883SSimon J. Gerraty #endif 428956e45f6SSimon J. Gerraty if (*p != '\0' || opts.maxJobs < 1) { 429956e45f6SSimon J. Gerraty (void)fprintf(stderr, 43098875883SSimon J. Gerraty "%s: argument '%s' to option '-j' " 43198875883SSimon J. Gerraty "must be a positive number\n", 43298875883SSimon J. Gerraty progname, arg); 43306b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 434956e45f6SSimon J. Gerraty } 43598875883SSimon J. Gerraty snprintf(v, sizeof(v), "%d", opts.maxJobs); 436dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-j"); 43798875883SSimon J. Gerraty Global_Append(MAKEFLAGS, v); 43898875883SSimon J. Gerraty Global_Set(".MAKE.JOBS", v); 439956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 440956e45f6SSimon J. Gerraty } 441956e45f6SSimon J. Gerraty 442956e45f6SSimon J. Gerraty static void 443956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue) 444956e45f6SSimon J. Gerraty { 445d5e0a182SSimon J. Gerraty if (strncmp(argvalue, ".../", 4) == 0) { 446956e45f6SSimon J. Gerraty char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 447956e45f6SSimon J. Gerraty if (found_path == NULL) 448956e45f6SSimon J. Gerraty return; 449dba7b0efSSimon J. Gerraty (void)SearchPath_Add(sysIncPath, found_path); 450956e45f6SSimon J. Gerraty free(found_path); 451956e45f6SSimon J. Gerraty } else { 452dba7b0efSSimon J. Gerraty (void)SearchPath_Add(sysIncPath, argvalue); 453956e45f6SSimon J. Gerraty } 454dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-m"); 455dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 4564fde40d9SSimon J. Gerraty Dir_SetSYSPATH(); 457956e45f6SSimon J. Gerraty } 458956e45f6SSimon J. Gerraty 459b0c40a00SSimon J. Gerraty static bool 4608c973ee2SSimon J. Gerraty MainParseOption(char c, const char *argvalue) 461956e45f6SSimon J. Gerraty { 462956e45f6SSimon J. Gerraty switch (c) { 463956e45f6SSimon J. Gerraty case '\0': 464956e45f6SSimon J. Gerraty break; 465956e45f6SSimon J. Gerraty case 'B': 466b0c40a00SSimon J. Gerraty opts.compatMake = true; 467dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-B"); 4688c973ee2SSimon J. Gerraty Global_Set(".MAKE.MODE", "compat"); 469956e45f6SSimon J. Gerraty break; 470956e45f6SSimon J. Gerraty case 'C': 471956e45f6SSimon J. Gerraty MainParseArgChdir(argvalue); 472956e45f6SSimon J. Gerraty break; 473956e45f6SSimon J. Gerraty case 'D': 4749f45a3c8SSimon J. Gerraty if (argvalue[0] == '\0') 4759f45a3c8SSimon J. Gerraty return false; 4769f45a3c8SSimon J. Gerraty Var_SetExpand(SCOPE_GLOBAL, argvalue, "1"); 477dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-D"); 478dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 479956e45f6SSimon J. Gerraty break; 480956e45f6SSimon J. Gerraty case 'I': 481d5e0a182SSimon J. Gerraty SearchPath_Add(parseIncPath, argvalue); 482dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-I"); 483dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 484956e45f6SSimon J. Gerraty break; 485956e45f6SSimon J. Gerraty case 'J': 486956e45f6SSimon J. Gerraty MainParseArgJobsInternal(argvalue); 487956e45f6SSimon J. Gerraty break; 488956e45f6SSimon J. Gerraty case 'N': 489b0c40a00SSimon J. Gerraty opts.noExecute = true; 490b0c40a00SSimon J. Gerraty opts.noRecursiveExecute = true; 491dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-N"); 492956e45f6SSimon J. Gerraty break; 493956e45f6SSimon J. Gerraty case 'S': 494b0c40a00SSimon J. Gerraty opts.keepgoing = false; 495dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-S"); 496956e45f6SSimon J. Gerraty break; 497956e45f6SSimon J. Gerraty case 'T': 498956e45f6SSimon J. Gerraty tracefile = bmake_strdup(argvalue); 499dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-T"); 500dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 501956e45f6SSimon J. Gerraty break; 502956e45f6SSimon J. Gerraty case 'V': 503956e45f6SSimon J. Gerraty case 'v': 504e2eeea75SSimon J. Gerraty opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED; 50506b9b3e0SSimon J. Gerraty Lst_Append(&opts.variables, bmake_strdup(argvalue)); 506956e45f6SSimon J. Gerraty /* XXX: Why always -V? */ 507dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-V"); 508dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 509956e45f6SSimon J. Gerraty break; 510956e45f6SSimon J. Gerraty case 'W': 511b0c40a00SSimon J. Gerraty opts.parseWarnFatal = true; 5129f45a3c8SSimon J. Gerraty /* XXX: why no Global_Append? */ 513956e45f6SSimon J. Gerraty break; 514956e45f6SSimon J. Gerraty case 'X': 515b0c40a00SSimon J. Gerraty opts.varNoExportEnv = true; 516dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-X"); 517956e45f6SSimon J. Gerraty break; 518956e45f6SSimon J. Gerraty case 'd': 519956e45f6SSimon J. Gerraty /* If '-d-opts' don't pass to children */ 520956e45f6SSimon J. Gerraty if (argvalue[0] == '-') 521956e45f6SSimon J. Gerraty argvalue++; 522956e45f6SSimon J. Gerraty else { 523dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-d"); 524dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 525956e45f6SSimon J. Gerraty } 526dba7b0efSSimon J. Gerraty MainParseArgDebug(argvalue); 527956e45f6SSimon J. Gerraty break; 528956e45f6SSimon J. Gerraty case 'e': 529b0c40a00SSimon J. Gerraty opts.checkEnvFirst = true; 530dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-e"); 531956e45f6SSimon J. Gerraty break; 532956e45f6SSimon J. Gerraty case 'f': 53306b9b3e0SSimon J. Gerraty Lst_Append(&opts.makefiles, bmake_strdup(argvalue)); 534956e45f6SSimon J. Gerraty break; 535956e45f6SSimon J. Gerraty case 'i': 536b0c40a00SSimon J. Gerraty opts.ignoreErrors = true; 537dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-i"); 538956e45f6SSimon J. Gerraty break; 539956e45f6SSimon J. Gerraty case 'j': 540956e45f6SSimon J. Gerraty MainParseArgJobs(argvalue); 541956e45f6SSimon J. Gerraty break; 542956e45f6SSimon J. Gerraty case 'k': 543b0c40a00SSimon J. Gerraty opts.keepgoing = true; 544dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-k"); 545956e45f6SSimon J. Gerraty break; 546956e45f6SSimon J. Gerraty case 'm': 547956e45f6SSimon J. Gerraty MainParseArgSysInc(argvalue); 548e2eeea75SSimon J. Gerraty /* XXX: why no Var_Append? */ 549956e45f6SSimon J. Gerraty break; 550956e45f6SSimon J. Gerraty case 'n': 551b0c40a00SSimon J. Gerraty opts.noExecute = true; 552dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-n"); 553956e45f6SSimon J. Gerraty break; 554956e45f6SSimon J. Gerraty case 'q': 5559f45a3c8SSimon J. Gerraty opts.query = true; 556956e45f6SSimon J. Gerraty /* Kind of nonsensical, wot? */ 557dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-q"); 558956e45f6SSimon J. Gerraty break; 559956e45f6SSimon J. Gerraty case 'r': 560b0c40a00SSimon J. Gerraty opts.noBuiltins = true; 561dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-r"); 562956e45f6SSimon J. Gerraty break; 563956e45f6SSimon J. Gerraty case 's': 5649f45a3c8SSimon J. Gerraty opts.silent = true; 565dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-s"); 566956e45f6SSimon J. Gerraty break; 567956e45f6SSimon J. Gerraty case 't': 5689f45a3c8SSimon J. Gerraty opts.touch = true; 569dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-t"); 570956e45f6SSimon J. Gerraty break; 571956e45f6SSimon J. Gerraty case 'w': 572b0c40a00SSimon J. Gerraty opts.enterFlag = true; 573dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-w"); 574956e45f6SSimon J. Gerraty break; 575956e45f6SSimon J. Gerraty default: 576956e45f6SSimon J. Gerraty usage(); 577956e45f6SSimon J. Gerraty } 578b0c40a00SSimon J. Gerraty return true; 579956e45f6SSimon J. Gerraty } 580956e45f6SSimon J. Gerraty 58106b9b3e0SSimon J. Gerraty /* 58206b9b3e0SSimon J. Gerraty * Parse the given arguments. Called from main() and from 5833955d011SMarcel Moolenaar * Main_ParseArgLine() when the .MAKEFLAGS target is used. 5843955d011SMarcel Moolenaar * 585956e45f6SSimon J. Gerraty * The arguments must be treated as read-only and will be freed after the 586956e45f6SSimon J. Gerraty * call. 5873955d011SMarcel Moolenaar * 58806b9b3e0SSimon J. Gerraty * XXX: Deal with command line overriding .MAKEFLAGS in makefile 58906b9b3e0SSimon J. Gerraty */ 5903955d011SMarcel Moolenaar static void 5913955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv) 5923955d011SMarcel Moolenaar { 593956e45f6SSimon J. Gerraty char c; 5943955d011SMarcel Moolenaar int arginc; 5953955d011SMarcel Moolenaar char *argvalue; 5963955d011SMarcel Moolenaar char *optscan; 597b0c40a00SSimon J. Gerraty bool inOption, dashDash = false; 5983955d011SMarcel Moolenaar 599956e45f6SSimon J. Gerraty const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 6003955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */ 6013955d011SMarcel Moolenaar 6023955d011SMarcel Moolenaar rearg: 603b0c40a00SSimon J. Gerraty inOption = false; 6043955d011SMarcel Moolenaar optscan = NULL; 6053955d011SMarcel Moolenaar while (argc > 1) { 606956e45f6SSimon J. Gerraty const char *optspec; 6073955d011SMarcel Moolenaar if (!inOption) 6083955d011SMarcel Moolenaar optscan = argv[1]; 6093955d011SMarcel Moolenaar c = *optscan++; 6103955d011SMarcel Moolenaar arginc = 0; 6113955d011SMarcel Moolenaar if (inOption) { 6123955d011SMarcel Moolenaar if (c == '\0') { 613e2eeea75SSimon J. Gerraty argv++; 614e2eeea75SSimon J. Gerraty argc--; 615b0c40a00SSimon J. Gerraty inOption = false; 6163955d011SMarcel Moolenaar continue; 6173955d011SMarcel Moolenaar } 6183955d011SMarcel Moolenaar } else { 6193955d011SMarcel Moolenaar if (c != '-' || dashDash) 6203955d011SMarcel Moolenaar break; 621b0c40a00SSimon J. Gerraty inOption = true; 6223955d011SMarcel Moolenaar c = *optscan++; 6233955d011SMarcel Moolenaar } 6243955d011SMarcel Moolenaar /* '-' found at some earlier point */ 625956e45f6SSimon J. Gerraty optspec = strchr(optspecs, c); 626956e45f6SSimon J. Gerraty if (c != '\0' && optspec != NULL && optspec[1] == ':') { 6279f45a3c8SSimon J. Gerraty /* 6289f45a3c8SSimon J. Gerraty * -<something> found, and <something> should have an 6299f45a3c8SSimon J. Gerraty * argument 6309f45a3c8SSimon J. Gerraty */ 631b0c40a00SSimon J. Gerraty inOption = false; 6323955d011SMarcel Moolenaar arginc = 1; 6333955d011SMarcel Moolenaar argvalue = optscan; 6343955d011SMarcel Moolenaar if (*argvalue == '\0') { 6353955d011SMarcel Moolenaar if (argc < 3) 6363955d011SMarcel Moolenaar goto noarg; 6373955d011SMarcel Moolenaar argvalue = argv[2]; 6383955d011SMarcel Moolenaar arginc = 2; 6393955d011SMarcel Moolenaar } 6403955d011SMarcel Moolenaar } else { 6413955d011SMarcel Moolenaar argvalue = NULL; 6423955d011SMarcel Moolenaar } 6433955d011SMarcel Moolenaar switch (c) { 6443955d011SMarcel Moolenaar case '\0': 6453955d011SMarcel Moolenaar arginc = 1; 646b0c40a00SSimon J. Gerraty inOption = false; 6473955d011SMarcel Moolenaar break; 6483955d011SMarcel Moolenaar case '-': 649b0c40a00SSimon J. Gerraty dashDash = true; 6503955d011SMarcel Moolenaar break; 6513955d011SMarcel Moolenaar default: 6528c973ee2SSimon J. Gerraty if (!MainParseOption(c, argvalue)) 653956e45f6SSimon J. Gerraty goto noarg; 6543955d011SMarcel Moolenaar } 6553955d011SMarcel Moolenaar argv += arginc; 6563955d011SMarcel Moolenaar argc -= arginc; 6573955d011SMarcel Moolenaar } 6583955d011SMarcel Moolenaar 6593955d011SMarcel Moolenaar /* 6603955d011SMarcel Moolenaar * See if the rest of the arguments are variable assignments and 6613955d011SMarcel Moolenaar * perform them if so. Else take them to be targets and stuff them 6623955d011SMarcel Moolenaar * on the end of the "create" list. 6633955d011SMarcel Moolenaar */ 664dba7b0efSSimon J. Gerraty for (; argc > 1; argv++, argc--) { 6659f45a3c8SSimon J. Gerraty if (!Parse_VarAssign(argv[1], false, SCOPE_CMDLINE)) { 666e2eeea75SSimon J. Gerraty if (argv[1][0] == '\0') 6673955d011SMarcel Moolenaar Punt("illegal (null) argument."); 668e2eeea75SSimon J. Gerraty if (argv[1][0] == '-' && !dashDash) 6693955d011SMarcel Moolenaar goto rearg; 67006b9b3e0SSimon J. Gerraty Lst_Append(&opts.create, bmake_strdup(argv[1])); 671956e45f6SSimon J. Gerraty } 6723955d011SMarcel Moolenaar } 6733955d011SMarcel Moolenaar 6743955d011SMarcel Moolenaar return; 6753955d011SMarcel Moolenaar noarg: 6763955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 6773955d011SMarcel Moolenaar progname, c); 6783955d011SMarcel Moolenaar usage(); 6793955d011SMarcel Moolenaar } 6803955d011SMarcel Moolenaar 68106b9b3e0SSimon J. Gerraty /* 68206b9b3e0SSimon J. Gerraty * Break a line of arguments into words and parse them. 6833955d011SMarcel Moolenaar * 684956e45f6SSimon J. Gerraty * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 68506b9b3e0SSimon J. Gerraty * by main() when reading the MAKEFLAGS environment variable. 68606b9b3e0SSimon J. Gerraty */ 6873955d011SMarcel Moolenaar void 6883955d011SMarcel Moolenaar Main_ParseArgLine(const char *line) 6893955d011SMarcel Moolenaar { 6902c3632d1SSimon J. Gerraty Words words; 6912c3632d1SSimon J. Gerraty char *buf; 692d5e0a182SSimon J. Gerraty const char *p; 6933955d011SMarcel Moolenaar 6943955d011SMarcel Moolenaar if (line == NULL) 6953955d011SMarcel Moolenaar return; 696d5e0a182SSimon J. Gerraty for (p = line; *p == ' '; p++) 6973955d011SMarcel Moolenaar continue; 698d5e0a182SSimon J. Gerraty if (p[0] == '\0') 6993955d011SMarcel Moolenaar return; 7003955d011SMarcel Moolenaar 701e2eeea75SSimon J. Gerraty { 702dba7b0efSSimon J. Gerraty FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE"); 703d5e0a182SSimon J. Gerraty buf = str_concat3(argv0.str, " ", p); 70406b9b3e0SSimon J. Gerraty FStr_Done(&argv0); 705e2eeea75SSimon J. Gerraty } 7063955d011SMarcel Moolenaar 707b0c40a00SSimon J. Gerraty words = Str_Words(buf, true); 7082c3632d1SSimon J. Gerraty if (words.words == NULL) { 7093955d011SMarcel Moolenaar Error("Unterminated quoted string [%s]", buf); 7103955d011SMarcel Moolenaar free(buf); 7113955d011SMarcel Moolenaar return; 7123955d011SMarcel Moolenaar } 7133955d011SMarcel Moolenaar free(buf); 7142c3632d1SSimon J. Gerraty MainParseArgs((int)words.len, words.words); 7153955d011SMarcel Moolenaar 7162c3632d1SSimon J. Gerraty Words_Free(words); 7173955d011SMarcel Moolenaar } 7183955d011SMarcel Moolenaar 719b0c40a00SSimon J. Gerraty bool 720b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...) 7213955d011SMarcel Moolenaar { 7223955d011SMarcel Moolenaar struct stat sb; 723b46b9039SSimon J. Gerraty char *path; 724b46b9039SSimon J. Gerraty char buf[MAXPATHLEN + 1]; 725e23f3f6eSSimon J. Gerraty char buf2[MAXPATHLEN + 1]; 72645447996SSimon J. Gerraty va_list ap; 72745447996SSimon J. Gerraty 72845447996SSimon J. Gerraty va_start(ap, fmt); 729b46b9039SSimon J. Gerraty vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 73045447996SSimon J. Gerraty va_end(ap); 7313955d011SMarcel Moolenaar 7323955d011SMarcel Moolenaar if (path[0] != '/') { 7334fde40d9SSimon J. Gerraty if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN) 734e1cee40dSSimon J. Gerraty path = buf2; 7354fde40d9SSimon J. Gerraty else 7364fde40d9SSimon J. Gerraty return false; 7373955d011SMarcel Moolenaar } 7383955d011SMarcel Moolenaar 7393955d011SMarcel Moolenaar /* look for the directory and try to chdir there */ 7409f45a3c8SSimon J. Gerraty if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode)) 7419f45a3c8SSimon J. Gerraty return false; 7429f45a3c8SSimon J. Gerraty 7439f45a3c8SSimon J. Gerraty if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) { 7441d3f2ddcSSimon J. Gerraty (void)fprintf(stderr, "%s: warning: %s: %s.\n", 745e2eeea75SSimon J. Gerraty progname, path, strerror(errno)); 7469f45a3c8SSimon J. Gerraty return false; 7479f45a3c8SSimon J. Gerraty } 7489f45a3c8SSimon J. Gerraty 7492c3632d1SSimon J. Gerraty snprintf(objdir, sizeof objdir, "%s", path); 750dba7b0efSSimon J. Gerraty Global_Set(".OBJDIR", objdir); 7513955d011SMarcel Moolenaar setenv("PWD", objdir, 1); 7523955d011SMarcel Moolenaar Dir_InitDot(); 753e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(); 754956e45f6SSimon J. Gerraty if (opts.enterFlag && strcmp(objdir, curdir) != 0) 755b0c40a00SSimon J. Gerraty enterFlagObj = true; 7569f45a3c8SSimon J. Gerraty return true; 7573955d011SMarcel Moolenaar } 7583955d011SMarcel Moolenaar 759b0c40a00SSimon J. Gerraty static bool 760b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix) 76145447996SSimon J. Gerraty { 762dba7b0efSSimon J. Gerraty FStr path = Var_Value(SCOPE_CMDLINE, var); 763b46b9039SSimon J. Gerraty 76406b9b3e0SSimon J. Gerraty if (path.str == NULL || path.str[0] == '\0') { 76506b9b3e0SSimon J. Gerraty FStr_Done(&path); 766b0c40a00SSimon J. Gerraty return false; 7672c3632d1SSimon J. Gerraty } 76845447996SSimon J. Gerraty 7699f45a3c8SSimon J. Gerraty Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES); 770b46b9039SSimon J. Gerraty 7719f45a3c8SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", path.str, suffix); 772b46b9039SSimon J. Gerraty 77306b9b3e0SSimon J. Gerraty FStr_Done(&path); 774b0c40a00SSimon J. Gerraty return true; 77545447996SSimon J. Gerraty } 77645447996SSimon J. Gerraty 77706b9b3e0SSimon J. Gerraty /* 778d5e0a182SSimon J. Gerraty * Splits str into words (in-place, modifying it), adding them to the list. 77906b9b3e0SSimon J. Gerraty * The string must be kept alive as long as the list. 78006b9b3e0SSimon J. Gerraty */ 781d5e0a182SSimon J. Gerraty void 782d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str) 7833955d011SMarcel Moolenaar { 784d5e0a182SSimon J. Gerraty char *p; 785e2eeea75SSimon J. Gerraty const char *sep = " \t"; 7863955d011SMarcel Moolenaar 787d5e0a182SSimon J. Gerraty for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep)) 788d5e0a182SSimon J. Gerraty Lst_Append(lp, p); 7893955d011SMarcel Moolenaar } 7903955d011SMarcel Moolenaar 7913955d011SMarcel Moolenaar #ifdef SIGINFO 7923955d011SMarcel Moolenaar /*ARGSUSED*/ 7933955d011SMarcel Moolenaar static void 7943955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED) 7953955d011SMarcel Moolenaar { 7963955d011SMarcel Moolenaar char dir[MAXPATHLEN]; 7973955d011SMarcel Moolenaar char str[2 * MAXPATHLEN]; 7983955d011SMarcel Moolenaar int len; 799e2eeea75SSimon J. Gerraty if (getcwd(dir, sizeof dir) == NULL) 8003955d011SMarcel Moolenaar return; 801e2eeea75SSimon J. Gerraty len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir); 8023955d011SMarcel Moolenaar if (len > 0) 8033955d011SMarcel Moolenaar (void)write(STDERR_FILENO, str, (size_t)len); 8043955d011SMarcel Moolenaar } 8053955d011SMarcel Moolenaar #endif 8063955d011SMarcel Moolenaar 80706b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */ 80806b9b3e0SSimon J. Gerraty static void 80906b9b3e0SSimon J. Gerraty MakeMode(void) 8103955d011SMarcel Moolenaar { 8118c973ee2SSimon J. Gerraty char *mode = Var_Subst("${.MAKE.MODE:tl}", 8128c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 813956e45f6SSimon J. Gerraty /* TODO: handle errors */ 8143955d011SMarcel Moolenaar 815dba7b0efSSimon J. Gerraty if (mode[0] != '\0') { 816dba7b0efSSimon J. Gerraty if (strstr(mode, "compat") != NULL) { 817b0c40a00SSimon J. Gerraty opts.compatMake = true; 818b0c40a00SSimon J. Gerraty forceJobs = false; 8193955d011SMarcel Moolenaar } 8203955d011SMarcel Moolenaar #if USE_META 821dba7b0efSSimon J. Gerraty if (strstr(mode, "meta") != NULL) 822dba7b0efSSimon J. Gerraty meta_mode_init(mode); 8233955d011SMarcel Moolenaar #endif 824954401e6SSimon J. Gerraty if (strstr(mode, "randomize-targets") != NULL) 825954401e6SSimon J. Gerraty opts.randomizeTargets = true; 8263955d011SMarcel Moolenaar } 827be19d90bSSimon J. Gerraty 828dba7b0efSSimon J. Gerraty free(mode); 8293955d011SMarcel Moolenaar } 8303955d011SMarcel Moolenaar 8318695518cSSimon J. Gerraty static void 832b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars) 833956e45f6SSimon J. Gerraty { 83406b9b3e0SSimon J. Gerraty if (strchr(varname, '$') != NULL) { 8358c973ee2SSimon J. Gerraty char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES); 836956e45f6SSimon J. Gerraty /* TODO: handle errors */ 837956e45f6SSimon J. Gerraty printf("%s\n", evalue); 8389f45a3c8SSimon J. Gerraty free(evalue); 839956e45f6SSimon J. Gerraty 840956e45f6SSimon J. Gerraty } else if (expandVars) { 841956e45f6SSimon J. Gerraty char *expr = str_concat3("${", varname, "}"); 8428c973ee2SSimon J. Gerraty char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); 843956e45f6SSimon J. Gerraty /* TODO: handle errors */ 844956e45f6SSimon J. Gerraty free(expr); 845956e45f6SSimon J. Gerraty printf("%s\n", evalue); 8469f45a3c8SSimon J. Gerraty free(evalue); 847956e45f6SSimon J. Gerraty 848956e45f6SSimon J. Gerraty } else { 849dba7b0efSSimon J. Gerraty FStr value = Var_Value(SCOPE_GLOBAL, varname); 85006b9b3e0SSimon J. Gerraty printf("%s\n", value.str != NULL ? value.str : ""); 85106b9b3e0SSimon J. Gerraty FStr_Done(&value); 852956e45f6SSimon J. Gerraty } 853956e45f6SSimon J. Gerraty } 854956e45f6SSimon J. Gerraty 855e2eeea75SSimon J. Gerraty /* 856b0c40a00SSimon J. Gerraty * Return a bool based on a variable. 857e2eeea75SSimon J. Gerraty * 858e2eeea75SSimon J. Gerraty * If the knob is not set, return the fallback. 859e2eeea75SSimon J. Gerraty * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 860b0c40a00SSimon J. Gerraty * is false, otherwise true. 861e2eeea75SSimon J. Gerraty */ 862b0c40a00SSimon J. Gerraty bool 863b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback) 864e2eeea75SSimon J. Gerraty { 865e2eeea75SSimon J. Gerraty char *value; 866b0c40a00SSimon J. Gerraty bool res; 867e2eeea75SSimon J. Gerraty 8688c973ee2SSimon J. Gerraty value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); 869e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 870e2eeea75SSimon J. Gerraty res = ParseBoolean(value, fallback); 871e2eeea75SSimon J. Gerraty free(value); 872e2eeea75SSimon J. Gerraty return res; 873e2eeea75SSimon J. Gerraty } 874e2eeea75SSimon J. Gerraty 875956e45f6SSimon J. Gerraty static void 8768695518cSSimon J. Gerraty doPrintVars(void) 8778695518cSSimon J. Gerraty { 878956e45f6SSimon J. Gerraty StringListNode *ln; 879b0c40a00SSimon J. Gerraty bool expandVars; 8808695518cSSimon J. Gerraty 881e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_EXPANDED) 882b0c40a00SSimon J. Gerraty expandVars = true; 883956e45f6SSimon J. Gerraty else if (opts.debugVflag) 884b0c40a00SSimon J. Gerraty expandVars = false; 8858695518cSSimon J. Gerraty else 886b0c40a00SSimon J. Gerraty expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}", 887b0c40a00SSimon J. Gerraty false); 8888695518cSSimon J. Gerraty 88906b9b3e0SSimon J. Gerraty for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 890956e45f6SSimon J. Gerraty const char *varname = ln->datum; 891956e45f6SSimon J. Gerraty PrintVar(varname, expandVars); 8928695518cSSimon J. Gerraty } 8938695518cSSimon J. Gerraty } 8948695518cSSimon J. Gerraty 895b0c40a00SSimon J. Gerraty static bool 8968695518cSSimon J. Gerraty runTargets(void) 8978695518cSSimon J. Gerraty { 89806b9b3e0SSimon J. Gerraty GNodeList targs = LST_INIT; /* target nodes to create */ 899b0c40a00SSimon J. Gerraty bool outOfDate; /* false if all targets up to date */ 9008695518cSSimon J. Gerraty 9018695518cSSimon J. Gerraty /* 9028695518cSSimon J. Gerraty * Have now read the entire graph and need to make a list of 9038695518cSSimon J. Gerraty * targets to create. If none was given on the command line, 9048695518cSSimon J. Gerraty * we consult the parsing module to find the main target(s) 9058695518cSSimon J. Gerraty * to create. 9068695518cSSimon J. Gerraty */ 90706b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) 90806b9b3e0SSimon J. Gerraty Parse_MainName(&targs); 9098695518cSSimon J. Gerraty else 91006b9b3e0SSimon J. Gerraty Targ_FindList(&targs, &opts.create); 9118695518cSSimon J. Gerraty 912956e45f6SSimon J. Gerraty if (!opts.compatMake) { 9138695518cSSimon J. Gerraty /* 9148695518cSSimon J. Gerraty * Initialize job module before traversing the graph 9158695518cSSimon J. Gerraty * now that any .BEGIN and .END targets have been read. 9168695518cSSimon J. Gerraty * This is done only if the -q flag wasn't given 9178695518cSSimon J. Gerraty * (to prevent the .BEGIN from being executed should 9188695518cSSimon J. Gerraty * it exist). 9198695518cSSimon J. Gerraty */ 9209f45a3c8SSimon J. Gerraty if (!opts.query) { 9218695518cSSimon J. Gerraty Job_Init(); 922b0c40a00SSimon J. Gerraty jobsRunning = true; 9238695518cSSimon J. Gerraty } 9248695518cSSimon J. Gerraty 9258695518cSSimon J. Gerraty /* Traverse the graph, checking on all the targets */ 92606b9b3e0SSimon J. Gerraty outOfDate = Make_Run(&targs); 9278695518cSSimon J. Gerraty } else { 928954401e6SSimon J. Gerraty Compat_MakeAll(&targs); 929b0c40a00SSimon J. Gerraty outOfDate = false; 9308695518cSSimon J. Gerraty } 931dba7b0efSSimon J. Gerraty Lst_Done(&targs); /* Don't free the targets themselves. */ 9328695518cSSimon J. Gerraty return outOfDate; 9338695518cSSimon J. Gerraty } 9348695518cSSimon J. Gerraty 935956e45f6SSimon J. Gerraty /* 9369f45a3c8SSimon J. Gerraty * Set up the .TARGETS variable to contain the list of targets to be created. 9379f45a3c8SSimon J. Gerraty * If none specified, make the variable empty for now, the parser will fill 9389f45a3c8SSimon J. Gerraty * in the default or .MAIN target later. 939956e45f6SSimon J. Gerraty */ 940956e45f6SSimon J. Gerraty static void 941956e45f6SSimon J. Gerraty InitVarTargets(void) 942956e45f6SSimon J. Gerraty { 943956e45f6SSimon J. Gerraty StringListNode *ln; 944956e45f6SSimon J. Gerraty 94506b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) { 946dba7b0efSSimon J. Gerraty Global_Set(".TARGETS", ""); 947956e45f6SSimon J. Gerraty return; 948956e45f6SSimon J. Gerraty } 949956e45f6SSimon J. Gerraty 95006b9b3e0SSimon J. Gerraty for (ln = opts.create.first; ln != NULL; ln = ln->next) { 951dba7b0efSSimon J. Gerraty const char *name = ln->datum; 952dba7b0efSSimon J. Gerraty Global_Append(".TARGETS", name); 953956e45f6SSimon J. Gerraty } 954956e45f6SSimon J. Gerraty } 955956e45f6SSimon J. Gerraty 956956e45f6SSimon J. Gerraty static void 957956e45f6SSimon J. Gerraty InitRandom(void) 958956e45f6SSimon J. Gerraty { 959956e45f6SSimon J. Gerraty struct timeval tv; 960956e45f6SSimon J. Gerraty 961956e45f6SSimon J. Gerraty gettimeofday(&tv, NULL); 962956e45f6SSimon J. Gerraty srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 963956e45f6SSimon J. Gerraty } 964956e45f6SSimon J. Gerraty 965956e45f6SSimon J. Gerraty static const char * 966dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED) 967956e45f6SSimon J. Gerraty { 968956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE 969e2eeea75SSimon J. Gerraty return FORCE_MACHINE; 970956e45f6SSimon J. Gerraty #else 971956e45f6SSimon J. Gerraty const char *machine = getenv("MACHINE"); 972e2eeea75SSimon J. Gerraty 973956e45f6SSimon J. Gerraty if (machine != NULL) 974956e45f6SSimon J. Gerraty return machine; 975956e45f6SSimon J. Gerraty 976e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE) 977956e45f6SSimon J. Gerraty return utsname->machine; 978e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE) 979956e45f6SSimon J. Gerraty return MAKE_MACHINE; 980956e45f6SSimon J. Gerraty #else 981956e45f6SSimon J. Gerraty return "unknown"; 982956e45f6SSimon J. Gerraty #endif 983956e45f6SSimon J. Gerraty #endif 984956e45f6SSimon J. Gerraty } 985956e45f6SSimon J. Gerraty 986956e45f6SSimon J. Gerraty static const char * 987e2eeea75SSimon J. Gerraty InitVarMachineArch(void) 988956e45f6SSimon J. Gerraty { 989e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH 990e2eeea75SSimon J. Gerraty return FORCE_MACHINE_ARCH; 991e2eeea75SSimon J. Gerraty #else 992956e45f6SSimon J. Gerraty const char *env = getenv("MACHINE_ARCH"); 993956e45f6SSimon J. Gerraty if (env != NULL) 994956e45f6SSimon J. Gerraty return env; 995956e45f6SSimon J. Gerraty 996956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW) 997956e45f6SSimon J. Gerraty { 998956e45f6SSimon J. Gerraty struct utsname utsname; 999e2eeea75SSimon J. Gerraty static char machine_arch_buf[sizeof utsname.machine]; 1000956e45f6SSimon J. Gerraty const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1001e2eeea75SSimon J. Gerraty size_t len = sizeof machine_arch_buf; 1002956e45f6SSimon J. Gerraty 100306b9b3e0SSimon J. Gerraty if (sysctl(mib, (unsigned int)__arraycount(mib), 100406b9b3e0SSimon J. Gerraty machine_arch_buf, &len, NULL, 0) < 0) { 100506b9b3e0SSimon J. Gerraty (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 100606b9b3e0SSimon J. Gerraty progname, strerror(errno)); 1007956e45f6SSimon J. Gerraty exit(2); 1008956e45f6SSimon J. Gerraty } 1009956e45f6SSimon J. Gerraty 1010956e45f6SSimon J. Gerraty return machine_arch_buf; 1011956e45f6SSimon J. Gerraty } 1012e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH) 1013e2eeea75SSimon J. Gerraty return MACHINE_ARCH; 1014e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH) 1015956e45f6SSimon J. Gerraty return MAKE_MACHINE_ARCH; 1016956e45f6SSimon J. Gerraty #else 1017956e45f6SSimon J. Gerraty return "unknown"; 1018956e45f6SSimon J. Gerraty #endif 1019956e45f6SSimon J. Gerraty #endif 1020956e45f6SSimon J. Gerraty } 1021956e45f6SSimon J. Gerraty 1022956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE 1023956e45f6SSimon J. Gerraty /* 1024956e45f6SSimon J. Gerraty * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1025956e45f6SSimon J. Gerraty * since the value of curdir can vary depending on how we got 1026d5e0a182SSimon J. Gerraty * here. That is, sitting at a shell prompt (shell that provides $PWD) 1027d5e0a182SSimon J. Gerraty * or via subdir.mk, in which case it's likely a shell which does 1028956e45f6SSimon J. Gerraty * not provide it. 1029956e45f6SSimon J. Gerraty * 1030956e45f6SSimon J. Gerraty * So, to stop it breaking this case only, we ignore PWD if 1031d5e0a182SSimon J. Gerraty * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression. 1032956e45f6SSimon J. Gerraty */ 1033956e45f6SSimon J. Gerraty static void 1034956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st) 1035956e45f6SSimon J. Gerraty { 1036956e45f6SSimon J. Gerraty char *pwd; 10379f45a3c8SSimon J. Gerraty FStr makeobjdir; 1038956e45f6SSimon J. Gerraty struct stat pwd_st; 1039956e45f6SSimon J. Gerraty 1040956e45f6SSimon J. Gerraty if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1041956e45f6SSimon J. Gerraty return; 1042956e45f6SSimon J. Gerraty 10439f45a3c8SSimon J. Gerraty if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX")) 1044956e45f6SSimon J. Gerraty return; 1045956e45f6SSimon J. Gerraty 1046dba7b0efSSimon J. Gerraty makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR"); 104706b9b3e0SSimon J. Gerraty if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1048956e45f6SSimon J. Gerraty goto ignore_pwd; 1049956e45f6SSimon J. Gerraty 1050956e45f6SSimon J. Gerraty if (stat(pwd, &pwd_st) == 0 && 1051956e45f6SSimon J. Gerraty curdir_st->st_ino == pwd_st.st_ino && 1052956e45f6SSimon J. Gerraty curdir_st->st_dev == pwd_st.st_dev) 1053956e45f6SSimon J. Gerraty (void)strncpy(curdir, pwd, MAXPATHLEN); 1054956e45f6SSimon J. Gerraty 1055956e45f6SSimon J. Gerraty ignore_pwd: 105606b9b3e0SSimon J. Gerraty FStr_Done(&makeobjdir); 1057956e45f6SSimon J. Gerraty } 1058956e45f6SSimon J. Gerraty #endif 1059956e45f6SSimon J. Gerraty 1060956e45f6SSimon J. Gerraty /* 10619f45a3c8SSimon J. Gerraty * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set 10629f45a3c8SSimon J. Gerraty * in the environment, try only that value and fall back to .CURDIR if it 10639f45a3c8SSimon J. Gerraty * does not exist. 1064956e45f6SSimon J. Gerraty * 1065956e45f6SSimon J. Gerraty * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 10669f45a3c8SSimon J. Gerraty * and finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none of these 10679f45a3c8SSimon J. Gerraty * paths exist, just use .CURDIR. 1068956e45f6SSimon J. Gerraty */ 1069956e45f6SSimon J. Gerraty static void 1070956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch) 1071956e45f6SSimon J. Gerraty { 1072b0c40a00SSimon J. Gerraty bool writable; 1073956e45f6SSimon J. Gerraty 107406b9b3e0SSimon J. Gerraty Dir_InitCur(curdir); 1075b0c40a00SSimon J. Gerraty writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true); 1076b0c40a00SSimon J. Gerraty (void)Main_SetObjdir(false, "%s", curdir); 1077e2eeea75SSimon J. Gerraty 1078e2eeea75SSimon J. Gerraty if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1079e2eeea75SSimon J. Gerraty !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1080e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1081e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1082e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1083e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1084956e45f6SSimon J. Gerraty } 1085956e45f6SSimon J. Gerraty 1086956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */ 1087956e45f6SSimon J. Gerraty static void 1088956e45f6SSimon J. Gerraty UnlimitFiles(void) 1089956e45f6SSimon J. Gerraty { 109012904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) 1091956e45f6SSimon J. Gerraty struct rlimit rl; 1092956e45f6SSimon J. Gerraty if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1093956e45f6SSimon J. Gerraty rl.rlim_cur != rl.rlim_max) { 10948c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX 10958c973ee2SSimon J. Gerraty if (BMAKE_NOFILE_MAX < rl.rlim_max) 10968c973ee2SSimon J. Gerraty rl.rlim_cur = BMAKE_NOFILE_MAX; 10978c973ee2SSimon J. Gerraty else 10988c973ee2SSimon J. Gerraty #endif 1099956e45f6SSimon J. Gerraty rl.rlim_cur = rl.rlim_max; 1100956e45f6SSimon J. Gerraty (void)setrlimit(RLIMIT_NOFILE, &rl); 1101956e45f6SSimon J. Gerraty } 1102956e45f6SSimon J. Gerraty #endif 1103956e45f6SSimon J. Gerraty } 1104956e45f6SSimon J. Gerraty 1105956e45f6SSimon J. Gerraty static void 1106956e45f6SSimon J. Gerraty CmdOpts_Init(void) 1107956e45f6SSimon J. Gerraty { 1108b0c40a00SSimon J. Gerraty opts.compatMake = false; 11099f45a3c8SSimon J. Gerraty memset(&opts.debug, 0, sizeof(opts.debug)); 1110dba7b0efSSimon J. Gerraty /* opts.debug_file has already been initialized earlier */ 1111b0c40a00SSimon J. Gerraty opts.strict = false; 1112b0c40a00SSimon J. Gerraty opts.debugVflag = false; 1113b0c40a00SSimon J. Gerraty opts.checkEnvFirst = false; 111406b9b3e0SSimon J. Gerraty Lst_Init(&opts.makefiles); 1115b0c40a00SSimon J. Gerraty opts.ignoreErrors = false; /* Pay attention to non-zero returns */ 111606b9b3e0SSimon J. Gerraty opts.maxJobs = 1; 1117b0c40a00SSimon J. Gerraty opts.keepgoing = false; /* Stop on error */ 1118b0c40a00SSimon J. Gerraty opts.noRecursiveExecute = false; /* Execute all .MAKE targets */ 1119b0c40a00SSimon J. Gerraty opts.noExecute = false; /* Execute all commands */ 11209f45a3c8SSimon J. Gerraty opts.query = false; 1121b0c40a00SSimon J. Gerraty opts.noBuiltins = false; /* Read the built-in rules */ 11229f45a3c8SSimon J. Gerraty opts.silent = false; /* Print commands as executed */ 11239f45a3c8SSimon J. Gerraty opts.touch = false; 1124e2eeea75SSimon J. Gerraty opts.printVars = PVM_NONE; 112506b9b3e0SSimon J. Gerraty Lst_Init(&opts.variables); 1126b0c40a00SSimon J. Gerraty opts.parseWarnFatal = false; 1127b0c40a00SSimon J. Gerraty opts.enterFlag = false; 1128b0c40a00SSimon J. Gerraty opts.varNoExportEnv = false; 112906b9b3e0SSimon J. Gerraty Lst_Init(&opts.create); 1130956e45f6SSimon J. Gerraty } 1131956e45f6SSimon J. Gerraty 113206b9b3e0SSimon J. Gerraty /* 113306b9b3e0SSimon J. Gerraty * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1134956e45f6SSimon J. Gerraty * found by execvp(3) and the shells, even after a chdir. 1135956e45f6SSimon J. Gerraty * 1136956e45f6SSimon J. Gerraty * If it's a relative path and contains a '/', resolve it to an absolute path. 113706b9b3e0SSimon J. Gerraty * Otherwise keep it as is, assuming it will be found in the PATH. 113806b9b3e0SSimon J. Gerraty */ 1139956e45f6SSimon J. Gerraty static void 1140956e45f6SSimon J. Gerraty InitVarMake(const char *argv0) 1141956e45f6SSimon J. Gerraty { 1142956e45f6SSimon J. Gerraty const char *make = argv0; 1143956e45f6SSimon J. Gerraty 1144956e45f6SSimon J. Gerraty if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1145956e45f6SSimon J. Gerraty char pathbuf[MAXPATHLEN]; 114606b9b3e0SSimon J. Gerraty const char *abspath = cached_realpath(argv0, pathbuf); 1147956e45f6SSimon J. Gerraty struct stat st; 114806b9b3e0SSimon J. Gerraty if (abspath != NULL && abspath[0] == '/' && 114906b9b3e0SSimon J. Gerraty stat(make, &st) == 0) 115006b9b3e0SSimon J. Gerraty make = abspath; 1151956e45f6SSimon J. Gerraty } 1152956e45f6SSimon J. Gerraty 1153dba7b0efSSimon J. Gerraty Global_Set("MAKE", make); 1154dba7b0efSSimon J. Gerraty Global_Set(".MAKE", make); 1155956e45f6SSimon J. Gerraty } 1156956e45f6SSimon J. Gerraty 115706b9b3e0SSimon J. Gerraty /* 115806b9b3e0SSimon J. Gerraty * Add the directories from the colon-separated syspath to defSysIncPath. 115906b9b3e0SSimon J. Gerraty * After returning, the contents of syspath is unspecified. 116006b9b3e0SSimon J. Gerraty */ 1161956e45f6SSimon J. Gerraty static void 1162956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath) 1163956e45f6SSimon J. Gerraty { 1164956e45f6SSimon J. Gerraty static char defsyspath[] = _PATH_DEFSYSPATH; 1165d5e0a182SSimon J. Gerraty char *start, *p; 1166956e45f6SSimon J. Gerraty 1167956e45f6SSimon J. Gerraty /* 1168956e45f6SSimon J. Gerraty * If no user-supplied system path was given (through the -m option) 1169956e45f6SSimon J. Gerraty * add the directories from the DEFSYSPATH (more than one may be given 1170956e45f6SSimon J. Gerraty * as dir1:...:dirn) to the system include path. 1171956e45f6SSimon J. Gerraty */ 1172956e45f6SSimon J. Gerraty if (syspath == NULL || syspath[0] == '\0') 1173956e45f6SSimon J. Gerraty syspath = defsyspath; 1174956e45f6SSimon J. Gerraty else 1175956e45f6SSimon J. Gerraty syspath = bmake_strdup(syspath); 1176956e45f6SSimon J. Gerraty 1177d5e0a182SSimon J. Gerraty for (start = syspath; *start != '\0'; start = p) { 1178d5e0a182SSimon J. Gerraty for (p = start; *p != '\0' && *p != ':'; p++) 1179956e45f6SSimon J. Gerraty continue; 1180d5e0a182SSimon J. Gerraty if (*p == ':') 1181d5e0a182SSimon J. Gerraty *p++ = '\0'; 1182e2eeea75SSimon J. Gerraty 1183956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 1184e2eeea75SSimon J. Gerraty if (strncmp(start, ".../", 4) == 0) { 1185956e45f6SSimon J. Gerraty char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1186956e45f6SSimon J. Gerraty if (dir != NULL) { 1187dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, dir); 1188956e45f6SSimon J. Gerraty free(dir); 1189956e45f6SSimon J. Gerraty } 1190e2eeea75SSimon J. Gerraty } else { 1191dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, start); 1192956e45f6SSimon J. Gerraty } 1193956e45f6SSimon J. Gerraty } 1194956e45f6SSimon J. Gerraty 1195956e45f6SSimon J. Gerraty if (syspath != defsyspath) 1196956e45f6SSimon J. Gerraty free(syspath); 1197956e45f6SSimon J. Gerraty } 1198956e45f6SSimon J. Gerraty 1199956e45f6SSimon J. Gerraty static void 1200956e45f6SSimon J. Gerraty ReadBuiltinRules(void) 1201956e45f6SSimon J. Gerraty { 1202e2eeea75SSimon J. Gerraty StringListNode *ln; 1203dba7b0efSSimon J. Gerraty StringList sysMkFiles = LST_INIT; 1204e2eeea75SSimon J. Gerraty 1205dba7b0efSSimon J. Gerraty SearchPath_Expand( 1206dba7b0efSSimon J. Gerraty Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath, 1207dba7b0efSSimon J. Gerraty _PATH_DEFSYSMK, 1208dba7b0efSSimon J. Gerraty &sysMkFiles); 1209dba7b0efSSimon J. Gerraty if (Lst_IsEmpty(&sysMkFiles)) 1210956e45f6SSimon J. Gerraty Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1211e2eeea75SSimon J. Gerraty 1212dba7b0efSSimon J. Gerraty for (ln = sysMkFiles.first; ln != NULL; ln = ln->next) 12139f45a3c8SSimon J. Gerraty if (ReadMakefile(ln->datum)) 1214e2eeea75SSimon J. Gerraty break; 1215e2eeea75SSimon J. Gerraty 1216e2eeea75SSimon J. Gerraty if (ln == NULL) 1217e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", 1218dba7b0efSSimon J. Gerraty progname, (const char *)sysMkFiles.first->datum); 1219e2eeea75SSimon J. Gerraty 12209f45a3c8SSimon J. Gerraty Lst_DoneCall(&sysMkFiles, free); 1221956e45f6SSimon J. Gerraty } 1222956e45f6SSimon J. Gerraty 1223956e45f6SSimon J. Gerraty static void 1224956e45f6SSimon J. Gerraty InitMaxJobs(void) 1225956e45f6SSimon J. Gerraty { 1226956e45f6SSimon J. Gerraty char *value; 1227956e45f6SSimon J. Gerraty int n; 1228956e45f6SSimon J. Gerraty 1229956e45f6SSimon J. Gerraty if (forceJobs || opts.compatMake || 1230dba7b0efSSimon J. Gerraty !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) 1231956e45f6SSimon J. Gerraty return; 1232956e45f6SSimon J. Gerraty 12338c973ee2SSimon J. Gerraty value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES); 1234956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1235956e45f6SSimon J. Gerraty n = (int)strtol(value, NULL, 0); 1236956e45f6SSimon J. Gerraty if (n < 1) { 1237956e45f6SSimon J. Gerraty (void)fprintf(stderr, 1238956e45f6SSimon J. Gerraty "%s: illegal value for .MAKE.JOBS " 1239956e45f6SSimon J. Gerraty "-- must be positive integer!\n", 1240956e45f6SSimon J. Gerraty progname); 124106b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 1242956e45f6SSimon J. Gerraty } 1243956e45f6SSimon J. Gerraty 1244956e45f6SSimon J. Gerraty if (n != opts.maxJobs) { 1245dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-j"); 1246dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, value); 1247956e45f6SSimon J. Gerraty } 1248956e45f6SSimon J. Gerraty 1249956e45f6SSimon J. Gerraty opts.maxJobs = n; 1250956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1251b0c40a00SSimon J. Gerraty forceJobs = true; 1252956e45f6SSimon J. Gerraty free(value); 1253956e45f6SSimon J. Gerraty } 1254956e45f6SSimon J. Gerraty 1255956e45f6SSimon J. Gerraty /* 1256956e45f6SSimon J. Gerraty * For compatibility, look at the directories in the VPATH variable 1257956e45f6SSimon J. Gerraty * and add them to the search path, if the variable is defined. The 1258956e45f6SSimon J. Gerraty * variable's value is in the same format as the PATH environment 1259956e45f6SSimon J. Gerraty * variable, i.e. <directory>:<directory>:<directory>... 1260956e45f6SSimon J. Gerraty */ 1261956e45f6SSimon J. Gerraty static void 1262956e45f6SSimon J. Gerraty InitVpath(void) 1263956e45f6SSimon J. Gerraty { 1264956e45f6SSimon J. Gerraty char *vpath, savec, *path; 1265dba7b0efSSimon J. Gerraty if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) 1266956e45f6SSimon J. Gerraty return; 1267956e45f6SSimon J. Gerraty 12688c973ee2SSimon J. Gerraty vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES); 1269956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1270956e45f6SSimon J. Gerraty path = vpath; 1271956e45f6SSimon J. Gerraty do { 1272d5e0a182SSimon J. Gerraty char *p; 1273956e45f6SSimon J. Gerraty /* skip to end of directory */ 1274d5e0a182SSimon J. Gerraty for (p = path; *p != ':' && *p != '\0'; p++) 1275956e45f6SSimon J. Gerraty continue; 1276956e45f6SSimon J. Gerraty /* Save terminator character so know when to stop */ 1277d5e0a182SSimon J. Gerraty savec = *p; 1278d5e0a182SSimon J. Gerraty *p = '\0'; 1279956e45f6SSimon J. Gerraty /* Add directory to search path */ 1280dba7b0efSSimon J. Gerraty (void)SearchPath_Add(&dirSearchPath, path); 1281d5e0a182SSimon J. Gerraty *p = savec; 1282d5e0a182SSimon J. Gerraty path = p + 1; 1283956e45f6SSimon J. Gerraty } while (savec == ':'); 1284956e45f6SSimon J. Gerraty free(vpath); 1285956e45f6SSimon J. Gerraty } 1286956e45f6SSimon J. Gerraty 1287956e45f6SSimon J. Gerraty static void 12889f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles) 1289956e45f6SSimon J. Gerraty { 1290956e45f6SSimon J. Gerraty StringListNode *ln; 1291956e45f6SSimon J. Gerraty 1292e2eeea75SSimon J. Gerraty for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1293e2eeea75SSimon J. Gerraty const char *fname = ln->datum; 12949f45a3c8SSimon J. Gerraty if (!ReadMakefile(fname)) 1295e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", progname, fname); 1296956e45f6SSimon J. Gerraty } 1297956e45f6SSimon J. Gerraty } 1298956e45f6SSimon J. Gerraty 1299956e45f6SSimon J. Gerraty static void 1300e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void) 1301956e45f6SSimon J. Gerraty { 13029f45a3c8SSimon J. Gerraty StringList makefiles = LST_INIT; 1303e2eeea75SSimon J. Gerraty StringListNode *ln; 13048c973ee2SSimon J. Gerraty char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}", 13058c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 1306e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 1307956e45f6SSimon J. Gerraty 1308d5e0a182SSimon J. Gerraty AppendWords(&makefiles, prefs); 1309956e45f6SSimon J. Gerraty 13109f45a3c8SSimon J. Gerraty for (ln = makefiles.first; ln != NULL; ln = ln->next) 13119f45a3c8SSimon J. Gerraty if (ReadMakefile(ln->datum)) 1312e2eeea75SSimon J. Gerraty break; 1313956e45f6SSimon J. Gerraty 13149f45a3c8SSimon J. Gerraty Lst_Done(&makefiles); 1315e2eeea75SSimon J. Gerraty free(prefs); 1316956e45f6SSimon J. Gerraty } 1317956e45f6SSimon J. Gerraty 131806b9b3e0SSimon J. Gerraty /* 131906b9b3e0SSimon J. Gerraty * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1320e2eeea75SSimon J. Gerraty * Initialize a few modules. 132106b9b3e0SSimon J. Gerraty * Parse the arguments from MAKEFLAGS and the command line. 132206b9b3e0SSimon J. Gerraty */ 1323e2eeea75SSimon J. Gerraty static void 1324e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv) 13253955d011SMarcel Moolenaar { 1326956e45f6SSimon J. Gerraty struct stat sa; 1327956e45f6SSimon J. Gerraty const char *machine; 1328956e45f6SSimon J. Gerraty const char *machine_arch; 13293955d011SMarcel Moolenaar char *syspath = getenv("MAKESYSPATH"); 13303955d011SMarcel Moolenaar struct utsname utsname; 13313955d011SMarcel Moolenaar 13323955d011SMarcel Moolenaar /* default to writing debug to stderr */ 1333956e45f6SSimon J. Gerraty opts.debug_file = stderr; 13343955d011SMarcel Moolenaar 13359f45a3c8SSimon J. Gerraty Str_Intern_Init(); 1336e2eeea75SSimon J. Gerraty HashTable_Init(&cached_realpaths); 1337e2eeea75SSimon J. Gerraty 13383955d011SMarcel Moolenaar #ifdef SIGINFO 13393955d011SMarcel Moolenaar (void)bmake_signal(SIGINFO, siginfo); 13403955d011SMarcel Moolenaar #endif 1341956e45f6SSimon J. Gerraty 1342956e45f6SSimon J. Gerraty InitRandom(); 13433955d011SMarcel Moolenaar 134406b9b3e0SSimon J. Gerraty progname = str_basename(argv[0]); 1345956e45f6SSimon J. Gerraty 1346956e45f6SSimon J. Gerraty UnlimitFiles(); 13473955d011SMarcel Moolenaar 13481748de26SSimon J. Gerraty if (uname(&utsname) == -1) { 13491748de26SSimon J. Gerraty (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 13501748de26SSimon J. Gerraty strerror(errno)); 13511748de26SSimon J. Gerraty exit(2); 13521748de26SSimon J. Gerraty } 13531748de26SSimon J. Gerraty 1354e2eeea75SSimon J. Gerraty machine = InitVarMachine(&utsname); 1355e2eeea75SSimon J. Gerraty machine_arch = InitVarMachineArch(); 13563955d011SMarcel Moolenaar 13573955d011SMarcel Moolenaar myPid = getpid(); /* remember this for vFork() */ 13583955d011SMarcel Moolenaar 1359d5e0a182SSimon J. Gerraty /* Just in case MAKEOBJDIR wants us to do something tricky. */ 1360e2eeea75SSimon J. Gerraty Targ_Init(); 1361e2eeea75SSimon J. Gerraty Var_Init(); 13624fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.OS", utsname.sysname); 1363dba7b0efSSimon J. Gerraty Global_Set("MACHINE", machine); 1364dba7b0efSSimon J. Gerraty Global_Set("MACHINE_ARCH", machine_arch); 13653955d011SMarcel Moolenaar #ifdef MAKE_VERSION 1366dba7b0efSSimon J. Gerraty Global_Set("MAKE_VERSION", MAKE_VERSION); 13673955d011SMarcel Moolenaar #endif 1368d5e0a182SSimon J. Gerraty Global_Set_ReadOnly(".newline", "\n"); 13693955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST 13709f45a3c8SSimon J. Gerraty /* This is the traditional preference for makefiles. */ 13713955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 13723955d011SMarcel Moolenaar #endif 13738c973ee2SSimon J. Gerraty Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST); 13744fde40d9SSimon J. Gerraty Global_Set(".MAKE.DEPENDFILE", ".depend"); 137598875883SSimon J. Gerraty /* Tell makefiles like jobs.mk whether we support -jC */ 137698875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN 137798875883SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.JOBS.C", "yes"); 137898875883SSimon J. Gerraty #else 137998875883SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.JOBS.C", "no"); 138098875883SSimon J. Gerraty #endif 13813955d011SMarcel Moolenaar 1382956e45f6SSimon J. Gerraty CmdOpts_Init(); 1383b0c40a00SSimon J. Gerraty allPrecious = false; /* Remove targets when interrupted */ 1384b0c40a00SSimon J. Gerraty deleteOnError = false; /* Historical default behavior */ 1385b0c40a00SSimon J. Gerraty jobsRunning = false; 13863955d011SMarcel Moolenaar 1387956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1388b0c40a00SSimon J. Gerraty ignorePWD = false; 13893955d011SMarcel Moolenaar 13903955d011SMarcel Moolenaar /* 13913955d011SMarcel Moolenaar * Initialize the parsing, directory and variable modules to prepare 13923955d011SMarcel Moolenaar * for the reading of inclusion paths and variable settings on the 13933955d011SMarcel Moolenaar * command line 13943955d011SMarcel Moolenaar */ 13953955d011SMarcel Moolenaar 13963955d011SMarcel Moolenaar /* 13973955d011SMarcel Moolenaar * Initialize various variables. 13983955d011SMarcel Moolenaar * MAKE also gets this name, for compatibility 13993955d011SMarcel Moolenaar * .MAKEFLAGS gets set to the empty string just in case. 14003955d011SMarcel Moolenaar * MFLAGS also gets initialized empty, for compatibility. 14013955d011SMarcel Moolenaar */ 14023955d011SMarcel Moolenaar Parse_Init(); 1403956e45f6SSimon J. Gerraty InitVarMake(argv[0]); 1404dba7b0efSSimon J. Gerraty Global_Set(MAKEFLAGS, ""); 14058c973ee2SSimon J. Gerraty Global_Set(".MAKEOVERRIDES", ""); 1406dba7b0efSSimon J. Gerraty Global_Set("MFLAGS", ""); 1407dba7b0efSSimon J. Gerraty Global_Set(".ALLTARGETS", ""); 14084fde40d9SSimon J. Gerraty Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV); 14093955d011SMarcel Moolenaar 1410e2eeea75SSimon J. Gerraty /* Set some other useful variables. */ 14113955d011SMarcel Moolenaar { 14129f45a3c8SSimon J. Gerraty char buf[64], *ep = getenv(MAKE_LEVEL_ENV); 14133955d011SMarcel Moolenaar 1414e2eeea75SSimon J. Gerraty makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 141551ee2c1cSSimon J. Gerraty if (makelevel < 0) 141651ee2c1cSSimon J. Gerraty makelevel = 0; 14179f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%d", makelevel); 14188c973ee2SSimon J. Gerraty Global_Set(".MAKE.LEVEL", buf); 14199f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", myPid); 14204fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.PID", buf); 14219f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getppid()); 14224fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.PPID", buf); 14239f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getuid()); 14244fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.UID", buf); 14259f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getgid()); 14264fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.GID", buf); 14273955d011SMarcel Moolenaar } 142851ee2c1cSSimon J. Gerraty if (makelevel > 0) { 142951ee2c1cSSimon J. Gerraty char pn[1024]; 1430e2eeea75SSimon J. Gerraty snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 143151ee2c1cSSimon J. Gerraty progname = bmake_strdup(pn); 143251ee2c1cSSimon J. Gerraty } 14333955d011SMarcel Moolenaar 14341748de26SSimon J. Gerraty #ifdef USE_META 14351748de26SSimon J. Gerraty meta_init(); 14361748de26SSimon J. Gerraty #endif 14372c3632d1SSimon J. Gerraty Dir_Init(); 14381ce939a7SSimon J. Gerraty 14399f45a3c8SSimon J. Gerraty { 14409f45a3c8SSimon J. Gerraty char *makeflags = explode(getenv("MAKEFLAGS")); 14419f45a3c8SSimon J. Gerraty Main_ParseArgLine(makeflags); 14429f45a3c8SSimon J. Gerraty free(makeflags); 14439f45a3c8SSimon J. Gerraty } 14443955d011SMarcel Moolenaar 14453955d011SMarcel Moolenaar if (getcwd(curdir, MAXPATHLEN) == NULL) { 14463955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: getcwd: %s.\n", 14473955d011SMarcel Moolenaar progname, strerror(errno)); 14483955d011SMarcel Moolenaar exit(2); 14493955d011SMarcel Moolenaar } 14503955d011SMarcel Moolenaar 14513955d011SMarcel Moolenaar MainParseArgs(argc, argv); 14523955d011SMarcel Moolenaar 1453956e45f6SSimon J. Gerraty if (opts.enterFlag) 145451ee2c1cSSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, curdir); 145551ee2c1cSSimon J. Gerraty 14563955d011SMarcel Moolenaar if (stat(curdir, &sa) == -1) { 14573955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: %s: %s.\n", 14583955d011SMarcel Moolenaar progname, curdir, strerror(errno)); 14593955d011SMarcel Moolenaar exit(2); 14603955d011SMarcel Moolenaar } 14613955d011SMarcel Moolenaar 14623955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE 1463956e45f6SSimon J. Gerraty HandlePWD(&sa); 14643955d011SMarcel Moolenaar #endif 1465dba7b0efSSimon J. Gerraty Global_Set(".CURDIR", curdir); 14663955d011SMarcel Moolenaar 1467956e45f6SSimon J. Gerraty InitObjdir(machine, machine_arch); 14683955d011SMarcel Moolenaar 14693955d011SMarcel Moolenaar Arch_Init(); 14703955d011SMarcel Moolenaar Suff_Init(); 14713955d011SMarcel Moolenaar Trace_Init(tracefile); 14723955d011SMarcel Moolenaar 1473e2eeea75SSimon J. Gerraty defaultNode = NULL; 14743955d011SMarcel Moolenaar (void)time(&now); 14753955d011SMarcel Moolenaar 14763955d011SMarcel Moolenaar Trace_Log(MAKESTART, NULL); 14773955d011SMarcel Moolenaar 1478956e45f6SSimon J. Gerraty InitVarTargets(); 14793955d011SMarcel Moolenaar 1480956e45f6SSimon J. Gerraty InitDefSysIncPath(syspath); 1481e2eeea75SSimon J. Gerraty } 14823955d011SMarcel Moolenaar 148306b9b3e0SSimon J. Gerraty /* 148406b9b3e0SSimon J. Gerraty * Read the system makefile followed by either makefile, Makefile or the 148506b9b3e0SSimon J. Gerraty * files given by the -f option. Exit on parse errors. 148606b9b3e0SSimon J. Gerraty */ 1487e2eeea75SSimon J. Gerraty static void 1488e2eeea75SSimon J. Gerraty main_ReadFiles(void) 1489e2eeea75SSimon J. Gerraty { 1490e2eeea75SSimon J. Gerraty 14914fde40d9SSimon J. Gerraty if (Lst_IsEmpty(&sysIncPath->dirs)) 14924fde40d9SSimon J. Gerraty SearchPath_AddAll(sysIncPath, defSysIncPath); 14934fde40d9SSimon J. Gerraty 14944fde40d9SSimon J. Gerraty Dir_SetSYSPATH(); 1495956e45f6SSimon J. Gerraty if (!opts.noBuiltins) 1496956e45f6SSimon J. Gerraty ReadBuiltinRules(); 14973955d011SMarcel Moolenaar 14982f2a5ecdSSimon J. Gerraty posix_state = PS_MAYBE_NEXT_LINE; 149906b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&opts.makefiles)) 150006b9b3e0SSimon J. Gerraty ReadAllMakefiles(&opts.makefiles); 1501e2eeea75SSimon J. Gerraty else 1502e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(); 1503e2eeea75SSimon J. Gerraty } 1504e2eeea75SSimon J. Gerraty 1505e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */ 1506e2eeea75SSimon J. Gerraty static void 1507e2eeea75SSimon J. Gerraty main_PrepareMaking(void) 1508e2eeea75SSimon J. Gerraty { 15093955d011SMarcel Moolenaar /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1510e2eeea75SSimon J. Gerraty if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 15118c973ee2SSimon J. Gerraty makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}", 15128c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 1513956e45f6SSimon J. Gerraty if (makeDependfile[0] != '\0') { 1514956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1515b0c40a00SSimon J. Gerraty doing_depend = true; 15162c3632d1SSimon J. Gerraty (void)ReadMakefile(makeDependfile); 1517b0c40a00SSimon J. Gerraty doing_depend = false; 15183955d011SMarcel Moolenaar } 1519956e45f6SSimon J. Gerraty } 15203955d011SMarcel Moolenaar 15214c620fe5SSimon J. Gerraty if (enterFlagObj) 15224c620fe5SSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, objdir); 15234c620fe5SSimon J. Gerraty 152406b9b3e0SSimon J. Gerraty MakeMode(); 15253955d011SMarcel Moolenaar 1526956e45f6SSimon J. Gerraty { 1527dba7b0efSSimon J. Gerraty FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS); 1528dba7b0efSSimon J. Gerraty Global_Append("MFLAGS", makeflags.str); 152906b9b3e0SSimon J. Gerraty FStr_Done(&makeflags); 1530956e45f6SSimon J. Gerraty } 1531e48f47ddSSimon J. Gerraty 1532956e45f6SSimon J. Gerraty InitMaxJobs(); 1533e48f47ddSSimon J. Gerraty 1534e2eeea75SSimon J. Gerraty if (!opts.compatMake && !forceJobs) 1535b0c40a00SSimon J. Gerraty opts.compatMake = true; 1536e48f47ddSSimon J. Gerraty 1537956e45f6SSimon J. Gerraty if (!opts.compatMake) 15383955d011SMarcel Moolenaar Job_ServerStart(maxJobTokens, jp_0, jp_1); 1539956e45f6SSimon J. Gerraty DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1540956e45f6SSimon J. Gerraty jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 15413955d011SMarcel Moolenaar 1542e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_NONE) 1543b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(true); /* initial export */ 15443955d011SMarcel Moolenaar 1545956e45f6SSimon J. Gerraty InitVpath(); 15463955d011SMarcel Moolenaar 15473955d011SMarcel Moolenaar /* 15483955d011SMarcel Moolenaar * Now that all search paths have been read for suffixes et al, it's 15493955d011SMarcel Moolenaar * time to add the default search path to their lists... 15503955d011SMarcel Moolenaar */ 1551b0c40a00SSimon J. Gerraty Suff_ExtendPaths(); 15523955d011SMarcel Moolenaar 15533955d011SMarcel Moolenaar /* 15543955d011SMarcel Moolenaar * Propagate attributes through :: dependency lists. 15553955d011SMarcel Moolenaar */ 15563955d011SMarcel Moolenaar Targ_Propagate(); 15573955d011SMarcel Moolenaar 15583955d011SMarcel Moolenaar /* print the initial graph, if the user requested it */ 15593955d011SMarcel Moolenaar if (DEBUG(GRAPH1)) 15603955d011SMarcel Moolenaar Targ_PrintGraph(1); 15613955d011SMarcel Moolenaar } 15623955d011SMarcel Moolenaar 156306b9b3e0SSimon J. Gerraty /* 156406b9b3e0SSimon J. Gerraty * Make the targets. 1565e2eeea75SSimon J. Gerraty * If the -v or -V options are given, print variables instead. 156606b9b3e0SSimon J. Gerraty * Return whether any of the targets is out-of-date. 156706b9b3e0SSimon J. Gerraty */ 1568b0c40a00SSimon J. Gerraty static bool 1569e2eeea75SSimon J. Gerraty main_Run(void) 1570e2eeea75SSimon J. Gerraty { 1571e2eeea75SSimon J. Gerraty if (opts.printVars != PVM_NONE) { 1572e2eeea75SSimon J. Gerraty /* print the values of any variables requested by the user */ 1573e2eeea75SSimon J. Gerraty doPrintVars(); 1574b0c40a00SSimon J. Gerraty return false; 1575e2eeea75SSimon J. Gerraty } else { 1576e2eeea75SSimon J. Gerraty return runTargets(); 1577e2eeea75SSimon J. Gerraty } 1578e2eeea75SSimon J. Gerraty } 15793955d011SMarcel Moolenaar 1580e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */ 1581e2eeea75SSimon J. Gerraty static void 1582e2eeea75SSimon J. Gerraty main_CleanUp(void) 1583e2eeea75SSimon J. Gerraty { 1584e2eeea75SSimon J. Gerraty #ifdef CLEANUP 158506b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.variables, free); 15869f45a3c8SSimon J. Gerraty Lst_DoneCall(&opts.makefiles, free); 158706b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.create, free); 1588e2eeea75SSimon J. Gerraty #endif 1589e2eeea75SSimon J. Gerraty 1590e2eeea75SSimon J. Gerraty if (DEBUG(GRAPH2)) 1591e2eeea75SSimon J. Gerraty Targ_PrintGraph(2); 1592e2eeea75SSimon J. Gerraty 1593e2eeea75SSimon J. Gerraty Trace_Log(MAKEEND, NULL); 1594e2eeea75SSimon J. Gerraty 1595e2eeea75SSimon J. Gerraty if (enterFlagObj) 1596e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, objdir); 1597e2eeea75SSimon J. Gerraty if (opts.enterFlag) 1598e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, curdir); 1599e2eeea75SSimon J. Gerraty 1600e2eeea75SSimon J. Gerraty #ifdef USE_META 1601e2eeea75SSimon J. Gerraty meta_finish(); 1602e2eeea75SSimon J. Gerraty #endif 1603e2eeea75SSimon J. Gerraty Suff_End(); 1604e2eeea75SSimon J. Gerraty Targ_End(); 1605e2eeea75SSimon J. Gerraty Arch_End(); 1606e2eeea75SSimon J. Gerraty Var_End(); 1607e2eeea75SSimon J. Gerraty Parse_End(); 1608e2eeea75SSimon J. Gerraty Dir_End(); 1609e2eeea75SSimon J. Gerraty Job_End(); 1610e2eeea75SSimon J. Gerraty Trace_End(); 16119f45a3c8SSimon J. Gerraty Str_Intern_End(); 1612e2eeea75SSimon J. Gerraty } 1613e2eeea75SSimon J. Gerraty 1614e2eeea75SSimon J. Gerraty /* Determine the exit code. */ 1615e2eeea75SSimon J. Gerraty static int 1616b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate) 1617e2eeea75SSimon J. Gerraty { 161812904384SSimon J. Gerraty if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0)) 1619956e45f6SSimon J. Gerraty return 2; /* Not 1 so -q can distinguish error */ 16203955d011SMarcel Moolenaar return outOfDate ? 1 : 0; 16213955d011SMarcel Moolenaar } 16223955d011SMarcel Moolenaar 1623e2eeea75SSimon J. Gerraty int 1624e2eeea75SSimon J. Gerraty main(int argc, char **argv) 1625e2eeea75SSimon J. Gerraty { 1626b0c40a00SSimon J. Gerraty bool outOfDate; 1627e2eeea75SSimon J. Gerraty 1628e2eeea75SSimon J. Gerraty main_Init(argc, argv); 1629e2eeea75SSimon J. Gerraty main_ReadFiles(); 1630e2eeea75SSimon J. Gerraty main_PrepareMaking(); 1631e2eeea75SSimon J. Gerraty outOfDate = main_Run(); 1632e2eeea75SSimon J. Gerraty main_CleanUp(); 1633e2eeea75SSimon J. Gerraty return main_Exit(outOfDate); 1634e2eeea75SSimon J. Gerraty } 1635e2eeea75SSimon J. Gerraty 163606b9b3e0SSimon J. Gerraty /* 163706b9b3e0SSimon J. Gerraty * Open and parse the given makefile, with all its side effects. 16389f45a3c8SSimon J. Gerraty * Return false if the file could not be opened. 16393955d011SMarcel Moolenaar */ 16409f45a3c8SSimon J. Gerraty static bool 16412c3632d1SSimon J. Gerraty ReadMakefile(const char *fname) 16423955d011SMarcel Moolenaar { 16433955d011SMarcel Moolenaar int fd; 16442c3632d1SSimon J. Gerraty char *name, *path = NULL; 16453955d011SMarcel Moolenaar 1646e2eeea75SSimon J. Gerraty if (strcmp(fname, "-") == 0) { 16479f45a3c8SSimon J. Gerraty Parse_File("(stdin)", -1); 1648dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", ""); 16493955d011SMarcel Moolenaar } else { 16503955d011SMarcel Moolenaar /* if we've chdir'd, rebuild the path name */ 1651e2eeea75SSimon J. Gerraty if (strcmp(curdir, objdir) != 0 && *fname != '/') { 16522c3632d1SSimon J. Gerraty path = str_concat3(curdir, "/", fname); 16533955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 16543955d011SMarcel Moolenaar if (fd != -1) { 16553955d011SMarcel Moolenaar fname = path; 16563955d011SMarcel Moolenaar goto found; 16573955d011SMarcel Moolenaar } 16582c3632d1SSimon J. Gerraty free(path); 16593955d011SMarcel Moolenaar 16603955d011SMarcel Moolenaar /* If curdir failed, try objdir (ala .depend) */ 16612c3632d1SSimon J. Gerraty path = str_concat3(objdir, "/", fname); 16623955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 16633955d011SMarcel Moolenaar if (fd != -1) { 16643955d011SMarcel Moolenaar fname = path; 16653955d011SMarcel Moolenaar goto found; 16663955d011SMarcel Moolenaar } 16673955d011SMarcel Moolenaar } else { 16683955d011SMarcel Moolenaar fd = open(fname, O_RDONLY); 16693955d011SMarcel Moolenaar if (fd != -1) 16703955d011SMarcel Moolenaar goto found; 16713955d011SMarcel Moolenaar } 16723955d011SMarcel Moolenaar /* look in -I and system include directories. */ 16733955d011SMarcel Moolenaar name = Dir_FindFile(fname, parseIncPath); 1674e2eeea75SSimon J. Gerraty if (name == NULL) { 1675dba7b0efSSimon J. Gerraty SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs) 1676956e45f6SSimon J. Gerraty ? defSysIncPath : sysIncPath; 1677956e45f6SSimon J. Gerraty name = Dir_FindFile(fname, sysInc); 1678956e45f6SSimon J. Gerraty } 1679e2eeea75SSimon J. Gerraty if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 16803955d011SMarcel Moolenaar free(name); 16813955d011SMarcel Moolenaar free(path); 16829f45a3c8SSimon J. Gerraty return false; 16833955d011SMarcel Moolenaar } 16843955d011SMarcel Moolenaar fname = name; 16853955d011SMarcel Moolenaar /* 16863955d011SMarcel Moolenaar * set the MAKEFILE variable desired by System V fans -- the 16873955d011SMarcel Moolenaar * placement of the setting here means it gets set to the last 16883955d011SMarcel Moolenaar * makefile specified, as it is set by SysV make. 16893955d011SMarcel Moolenaar */ 16903955d011SMarcel Moolenaar found: 16913955d011SMarcel Moolenaar if (!doing_depend) 1692dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname); 16933955d011SMarcel Moolenaar Parse_File(fname, fd); 16943955d011SMarcel Moolenaar } 16953955d011SMarcel Moolenaar free(path); 16969f45a3c8SSimon J. Gerraty return true; 16973955d011SMarcel Moolenaar } 16983955d011SMarcel Moolenaar 1699dba7b0efSSimon J. Gerraty /* 17009f45a3c8SSimon J. Gerraty * Execute the command in cmd, and return its output (only stdout, not 17019f45a3c8SSimon J. Gerraty * stderr, possibly empty). In the output, replace newlines with spaces. 17023955d011SMarcel Moolenaar */ 17033955d011SMarcel Moolenaar char * 17049f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error) 17053955d011SMarcel Moolenaar { 17069f45a3c8SSimon J. Gerraty const char *args[4]; /* Arguments for invoking the shell */ 170706b9b3e0SSimon J. Gerraty int pipefds[2]; 17083955d011SMarcel Moolenaar int cpid; /* Child PID */ 17093955d011SMarcel Moolenaar int pid; /* PID from wait() */ 1710e2eeea75SSimon J. Gerraty int status; /* command exit status */ 17113955d011SMarcel Moolenaar Buffer buf; /* buffer to store the result */ 17122c3632d1SSimon J. Gerraty ssize_t bytes_read; 17139f45a3c8SSimon J. Gerraty char *output; 1714d5e0a182SSimon J. Gerraty char *p; 17159f45a3c8SSimon J. Gerraty int saved_errno; 1716d5e0a182SSimon J. Gerraty char cmd_file[MAXPATHLEN]; 1717d5e0a182SSimon J. Gerraty size_t cmd_len; 1718d5e0a182SSimon J. Gerraty int cmd_fd = -1; 17193955d011SMarcel Moolenaar 1720d5e0a182SSimon J. Gerraty if (shellPath == NULL) 17213955d011SMarcel Moolenaar Shell_Init(); 17229f45a3c8SSimon J. Gerraty 1723d5e0a182SSimon J. Gerraty cmd_len = strlen(cmd); 1724d5e0a182SSimon J. Gerraty if (cmd_len > 1000) { 1725d5e0a182SSimon J. Gerraty cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file)); 1726d5e0a182SSimon J. Gerraty if (cmd_fd >= 0) { 1727d5e0a182SSimon J. Gerraty ssize_t n; 1728d5e0a182SSimon J. Gerraty 1729d5e0a182SSimon J. Gerraty n = write(cmd_fd, cmd, cmd_len); 1730d5e0a182SSimon J. Gerraty close(cmd_fd); 1731d5e0a182SSimon J. Gerraty if (n < (ssize_t)cmd_len) { 1732d5e0a182SSimon J. Gerraty unlink(cmd_file); 1733d5e0a182SSimon J. Gerraty cmd_fd = -1; 1734d5e0a182SSimon J. Gerraty } 1735d5e0a182SSimon J. Gerraty } 1736d5e0a182SSimon J. Gerraty } 1737d5e0a182SSimon J. Gerraty 17383955d011SMarcel Moolenaar args[0] = shellName; 1739d5e0a182SSimon J. Gerraty if (cmd_fd >= 0) { 1740d5e0a182SSimon J. Gerraty args[1] = cmd_file; 1741d5e0a182SSimon J. Gerraty args[2] = NULL; 1742d5e0a182SSimon J. Gerraty } else { 1743d5e0a182SSimon J. Gerraty cmd_file[0] = '\0'; 17443955d011SMarcel Moolenaar args[1] = "-c"; 17453955d011SMarcel Moolenaar args[2] = cmd; 17463955d011SMarcel Moolenaar args[3] = NULL; 1747d5e0a182SSimon J. Gerraty } 17489f45a3c8SSimon J. Gerraty DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd); 17493955d011SMarcel Moolenaar 175006b9b3e0SSimon J. Gerraty if (pipe(pipefds) == -1) { 17519f45a3c8SSimon J. Gerraty *error = str_concat3( 17529f45a3c8SSimon J. Gerraty "Couldn't create pipe for \"", cmd, "\""); 17539f45a3c8SSimon J. Gerraty return bmake_strdup(""); 17543955d011SMarcel Moolenaar } 17553955d011SMarcel Moolenaar 1756*c59c3bf3SSimon J. Gerraty Var_ReexportVars(SCOPE_GLOBAL); 175706b9b3e0SSimon J. Gerraty 1758dba7b0efSSimon J. Gerraty switch (cpid = vfork()) { 17593955d011SMarcel Moolenaar case 0: 17609f45a3c8SSimon J. Gerraty (void)close(pipefds[0]); 17619f45a3c8SSimon J. Gerraty (void)dup2(pipefds[1], STDOUT_FILENO); 176206b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); 17633955d011SMarcel Moolenaar 17643955d011SMarcel Moolenaar (void)execv(shellPath, UNCONST(args)); 17653955d011SMarcel Moolenaar _exit(1); 17663955d011SMarcel Moolenaar /* NOTREACHED */ 17673955d011SMarcel Moolenaar 17683955d011SMarcel Moolenaar case -1: 17699f45a3c8SSimon J. Gerraty *error = str_concat3("Couldn't exec \"", cmd, "\""); 17709f45a3c8SSimon J. Gerraty return bmake_strdup(""); 17719f45a3c8SSimon J. Gerraty } 17723955d011SMarcel Moolenaar 177306b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); /* No need for the writing half */ 17743955d011SMarcel Moolenaar 17759f45a3c8SSimon J. Gerraty saved_errno = 0; 1776e2eeea75SSimon J. Gerraty Buf_Init(&buf); 17773955d011SMarcel Moolenaar 17783955d011SMarcel Moolenaar do { 17793955d011SMarcel Moolenaar char result[BUFSIZ]; 178006b9b3e0SSimon J. Gerraty bytes_read = read(pipefds[0], result, sizeof result); 17812c3632d1SSimon J. Gerraty if (bytes_read > 0) 17822c3632d1SSimon J. Gerraty Buf_AddBytes(&buf, result, (size_t)bytes_read); 17839f45a3c8SSimon J. Gerraty } while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); 17842c3632d1SSimon J. Gerraty if (bytes_read == -1) 17859f45a3c8SSimon J. Gerraty saved_errno = errno; 17863955d011SMarcel Moolenaar 178706b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close the input side of the pipe. */ 17883955d011SMarcel Moolenaar 1789e2eeea75SSimon J. Gerraty while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 1790b0c40a00SSimon J. Gerraty JobReapChild(pid, status, false); 1791e2eeea75SSimon J. Gerraty 17929f45a3c8SSimon J. Gerraty if (Buf_EndsWith(&buf, '\n')) 17939f45a3c8SSimon J. Gerraty buf.data[buf.len - 1] = '\0'; 17943955d011SMarcel Moolenaar 17959f45a3c8SSimon J. Gerraty output = Buf_DoneData(&buf); 1796d5e0a182SSimon J. Gerraty for (p = output; *p != '\0'; p++) 1797d5e0a182SSimon J. Gerraty if (*p == '\n') 1798d5e0a182SSimon J. Gerraty *p = ' '; 17999f45a3c8SSimon J. Gerraty 18009f45a3c8SSimon J. Gerraty if (WIFSIGNALED(status)) 18019f45a3c8SSimon J. Gerraty *error = str_concat3("\"", cmd, "\" exited on a signal"); 18029f45a3c8SSimon J. Gerraty else if (WEXITSTATUS(status) != 0) 18039f45a3c8SSimon J. Gerraty *error = str_concat3( 18049f45a3c8SSimon J. Gerraty "\"", cmd, "\" returned non-zero status"); 18059f45a3c8SSimon J. Gerraty else if (saved_errno != 0) 18069f45a3c8SSimon J. Gerraty *error = str_concat3( 18079f45a3c8SSimon J. Gerraty "Couldn't read shell's output for \"", cmd, "\""); 18089f45a3c8SSimon J. Gerraty else 18099f45a3c8SSimon J. Gerraty *error = NULL; 1810d5e0a182SSimon J. Gerraty if (cmd_file[0] != '\0') 1811d5e0a182SSimon J. Gerraty unlink(cmd_file); 18129f45a3c8SSimon J. Gerraty return output; 18133955d011SMarcel Moolenaar } 18143955d011SMarcel Moolenaar 181506b9b3e0SSimon J. Gerraty /* 181606b9b3e0SSimon J. Gerraty * Print a printf-style error message. 18173955d011SMarcel Moolenaar * 18189f45a3c8SSimon J. Gerraty * In default mode, this error message has no consequences, for compatibility 18199f45a3c8SSimon J. Gerraty * reasons, in particular it does not affect the exit status. Only in lint 18209f45a3c8SSimon J. Gerraty * mode (-dL) it does. 182106b9b3e0SSimon J. Gerraty */ 18223955d011SMarcel Moolenaar void 18233955d011SMarcel Moolenaar Error(const char *fmt, ...) 18243955d011SMarcel Moolenaar { 18253955d011SMarcel Moolenaar va_list ap; 18269f45a3c8SSimon J. Gerraty FILE *f; 18273955d011SMarcel Moolenaar 18289f45a3c8SSimon J. Gerraty f = opts.debug_file; 18299f45a3c8SSimon J. Gerraty if (f == stdout) 18309f45a3c8SSimon J. Gerraty f = stderr; 18313955d011SMarcel Moolenaar (void)fflush(stdout); 18329f45a3c8SSimon J. Gerraty 18333955d011SMarcel Moolenaar for (;;) { 18349f45a3c8SSimon J. Gerraty fprintf(f, "%s: ", progname); 18353955d011SMarcel Moolenaar va_start(ap, fmt); 18369f45a3c8SSimon J. Gerraty (void)vfprintf(f, fmt, ap); 18373955d011SMarcel Moolenaar va_end(ap); 18389f45a3c8SSimon J. Gerraty (void)fprintf(f, "\n"); 18399f45a3c8SSimon J. Gerraty (void)fflush(f); 18409f45a3c8SSimon J. Gerraty if (f == stderr) 18413955d011SMarcel Moolenaar break; 18429f45a3c8SSimon J. Gerraty f = stderr; 18433955d011SMarcel Moolenaar } 184406b9b3e0SSimon J. Gerraty main_errors++; 18453955d011SMarcel Moolenaar } 18463955d011SMarcel Moolenaar 184706b9b3e0SSimon J. Gerraty /* 184806b9b3e0SSimon J. Gerraty * Wait for any running jobs to finish, then produce an error message, 1849e2eeea75SSimon J. Gerraty * finally exit immediately. 18503955d011SMarcel Moolenaar * 1851e2eeea75SSimon J. Gerraty * Exiting immediately differs from Parse_Error, which exits only after the 185206b9b3e0SSimon J. Gerraty * current top-level makefile has been parsed completely. 185306b9b3e0SSimon J. Gerraty */ 18543955d011SMarcel Moolenaar void 18553955d011SMarcel Moolenaar Fatal(const char *fmt, ...) 18563955d011SMarcel Moolenaar { 18573955d011SMarcel Moolenaar va_list ap; 18583955d011SMarcel Moolenaar 18593955d011SMarcel Moolenaar if (jobsRunning) 18603955d011SMarcel Moolenaar Job_Wait(); 18613955d011SMarcel Moolenaar 18623955d011SMarcel Moolenaar (void)fflush(stdout); 1863d5e0a182SSimon J. Gerraty fprintf(stderr, "%s: ", progname); 1864e2eeea75SSimon J. Gerraty va_start(ap, fmt); 18653955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 18663955d011SMarcel Moolenaar va_end(ap); 18673955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 18683955d011SMarcel Moolenaar (void)fflush(stderr); 18699f45a3c8SSimon J. Gerraty PrintStackTrace(true); 18703955d011SMarcel Moolenaar 18719f45a3c8SSimon J. Gerraty PrintOnError(NULL, "\n"); 18723955d011SMarcel Moolenaar 18733955d011SMarcel Moolenaar if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 18743955d011SMarcel Moolenaar Targ_PrintGraph(2); 1875e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 18763955d011SMarcel Moolenaar exit(2); /* Not 1 so -q can distinguish error */ 18773955d011SMarcel Moolenaar } 18783955d011SMarcel Moolenaar 187906b9b3e0SSimon J. Gerraty /* 188006b9b3e0SSimon J. Gerraty * Major exception once jobs are being created. 188106b9b3e0SSimon J. Gerraty * Kills all jobs, prints a message and exits. 188206b9b3e0SSimon J. Gerraty */ 18833955d011SMarcel Moolenaar void 18843955d011SMarcel Moolenaar Punt(const char *fmt, ...) 18853955d011SMarcel Moolenaar { 18863955d011SMarcel Moolenaar va_list ap; 18873955d011SMarcel Moolenaar 18883955d011SMarcel Moolenaar (void)fflush(stdout); 18893955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: ", progname); 18909f45a3c8SSimon J. Gerraty va_start(ap, fmt); 18913955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 18923955d011SMarcel Moolenaar va_end(ap); 18933955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 18943955d011SMarcel Moolenaar (void)fflush(stderr); 18953955d011SMarcel Moolenaar 18969f45a3c8SSimon J. Gerraty PrintOnError(NULL, "\n"); 18973955d011SMarcel Moolenaar 18983955d011SMarcel Moolenaar DieHorribly(); 18993955d011SMarcel Moolenaar } 19003955d011SMarcel Moolenaar 1901956e45f6SSimon J. Gerraty /* Exit without giving a message. */ 19023955d011SMarcel Moolenaar void 19033955d011SMarcel Moolenaar DieHorribly(void) 19043955d011SMarcel Moolenaar { 19053955d011SMarcel Moolenaar if (jobsRunning) 19063955d011SMarcel Moolenaar Job_AbortAll(); 19073955d011SMarcel Moolenaar if (DEBUG(GRAPH2)) 19083955d011SMarcel Moolenaar Targ_PrintGraph(2); 1909e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 191006b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 19113955d011SMarcel Moolenaar } 19123955d011SMarcel Moolenaar 191306b9b3e0SSimon J. Gerraty /* 191406b9b3e0SSimon J. Gerraty * Called when aborting due to errors in child shell to signal abnormal exit. 1915956e45f6SSimon J. Gerraty * The program exits. 191606b9b3e0SSimon J. Gerraty * Errors is the number of errors encountered in Make_Make. 191706b9b3e0SSimon J. Gerraty */ 19183955d011SMarcel Moolenaar void 1919956e45f6SSimon J. Gerraty Finish(int errs) 19203955d011SMarcel Moolenaar { 1921e2eeea75SSimon J. Gerraty if (shouldDieQuietly(NULL, -1)) 19223841c287SSimon J. Gerraty exit(2); 1923956e45f6SSimon J. Gerraty Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 19243955d011SMarcel Moolenaar } 19253955d011SMarcel Moolenaar 19264fde40d9SSimon J. Gerraty int 19279f45a3c8SSimon J. Gerraty unlink_file(const char *file) 19283955d011SMarcel Moolenaar { 19293955d011SMarcel Moolenaar struct stat st; 19303955d011SMarcel Moolenaar 19313955d011SMarcel Moolenaar if (lstat(file, &st) == -1) 19324fde40d9SSimon J. Gerraty return -1; 19333955d011SMarcel Moolenaar 19343955d011SMarcel Moolenaar if (S_ISDIR(st.st_mode)) { 19354fde40d9SSimon J. Gerraty /* 19364fde40d9SSimon J. Gerraty * POSIX says for unlink: "The path argument shall not name 19374fde40d9SSimon J. Gerraty * a directory unless [...]". 19384fde40d9SSimon J. Gerraty */ 19393955d011SMarcel Moolenaar errno = EISDIR; 19404fde40d9SSimon J. Gerraty return -1; 19413955d011SMarcel Moolenaar } 19424fde40d9SSimon J. Gerraty return unlink(file); 19433955d011SMarcel Moolenaar } 19443955d011SMarcel Moolenaar 1945956e45f6SSimon J. Gerraty static void 1946956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n) 1947956e45f6SSimon J. Gerraty { 1948956e45f6SSimon J. Gerraty const char *mem = data; 1949956e45f6SSimon J. Gerraty 1950956e45f6SSimon J. Gerraty while (n > 0) { 1951956e45f6SSimon J. Gerraty ssize_t written = write(fd, mem, n); 19529f45a3c8SSimon J. Gerraty /* XXX: Should this EAGAIN be EINTR? */ 1953956e45f6SSimon J. Gerraty if (written == -1 && errno == EAGAIN) 1954956e45f6SSimon J. Gerraty continue; 1955956e45f6SSimon J. Gerraty if (written == -1) 1956956e45f6SSimon J. Gerraty break; 1957956e45f6SSimon J. Gerraty mem += written; 1958956e45f6SSimon J. Gerraty n -= (size_t)written; 1959956e45f6SSimon J. Gerraty } 1960956e45f6SSimon J. Gerraty } 1961956e45f6SSimon J. Gerraty 19629f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */ 1963956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD 1964956e45f6SSimon J. Gerraty execDie(const char *af, const char *av) 19653955d011SMarcel Moolenaar { 1966956e45f6SSimon J. Gerraty Buffer buf; 19673955d011SMarcel Moolenaar 1968e2eeea75SSimon J. Gerraty Buf_Init(&buf); 1969956e45f6SSimon J. Gerraty Buf_AddStr(&buf, progname); 1970956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ": "); 1971956e45f6SSimon J. Gerraty Buf_AddStr(&buf, af); 1972956e45f6SSimon J. Gerraty Buf_AddStr(&buf, "("); 1973956e45f6SSimon J. Gerraty Buf_AddStr(&buf, av); 1974956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ") failed ("); 1975956e45f6SSimon J. Gerraty Buf_AddStr(&buf, strerror(errno)); 1976956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ")\n"); 19773955d011SMarcel Moolenaar 1978dba7b0efSSimon J. Gerraty write_all(STDERR_FILENO, buf.data, buf.len); 1979956e45f6SSimon J. Gerraty 1980dba7b0efSSimon J. Gerraty Buf_Done(&buf); 1981956e45f6SSimon J. Gerraty _exit(1); 19823955d011SMarcel Moolenaar } 19833955d011SMarcel Moolenaar 1984e1cee40dSSimon J. Gerraty static void 1985e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void) 1986e1cee40dSSimon J. Gerraty { 1987d5e0a182SSimon J. Gerraty HashEntry *he, *next; 1988956e45f6SSimon J. Gerraty HashIter hi; 1989b778b302SSimon J. Gerraty 1990e2eeea75SSimon J. Gerraty HashIter_Init(&hi, &cached_realpaths); 1991956e45f6SSimon J. Gerraty he = HashIter_Next(&hi); 1992956e45f6SSimon J. Gerraty while (he != NULL) { 1993d5e0a182SSimon J. Gerraty next = HashIter_Next(&hi); 1994956e45f6SSimon J. Gerraty if (he->key[0] != '/') { 1995e2eeea75SSimon J. Gerraty DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 1996e2eeea75SSimon J. Gerraty HashTable_DeleteEntry(&cached_realpaths, he); 19979f45a3c8SSimon J. Gerraty /* 19989f45a3c8SSimon J. Gerraty * XXX: What about the allocated he->value? Either 19999f45a3c8SSimon J. Gerraty * free them or document why they cannot be freed. 20009f45a3c8SSimon J. Gerraty */ 2001b46b9039SSimon J. Gerraty } 2002d5e0a182SSimon J. Gerraty he = next; 2003b46b9039SSimon J. Gerraty } 2004b46b9039SSimon J. Gerraty } 2005e1cee40dSSimon J. Gerraty 20069f45a3c8SSimon J. Gerraty const char * 2007e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved) 2008e1cee40dSSimon J. Gerraty { 20092c3632d1SSimon J. Gerraty const char *rp; 2010e1cee40dSSimon J. Gerraty 2011e2eeea75SSimon J. Gerraty if (pathname == NULL || pathname[0] == '\0') 2012e1cee40dSSimon J. Gerraty return NULL; 2013e1cee40dSSimon J. Gerraty 2014e2eeea75SSimon J. Gerraty rp = HashTable_FindValue(&cached_realpaths, pathname); 2015e2eeea75SSimon J. Gerraty if (rp != NULL) { 2016b778b302SSimon J. Gerraty /* a hit */ 2017e2eeea75SSimon J. Gerraty strncpy(resolved, rp, MAXPATHLEN); 2018e2eeea75SSimon J. Gerraty resolved[MAXPATHLEN - 1] = '\0'; 2019e2eeea75SSimon J. Gerraty return resolved; 2020e2eeea75SSimon J. Gerraty } 20213841c287SSimon J. Gerraty 2022e2eeea75SSimon J. Gerraty rp = realpath(pathname, resolved); 2023e2eeea75SSimon J. Gerraty if (rp != NULL) { 2024e2eeea75SSimon J. Gerraty HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2025e2eeea75SSimon J. Gerraty DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2026e2eeea75SSimon J. Gerraty return resolved; 2027e2eeea75SSimon J. Gerraty } 2028e2eeea75SSimon J. Gerraty 2029e2eeea75SSimon J. Gerraty /* should we negative-cache? */ 2030e2eeea75SSimon J. Gerraty return NULL; 2031b778b302SSimon J. Gerraty } 2032b778b302SSimon J. Gerraty 20333841c287SSimon J. Gerraty /* 20343841c287SSimon J. Gerraty * Return true if we should die without noise. 2035e2eeea75SSimon J. Gerraty * For example our failing child was a sub-make or failure happened elsewhere. 20363841c287SSimon J. Gerraty */ 2037b0c40a00SSimon J. Gerraty bool 2038e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf) 20393841c287SSimon J. Gerraty { 20403841c287SSimon J. Gerraty static int quietly = -1; 20413841c287SSimon J. Gerraty 20423841c287SSimon J. Gerraty if (quietly < 0) { 2043b0c40a00SSimon J. Gerraty if (DEBUG(JOB) || 2044b0c40a00SSimon J. Gerraty !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true)) 20453841c287SSimon J. Gerraty quietly = 0; 20463841c287SSimon J. Gerraty else if (bf >= 0) 20473841c287SSimon J. Gerraty quietly = bf; 20483841c287SSimon J. Gerraty else 204906b9b3e0SSimon J. Gerraty quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0; 20503841c287SSimon J. Gerraty } 2051dba7b0efSSimon J. Gerraty return quietly != 0; 20523841c287SSimon J. Gerraty } 20533841c287SSimon J. Gerraty 2054956e45f6SSimon J. Gerraty static void 2055956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn) 2056956e45f6SSimon J. Gerraty { 2057956e45f6SSimon J. Gerraty StringListNode *ln; 2058*c59c3bf3SSimon J. Gerraty char sts[16]; 2059956e45f6SSimon J. Gerraty 2060956e45f6SSimon J. Gerraty /* 2061956e45f6SSimon J. Gerraty * We can print this even if there is no .ERROR target. 2062956e45f6SSimon J. Gerraty */ 2063*c59c3bf3SSimon J. Gerraty snprintf(sts, sizeof(sts), "%d", gn->exit_status); 2064*c59c3bf3SSimon J. Gerraty Global_Set(".ERROR_EXIT", sts); 2065dba7b0efSSimon J. Gerraty Global_Set(".ERROR_TARGET", gn->name); 2066dba7b0efSSimon J. Gerraty Global_Delete(".ERROR_CMD"); 2067956e45f6SSimon J. Gerraty 206806b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) { 2069956e45f6SSimon J. Gerraty const char *cmd = ln->datum; 2070956e45f6SSimon J. Gerraty 2071956e45f6SSimon J. Gerraty if (cmd == NULL) 2072956e45f6SSimon J. Gerraty break; 2073dba7b0efSSimon J. Gerraty Global_Append(".ERROR_CMD", cmd); 2074956e45f6SSimon J. Gerraty } 2075956e45f6SSimon J. Gerraty } 2076956e45f6SSimon J. Gerraty 207706b9b3e0SSimon J. Gerraty /* 207806b9b3e0SSimon J. Gerraty * Print some helpful information in case of an error. 207906b9b3e0SSimon J. Gerraty * The caller should exit soon after calling this function. 208006b9b3e0SSimon J. Gerraty */ 20813955d011SMarcel Moolenaar void 2082e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg) 20833955d011SMarcel Moolenaar { 2084e2eeea75SSimon J. Gerraty static GNode *errorNode = NULL; 20853955d011SMarcel Moolenaar 20862c3632d1SSimon J. Gerraty if (DEBUG(HASH)) { 20872c3632d1SSimon J. Gerraty Targ_Stats(); 20882c3632d1SSimon J. Gerraty Var_Stats(); 20892c3632d1SSimon J. Gerraty } 20902c3632d1SSimon J. Gerraty 209106b9b3e0SSimon J. Gerraty if (errorNode != NULL) 209206b9b3e0SSimon J. Gerraty return; /* we've been here! */ 20933841c287SSimon J. Gerraty 20949f45a3c8SSimon J. Gerraty printf("%s%s: stopped in %s\n", msg, progname, curdir); 20953955d011SMarcel Moolenaar 209606b9b3e0SSimon J. Gerraty /* we generally want to keep quiet if a sub-make died */ 209706b9b3e0SSimon J. Gerraty if (shouldDieQuietly(gn, -1)) 209806b9b3e0SSimon J. Gerraty return; 2099e2eeea75SSimon J. Gerraty 2100e2eeea75SSimon J. Gerraty if (gn != NULL) 2101956e45f6SSimon J. Gerraty SetErrorVars(gn); 2102e2eeea75SSimon J. Gerraty 2103e2eeea75SSimon J. Gerraty { 21048c973ee2SSimon J. Gerraty char *errorVarsValues = Var_Subst( 21058c973ee2SSimon J. Gerraty "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 21068c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 2107956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2108e2eeea75SSimon J. Gerraty printf("%s", errorVarsValues); 2109e2eeea75SSimon J. Gerraty free(errorVarsValues); 2110e2eeea75SSimon J. Gerraty } 2111e2eeea75SSimon J. Gerraty 2112ac3446e9SSimon J. Gerraty fflush(stdout); 2113ac3446e9SSimon J. Gerraty 21143955d011SMarcel Moolenaar /* 21153955d011SMarcel Moolenaar * Finally, see if there is a .ERROR target, and run it if so. 21163955d011SMarcel Moolenaar */ 2117e2eeea75SSimon J. Gerraty errorNode = Targ_FindNode(".ERROR"); 2118e2eeea75SSimon J. Gerraty if (errorNode != NULL) { 2119e2eeea75SSimon J. Gerraty errorNode->type |= OP_SPECIAL; 2120e2eeea75SSimon J. Gerraty Compat_Make(errorNode, errorNode); 21213955d011SMarcel Moolenaar } 21223955d011SMarcel Moolenaar } 21233955d011SMarcel Moolenaar 21243955d011SMarcel Moolenaar void 2125b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first) 21263955d011SMarcel Moolenaar { 2127b0c40a00SSimon J. Gerraty static bool once = true; 21289f45a3c8SSimon J. Gerraty char *flags; 21293955d011SMarcel Moolenaar 21303955d011SMarcel Moolenaar if (once != first) 21313955d011SMarcel Moolenaar return; 2132b0c40a00SSimon J. Gerraty once = false; 21333955d011SMarcel Moolenaar 21348c973ee2SSimon J. Gerraty flags = Var_Subst( 21359f45a3c8SSimon J. Gerraty "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 21368c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 2137956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2138*c59c3bf3SSimon J. Gerraty if (flags[0] != '\0') 21399f45a3c8SSimon J. Gerraty setenv("MAKEFLAGS", flags, 1); 21403955d011SMarcel Moolenaar } 21413955d011SMarcel Moolenaar 21423955d011SMarcel Moolenaar char * 21433955d011SMarcel Moolenaar getTmpdir(void) 21443955d011SMarcel Moolenaar { 21453955d011SMarcel Moolenaar static char *tmpdir = NULL; 21463955d011SMarcel Moolenaar struct stat st; 21473955d011SMarcel Moolenaar 2148e2eeea75SSimon J. Gerraty if (tmpdir != NULL) 2149e2eeea75SSimon J. Gerraty return tmpdir; 2150e2eeea75SSimon J. Gerraty 21519f45a3c8SSimon J. Gerraty /* Honor $TMPDIR if it is valid, strip a trailing '/'. */ 21528c973ee2SSimon J. Gerraty tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/", 21538c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 2154956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2155e2eeea75SSimon J. Gerraty 21563955d011SMarcel Moolenaar if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 21573955d011SMarcel Moolenaar free(tmpdir); 21583955d011SMarcel Moolenaar tmpdir = bmake_strdup(_PATH_TMP); 21593955d011SMarcel Moolenaar } 21603955d011SMarcel Moolenaar return tmpdir; 21613955d011SMarcel Moolenaar } 21623955d011SMarcel Moolenaar 21633955d011SMarcel Moolenaar /* 21643955d011SMarcel Moolenaar * Create and open a temp file using "pattern". 2165d5e0a182SSimon J. Gerraty * If tfile is provided, set it to a copy of the filename created. 21663955d011SMarcel Moolenaar * Otherwise unlink the file once open. 21673955d011SMarcel Moolenaar */ 21683955d011SMarcel Moolenaar int 2169dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz) 21703955d011SMarcel Moolenaar { 21713955d011SMarcel Moolenaar static char *tmpdir = NULL; 2172dba7b0efSSimon J. Gerraty char tbuf[MAXPATHLEN]; 21733955d011SMarcel Moolenaar int fd; 21743955d011SMarcel Moolenaar 2175e2eeea75SSimon J. Gerraty if (pattern == NULL) 21763955d011SMarcel Moolenaar pattern = TMPPAT; 2177956e45f6SSimon J. Gerraty if (tmpdir == NULL) 21783955d011SMarcel Moolenaar tmpdir = getTmpdir(); 2179dba7b0efSSimon J. Gerraty if (tfile == NULL) { 2180dba7b0efSSimon J. Gerraty tfile = tbuf; 2181dba7b0efSSimon J. Gerraty tfile_sz = sizeof tbuf; 2182dba7b0efSSimon J. Gerraty } 21839f45a3c8SSimon J. Gerraty 21849f45a3c8SSimon J. Gerraty if (pattern[0] == '/') 2185dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s", pattern); 21869f45a3c8SSimon J. Gerraty else 2187dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern); 21889f45a3c8SSimon J. Gerraty 21893955d011SMarcel Moolenaar if ((fd = mkstemp(tfile)) < 0) 2190e2eeea75SSimon J. Gerraty Punt("Could not create temporary file %s: %s", tfile, 2191e2eeea75SSimon J. Gerraty strerror(errno)); 21929f45a3c8SSimon J. Gerraty if (tfile == tbuf) 219306b9b3e0SSimon J. Gerraty unlink(tfile); /* we just want the descriptor */ 21949f45a3c8SSimon J. Gerraty 21953955d011SMarcel Moolenaar return fd; 21963955d011SMarcel Moolenaar } 21973955d011SMarcel Moolenaar 2198be19d90bSSimon J. Gerraty /* 2199e2eeea75SSimon J. Gerraty * Convert a string representation of a boolean into a boolean value. 2200b0c40a00SSimon J. Gerraty * Anything that looks like "No", "False", "Off", "0" etc. is false, 2201b0c40a00SSimon J. Gerraty * the empty string is the fallback, everything else is true. 2202be19d90bSSimon J. Gerraty */ 2203b0c40a00SSimon J. Gerraty bool 2204b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback) 2205be19d90bSSimon J. Gerraty { 2206e2eeea75SSimon J. Gerraty char ch = ch_tolower(s[0]); 2207e2eeea75SSimon J. Gerraty if (ch == '\0') 2208e2eeea75SSimon J. Gerraty return fallback; 2209e2eeea75SSimon J. Gerraty if (ch == '0' || ch == 'f' || ch == 'n') 2210b0c40a00SSimon J. Gerraty return false; 2211e2eeea75SSimon J. Gerraty if (ch == 'o') 2212e2eeea75SSimon J. Gerraty return ch_tolower(s[1]) != 'f'; 2213b0c40a00SSimon J. Gerraty return true; 2214be19d90bSSimon J. Gerraty } 2215