1*d5e0a182SSimon J. Gerraty /* $NetBSD: main.c,v 1.609 2024/01/07 01:33:57 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*d5e0a182SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.609 2024/01/07 01:33:57 sjg Exp $"); 115*d5e0a182SSimon 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 */ 128*d5e0a182SSimon 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) { 229*d5e0a182SSimon 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); 409*d5e0a182SSimon 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 414*d5e0a182SSimon J. Gerraty if (*p == 'C') 41598875883SSimon J. Gerraty d = (opts.maxJobs > 0) ? opts.maxJobs : 1; 416*d5e0a182SSimon J. Gerraty else if (*p == '.') { 41798875883SSimon J. Gerraty d = strtod(arg, &end); 418*d5e0a182SSimon J. Gerraty p = end; 41998875883SSimon J. Gerraty } else 420*d5e0a182SSimon J. Gerraty d = 0.0; 421*d5e0a182SSimon 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 { 445*d5e0a182SSimon 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': 481*d5e0a182SSimon 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; 692*d5e0a182SSimon J. Gerraty const char *p; 6933955d011SMarcel Moolenaar 6943955d011SMarcel Moolenaar if (line == NULL) 6953955d011SMarcel Moolenaar return; 696*d5e0a182SSimon J. Gerraty for (p = line; *p == ' '; p++) 6973955d011SMarcel Moolenaar continue; 698*d5e0a182SSimon J. Gerraty if (p[0] == '\0') 6993955d011SMarcel Moolenaar return; 7003955d011SMarcel Moolenaar 7013955d011SMarcel Moolenaar #ifndef POSIX 7023955d011SMarcel Moolenaar { 7033955d011SMarcel Moolenaar /* 7043955d011SMarcel Moolenaar * $MAKE may simply be naming the make(1) binary 7053955d011SMarcel Moolenaar */ 7063955d011SMarcel Moolenaar char *cp; 7073955d011SMarcel Moolenaar 7083955d011SMarcel Moolenaar if (!(cp = strrchr(line, '/'))) 7093955d011SMarcel Moolenaar cp = line; 7103955d011SMarcel Moolenaar if ((cp = strstr(cp, "make")) && 7113955d011SMarcel Moolenaar strcmp(cp, "make") == 0) 7123955d011SMarcel Moolenaar return; 7133955d011SMarcel Moolenaar } 7143955d011SMarcel Moolenaar #endif 715e2eeea75SSimon J. Gerraty { 716dba7b0efSSimon J. Gerraty FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE"); 717*d5e0a182SSimon J. Gerraty buf = str_concat3(argv0.str, " ", p); 71806b9b3e0SSimon J. Gerraty FStr_Done(&argv0); 719e2eeea75SSimon J. Gerraty } 7203955d011SMarcel Moolenaar 721b0c40a00SSimon J. Gerraty words = Str_Words(buf, true); 7222c3632d1SSimon J. Gerraty if (words.words == NULL) { 7233955d011SMarcel Moolenaar Error("Unterminated quoted string [%s]", buf); 7243955d011SMarcel Moolenaar free(buf); 7253955d011SMarcel Moolenaar return; 7263955d011SMarcel Moolenaar } 7273955d011SMarcel Moolenaar free(buf); 7282c3632d1SSimon J. Gerraty MainParseArgs((int)words.len, words.words); 7293955d011SMarcel Moolenaar 7302c3632d1SSimon J. Gerraty Words_Free(words); 7313955d011SMarcel Moolenaar } 7323955d011SMarcel Moolenaar 733b0c40a00SSimon J. Gerraty bool 734b0c40a00SSimon J. Gerraty Main_SetObjdir(bool writable, const char *fmt, ...) 7353955d011SMarcel Moolenaar { 7363955d011SMarcel Moolenaar struct stat sb; 737b46b9039SSimon J. Gerraty char *path; 738b46b9039SSimon J. Gerraty char buf[MAXPATHLEN + 1]; 739e23f3f6eSSimon J. Gerraty char buf2[MAXPATHLEN + 1]; 74045447996SSimon J. Gerraty va_list ap; 74145447996SSimon J. Gerraty 74245447996SSimon J. Gerraty va_start(ap, fmt); 743b46b9039SSimon J. Gerraty vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 74445447996SSimon J. Gerraty va_end(ap); 7453955d011SMarcel Moolenaar 7463955d011SMarcel Moolenaar if (path[0] != '/') { 7474fde40d9SSimon J. Gerraty if (snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path) <= MAXPATHLEN) 748e1cee40dSSimon J. Gerraty path = buf2; 7494fde40d9SSimon J. Gerraty else 7504fde40d9SSimon J. Gerraty return false; 7513955d011SMarcel Moolenaar } 7523955d011SMarcel Moolenaar 7533955d011SMarcel Moolenaar /* look for the directory and try to chdir there */ 7549f45a3c8SSimon J. Gerraty if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode)) 7559f45a3c8SSimon J. Gerraty return false; 7569f45a3c8SSimon J. Gerraty 7579f45a3c8SSimon J. Gerraty if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) { 7581d3f2ddcSSimon J. Gerraty (void)fprintf(stderr, "%s: warning: %s: %s.\n", 759e2eeea75SSimon J. Gerraty progname, path, strerror(errno)); 7609f45a3c8SSimon J. Gerraty return false; 7619f45a3c8SSimon J. Gerraty } 7629f45a3c8SSimon J. Gerraty 7632c3632d1SSimon J. Gerraty snprintf(objdir, sizeof objdir, "%s", path); 764dba7b0efSSimon J. Gerraty Global_Set(".OBJDIR", objdir); 7653955d011SMarcel Moolenaar setenv("PWD", objdir, 1); 7663955d011SMarcel Moolenaar Dir_InitDot(); 767e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(); 768956e45f6SSimon J. Gerraty if (opts.enterFlag && strcmp(objdir, curdir) != 0) 769b0c40a00SSimon J. Gerraty enterFlagObj = true; 7709f45a3c8SSimon J. Gerraty return true; 7713955d011SMarcel Moolenaar } 7723955d011SMarcel Moolenaar 773b0c40a00SSimon J. Gerraty static bool 774b0c40a00SSimon J. Gerraty SetVarObjdir(bool writable, const char *var, const char *suffix) 77545447996SSimon J. Gerraty { 776dba7b0efSSimon J. Gerraty FStr path = Var_Value(SCOPE_CMDLINE, var); 777b46b9039SSimon J. Gerraty 77806b9b3e0SSimon J. Gerraty if (path.str == NULL || path.str[0] == '\0') { 77906b9b3e0SSimon J. Gerraty FStr_Done(&path); 780b0c40a00SSimon J. Gerraty return false; 7812c3632d1SSimon J. Gerraty } 78245447996SSimon J. Gerraty 7839f45a3c8SSimon J. Gerraty Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES); 784b46b9039SSimon J. Gerraty 7859f45a3c8SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", path.str, suffix); 786b46b9039SSimon J. Gerraty 78706b9b3e0SSimon J. Gerraty FStr_Done(&path); 788b0c40a00SSimon J. Gerraty return true; 78945447996SSimon J. Gerraty } 79045447996SSimon J. Gerraty 79106b9b3e0SSimon J. Gerraty /* 792*d5e0a182SSimon J. Gerraty * Splits str into words (in-place, modifying it), adding them to the list. 79306b9b3e0SSimon J. Gerraty * The string must be kept alive as long as the list. 79406b9b3e0SSimon J. Gerraty */ 795*d5e0a182SSimon J. Gerraty void 796*d5e0a182SSimon J. Gerraty AppendWords(StringList *lp, char *str) 7973955d011SMarcel Moolenaar { 798*d5e0a182SSimon J. Gerraty char *p; 799e2eeea75SSimon J. Gerraty const char *sep = " \t"; 8003955d011SMarcel Moolenaar 801*d5e0a182SSimon J. Gerraty for (p = strtok(str, sep); p != NULL; p = strtok(NULL, sep)) 802*d5e0a182SSimon J. Gerraty Lst_Append(lp, p); 8033955d011SMarcel Moolenaar } 8043955d011SMarcel Moolenaar 8053955d011SMarcel Moolenaar #ifdef SIGINFO 8063955d011SMarcel Moolenaar /*ARGSUSED*/ 8073955d011SMarcel Moolenaar static void 8083955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED) 8093955d011SMarcel Moolenaar { 8103955d011SMarcel Moolenaar char dir[MAXPATHLEN]; 8113955d011SMarcel Moolenaar char str[2 * MAXPATHLEN]; 8123955d011SMarcel Moolenaar int len; 813e2eeea75SSimon J. Gerraty if (getcwd(dir, sizeof dir) == NULL) 8143955d011SMarcel Moolenaar return; 815e2eeea75SSimon J. Gerraty len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir); 8163955d011SMarcel Moolenaar if (len > 0) 8173955d011SMarcel Moolenaar (void)write(STDERR_FILENO, str, (size_t)len); 8183955d011SMarcel Moolenaar } 8193955d011SMarcel Moolenaar #endif 8203955d011SMarcel Moolenaar 82106b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */ 82206b9b3e0SSimon J. Gerraty static void 82306b9b3e0SSimon J. Gerraty MakeMode(void) 8243955d011SMarcel Moolenaar { 8258c973ee2SSimon J. Gerraty char *mode = Var_Subst("${.MAKE.MODE:tl}", 8268c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 827956e45f6SSimon J. Gerraty /* TODO: handle errors */ 8283955d011SMarcel Moolenaar 829dba7b0efSSimon J. Gerraty if (mode[0] != '\0') { 830dba7b0efSSimon J. Gerraty if (strstr(mode, "compat") != NULL) { 831b0c40a00SSimon J. Gerraty opts.compatMake = true; 832b0c40a00SSimon J. Gerraty forceJobs = false; 8333955d011SMarcel Moolenaar } 8343955d011SMarcel Moolenaar #if USE_META 835dba7b0efSSimon J. Gerraty if (strstr(mode, "meta") != NULL) 836dba7b0efSSimon J. Gerraty meta_mode_init(mode); 8373955d011SMarcel Moolenaar #endif 838954401e6SSimon J. Gerraty if (strstr(mode, "randomize-targets") != NULL) 839954401e6SSimon J. Gerraty opts.randomizeTargets = true; 8403955d011SMarcel Moolenaar } 841be19d90bSSimon J. Gerraty 842dba7b0efSSimon J. Gerraty free(mode); 8433955d011SMarcel Moolenaar } 8443955d011SMarcel Moolenaar 8458695518cSSimon J. Gerraty static void 846b0c40a00SSimon J. Gerraty PrintVar(const char *varname, bool expandVars) 847956e45f6SSimon J. Gerraty { 84806b9b3e0SSimon J. Gerraty if (strchr(varname, '$') != NULL) { 8498c973ee2SSimon J. Gerraty char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES); 850956e45f6SSimon J. Gerraty /* TODO: handle errors */ 851956e45f6SSimon J. Gerraty printf("%s\n", evalue); 8529f45a3c8SSimon J. Gerraty free(evalue); 853956e45f6SSimon J. Gerraty 854956e45f6SSimon J. Gerraty } else if (expandVars) { 855956e45f6SSimon J. Gerraty char *expr = str_concat3("${", varname, "}"); 8568c973ee2SSimon J. Gerraty char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); 857956e45f6SSimon J. Gerraty /* TODO: handle errors */ 858956e45f6SSimon J. Gerraty free(expr); 859956e45f6SSimon J. Gerraty printf("%s\n", evalue); 8609f45a3c8SSimon J. Gerraty free(evalue); 861956e45f6SSimon J. Gerraty 862956e45f6SSimon J. Gerraty } else { 863dba7b0efSSimon J. Gerraty FStr value = Var_Value(SCOPE_GLOBAL, varname); 86406b9b3e0SSimon J. Gerraty printf("%s\n", value.str != NULL ? value.str : ""); 86506b9b3e0SSimon J. Gerraty FStr_Done(&value); 866956e45f6SSimon J. Gerraty } 867956e45f6SSimon J. Gerraty } 868956e45f6SSimon J. Gerraty 869e2eeea75SSimon J. Gerraty /* 870b0c40a00SSimon J. Gerraty * Return a bool based on a variable. 871e2eeea75SSimon J. Gerraty * 872e2eeea75SSimon J. Gerraty * If the knob is not set, return the fallback. 873e2eeea75SSimon J. Gerraty * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 874b0c40a00SSimon J. Gerraty * is false, otherwise true. 875e2eeea75SSimon J. Gerraty */ 876b0c40a00SSimon J. Gerraty bool 877b0c40a00SSimon J. Gerraty GetBooleanExpr(const char *expr, bool fallback) 878e2eeea75SSimon J. Gerraty { 879e2eeea75SSimon J. Gerraty char *value; 880b0c40a00SSimon J. Gerraty bool res; 881e2eeea75SSimon J. Gerraty 8828c973ee2SSimon J. Gerraty value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); 883e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 884e2eeea75SSimon J. Gerraty res = ParseBoolean(value, fallback); 885e2eeea75SSimon J. Gerraty free(value); 886e2eeea75SSimon J. Gerraty return res; 887e2eeea75SSimon J. Gerraty } 888e2eeea75SSimon J. Gerraty 889956e45f6SSimon J. Gerraty static void 8908695518cSSimon J. Gerraty doPrintVars(void) 8918695518cSSimon J. Gerraty { 892956e45f6SSimon J. Gerraty StringListNode *ln; 893b0c40a00SSimon J. Gerraty bool expandVars; 8948695518cSSimon J. Gerraty 895e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_EXPANDED) 896b0c40a00SSimon J. Gerraty expandVars = true; 897956e45f6SSimon J. Gerraty else if (opts.debugVflag) 898b0c40a00SSimon J. Gerraty expandVars = false; 8998695518cSSimon J. Gerraty else 900b0c40a00SSimon J. Gerraty expandVars = GetBooleanExpr("${.MAKE.EXPAND_VARIABLES}", 901b0c40a00SSimon J. Gerraty false); 9028695518cSSimon J. Gerraty 90306b9b3e0SSimon J. Gerraty for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 904956e45f6SSimon J. Gerraty const char *varname = ln->datum; 905956e45f6SSimon J. Gerraty PrintVar(varname, expandVars); 9068695518cSSimon J. Gerraty } 9078695518cSSimon J. Gerraty } 9088695518cSSimon J. Gerraty 909b0c40a00SSimon J. Gerraty static bool 9108695518cSSimon J. Gerraty runTargets(void) 9118695518cSSimon J. Gerraty { 91206b9b3e0SSimon J. Gerraty GNodeList targs = LST_INIT; /* target nodes to create */ 913b0c40a00SSimon J. Gerraty bool outOfDate; /* false if all targets up to date */ 9148695518cSSimon J. Gerraty 9158695518cSSimon J. Gerraty /* 9168695518cSSimon J. Gerraty * Have now read the entire graph and need to make a list of 9178695518cSSimon J. Gerraty * targets to create. If none was given on the command line, 9188695518cSSimon J. Gerraty * we consult the parsing module to find the main target(s) 9198695518cSSimon J. Gerraty * to create. 9208695518cSSimon J. Gerraty */ 92106b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) 92206b9b3e0SSimon J. Gerraty Parse_MainName(&targs); 9238695518cSSimon J. Gerraty else 92406b9b3e0SSimon J. Gerraty Targ_FindList(&targs, &opts.create); 9258695518cSSimon J. Gerraty 926956e45f6SSimon J. Gerraty if (!opts.compatMake) { 9278695518cSSimon J. Gerraty /* 9288695518cSSimon J. Gerraty * Initialize job module before traversing the graph 9298695518cSSimon J. Gerraty * now that any .BEGIN and .END targets have been read. 9308695518cSSimon J. Gerraty * This is done only if the -q flag wasn't given 9318695518cSSimon J. Gerraty * (to prevent the .BEGIN from being executed should 9328695518cSSimon J. Gerraty * it exist). 9338695518cSSimon J. Gerraty */ 9349f45a3c8SSimon J. Gerraty if (!opts.query) { 9358695518cSSimon J. Gerraty Job_Init(); 936b0c40a00SSimon J. Gerraty jobsRunning = true; 9378695518cSSimon J. Gerraty } 9388695518cSSimon J. Gerraty 9398695518cSSimon J. Gerraty /* Traverse the graph, checking on all the targets */ 94006b9b3e0SSimon J. Gerraty outOfDate = Make_Run(&targs); 9418695518cSSimon J. Gerraty } else { 942954401e6SSimon J. Gerraty Compat_MakeAll(&targs); 943b0c40a00SSimon J. Gerraty outOfDate = false; 9448695518cSSimon J. Gerraty } 945dba7b0efSSimon J. Gerraty Lst_Done(&targs); /* Don't free the targets themselves. */ 9468695518cSSimon J. Gerraty return outOfDate; 9478695518cSSimon J. Gerraty } 9488695518cSSimon J. Gerraty 949956e45f6SSimon J. Gerraty /* 9509f45a3c8SSimon J. Gerraty * Set up the .TARGETS variable to contain the list of targets to be created. 9519f45a3c8SSimon J. Gerraty * If none specified, make the variable empty for now, the parser will fill 9529f45a3c8SSimon J. Gerraty * in the default or .MAIN target later. 953956e45f6SSimon J. Gerraty */ 954956e45f6SSimon J. Gerraty static void 955956e45f6SSimon J. Gerraty InitVarTargets(void) 956956e45f6SSimon J. Gerraty { 957956e45f6SSimon J. Gerraty StringListNode *ln; 958956e45f6SSimon J. Gerraty 95906b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) { 960dba7b0efSSimon J. Gerraty Global_Set(".TARGETS", ""); 961956e45f6SSimon J. Gerraty return; 962956e45f6SSimon J. Gerraty } 963956e45f6SSimon J. Gerraty 96406b9b3e0SSimon J. Gerraty for (ln = opts.create.first; ln != NULL; ln = ln->next) { 965dba7b0efSSimon J. Gerraty const char *name = ln->datum; 966dba7b0efSSimon J. Gerraty Global_Append(".TARGETS", name); 967956e45f6SSimon J. Gerraty } 968956e45f6SSimon J. Gerraty } 969956e45f6SSimon J. Gerraty 970956e45f6SSimon J. Gerraty static void 971956e45f6SSimon J. Gerraty InitRandom(void) 972956e45f6SSimon J. Gerraty { 973956e45f6SSimon J. Gerraty struct timeval tv; 974956e45f6SSimon J. Gerraty 975956e45f6SSimon J. Gerraty gettimeofday(&tv, NULL); 976956e45f6SSimon J. Gerraty srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 977956e45f6SSimon J. Gerraty } 978956e45f6SSimon J. Gerraty 979956e45f6SSimon J. Gerraty static const char * 980dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED) 981956e45f6SSimon J. Gerraty { 982956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE 983e2eeea75SSimon J. Gerraty return FORCE_MACHINE; 984956e45f6SSimon J. Gerraty #else 985956e45f6SSimon J. Gerraty const char *machine = getenv("MACHINE"); 986e2eeea75SSimon J. Gerraty 987956e45f6SSimon J. Gerraty if (machine != NULL) 988956e45f6SSimon J. Gerraty return machine; 989956e45f6SSimon J. Gerraty 990e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE) 991956e45f6SSimon J. Gerraty return utsname->machine; 992e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE) 993956e45f6SSimon J. Gerraty return MAKE_MACHINE; 994956e45f6SSimon J. Gerraty #else 995956e45f6SSimon J. Gerraty return "unknown"; 996956e45f6SSimon J. Gerraty #endif 997956e45f6SSimon J. Gerraty #endif 998956e45f6SSimon J. Gerraty } 999956e45f6SSimon J. Gerraty 1000956e45f6SSimon J. Gerraty static const char * 1001e2eeea75SSimon J. Gerraty InitVarMachineArch(void) 1002956e45f6SSimon J. Gerraty { 1003e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH 1004e2eeea75SSimon J. Gerraty return FORCE_MACHINE_ARCH; 1005e2eeea75SSimon J. Gerraty #else 1006956e45f6SSimon J. Gerraty const char *env = getenv("MACHINE_ARCH"); 1007956e45f6SSimon J. Gerraty if (env != NULL) 1008956e45f6SSimon J. Gerraty return env; 1009956e45f6SSimon J. Gerraty 1010956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW) 1011956e45f6SSimon J. Gerraty { 1012956e45f6SSimon J. Gerraty struct utsname utsname; 1013e2eeea75SSimon J. Gerraty static char machine_arch_buf[sizeof utsname.machine]; 1014956e45f6SSimon J. Gerraty const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1015e2eeea75SSimon J. Gerraty size_t len = sizeof machine_arch_buf; 1016956e45f6SSimon J. Gerraty 101706b9b3e0SSimon J. Gerraty if (sysctl(mib, (unsigned int)__arraycount(mib), 101806b9b3e0SSimon J. Gerraty machine_arch_buf, &len, NULL, 0) < 0) { 101906b9b3e0SSimon J. Gerraty (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 102006b9b3e0SSimon J. Gerraty progname, strerror(errno)); 1021956e45f6SSimon J. Gerraty exit(2); 1022956e45f6SSimon J. Gerraty } 1023956e45f6SSimon J. Gerraty 1024956e45f6SSimon J. Gerraty return machine_arch_buf; 1025956e45f6SSimon J. Gerraty } 1026e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH) 1027e2eeea75SSimon J. Gerraty return MACHINE_ARCH; 1028e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH) 1029956e45f6SSimon J. Gerraty return MAKE_MACHINE_ARCH; 1030956e45f6SSimon J. Gerraty #else 1031956e45f6SSimon J. Gerraty return "unknown"; 1032956e45f6SSimon J. Gerraty #endif 1033956e45f6SSimon J. Gerraty #endif 1034956e45f6SSimon J. Gerraty } 1035956e45f6SSimon J. Gerraty 1036956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE 1037956e45f6SSimon J. Gerraty /* 1038956e45f6SSimon J. Gerraty * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1039956e45f6SSimon J. Gerraty * since the value of curdir can vary depending on how we got 1040*d5e0a182SSimon J. Gerraty * here. That is, sitting at a shell prompt (shell that provides $PWD) 1041*d5e0a182SSimon J. Gerraty * or via subdir.mk, in which case it's likely a shell which does 1042956e45f6SSimon J. Gerraty * not provide it. 1043956e45f6SSimon J. Gerraty * 1044956e45f6SSimon J. Gerraty * So, to stop it breaking this case only, we ignore PWD if 1045*d5e0a182SSimon J. Gerraty * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains an expression. 1046956e45f6SSimon J. Gerraty */ 1047956e45f6SSimon J. Gerraty static void 1048956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st) 1049956e45f6SSimon J. Gerraty { 1050956e45f6SSimon J. Gerraty char *pwd; 10519f45a3c8SSimon J. Gerraty FStr makeobjdir; 1052956e45f6SSimon J. Gerraty struct stat pwd_st; 1053956e45f6SSimon J. Gerraty 1054956e45f6SSimon J. Gerraty if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1055956e45f6SSimon J. Gerraty return; 1056956e45f6SSimon J. Gerraty 10579f45a3c8SSimon J. Gerraty if (Var_Exists(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX")) 1058956e45f6SSimon J. Gerraty return; 1059956e45f6SSimon J. Gerraty 1060dba7b0efSSimon J. Gerraty makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR"); 106106b9b3e0SSimon J. Gerraty if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1062956e45f6SSimon J. Gerraty goto ignore_pwd; 1063956e45f6SSimon J. Gerraty 1064956e45f6SSimon J. Gerraty if (stat(pwd, &pwd_st) == 0 && 1065956e45f6SSimon J. Gerraty curdir_st->st_ino == pwd_st.st_ino && 1066956e45f6SSimon J. Gerraty curdir_st->st_dev == pwd_st.st_dev) 1067956e45f6SSimon J. Gerraty (void)strncpy(curdir, pwd, MAXPATHLEN); 1068956e45f6SSimon J. Gerraty 1069956e45f6SSimon J. Gerraty ignore_pwd: 107006b9b3e0SSimon J. Gerraty FStr_Done(&makeobjdir); 1071956e45f6SSimon J. Gerraty } 1072956e45f6SSimon J. Gerraty #endif 1073956e45f6SSimon J. Gerraty 1074956e45f6SSimon J. Gerraty /* 10759f45a3c8SSimon J. Gerraty * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, MAKEOBJDIR is set 10769f45a3c8SSimon J. Gerraty * in the environment, try only that value and fall back to .CURDIR if it 10779f45a3c8SSimon J. Gerraty * does not exist. 1078956e45f6SSimon J. Gerraty * 1079956e45f6SSimon J. Gerraty * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 10809f45a3c8SSimon J. Gerraty * and finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none of these 10819f45a3c8SSimon J. Gerraty * paths exist, just use .CURDIR. 1082956e45f6SSimon J. Gerraty */ 1083956e45f6SSimon J. Gerraty static void 1084956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch) 1085956e45f6SSimon J. Gerraty { 1086b0c40a00SSimon J. Gerraty bool writable; 1087956e45f6SSimon J. Gerraty 108806b9b3e0SSimon J. Gerraty Dir_InitCur(curdir); 1089b0c40a00SSimon J. Gerraty writable = GetBooleanExpr("${MAKE_OBJDIR_CHECK_WRITABLE}", true); 1090b0c40a00SSimon J. Gerraty (void)Main_SetObjdir(false, "%s", curdir); 1091e2eeea75SSimon J. Gerraty 1092e2eeea75SSimon J. Gerraty if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1093e2eeea75SSimon J. Gerraty !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1094e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1095e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1096e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1097e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1098956e45f6SSimon J. Gerraty } 1099956e45f6SSimon J. Gerraty 1100956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */ 1101956e45f6SSimon J. Gerraty static void 1102956e45f6SSimon J. Gerraty UnlimitFiles(void) 1103956e45f6SSimon J. Gerraty { 110412904384SSimon J. Gerraty #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) 1105956e45f6SSimon J. Gerraty struct rlimit rl; 1106956e45f6SSimon J. Gerraty if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1107956e45f6SSimon J. Gerraty rl.rlim_cur != rl.rlim_max) { 11088c973ee2SSimon J. Gerraty #ifdef BMAKE_NOFILE_MAX 11098c973ee2SSimon J. Gerraty if (BMAKE_NOFILE_MAX < rl.rlim_max) 11108c973ee2SSimon J. Gerraty rl.rlim_cur = BMAKE_NOFILE_MAX; 11118c973ee2SSimon J. Gerraty else 11128c973ee2SSimon J. Gerraty #endif 1113956e45f6SSimon J. Gerraty rl.rlim_cur = rl.rlim_max; 1114956e45f6SSimon J. Gerraty (void)setrlimit(RLIMIT_NOFILE, &rl); 1115956e45f6SSimon J. Gerraty } 1116956e45f6SSimon J. Gerraty #endif 1117956e45f6SSimon J. Gerraty } 1118956e45f6SSimon J. Gerraty 1119956e45f6SSimon J. Gerraty static void 1120956e45f6SSimon J. Gerraty CmdOpts_Init(void) 1121956e45f6SSimon J. Gerraty { 1122b0c40a00SSimon J. Gerraty opts.compatMake = false; 11239f45a3c8SSimon J. Gerraty memset(&opts.debug, 0, sizeof(opts.debug)); 1124dba7b0efSSimon J. Gerraty /* opts.debug_file has already been initialized earlier */ 1125b0c40a00SSimon J. Gerraty opts.strict = false; 1126b0c40a00SSimon J. Gerraty opts.debugVflag = false; 1127b0c40a00SSimon J. Gerraty opts.checkEnvFirst = false; 112806b9b3e0SSimon J. Gerraty Lst_Init(&opts.makefiles); 1129b0c40a00SSimon J. Gerraty opts.ignoreErrors = false; /* Pay attention to non-zero returns */ 113006b9b3e0SSimon J. Gerraty opts.maxJobs = 1; 1131b0c40a00SSimon J. Gerraty opts.keepgoing = false; /* Stop on error */ 1132b0c40a00SSimon J. Gerraty opts.noRecursiveExecute = false; /* Execute all .MAKE targets */ 1133b0c40a00SSimon J. Gerraty opts.noExecute = false; /* Execute all commands */ 11349f45a3c8SSimon J. Gerraty opts.query = false; 1135b0c40a00SSimon J. Gerraty opts.noBuiltins = false; /* Read the built-in rules */ 11369f45a3c8SSimon J. Gerraty opts.silent = false; /* Print commands as executed */ 11379f45a3c8SSimon J. Gerraty opts.touch = false; 1138e2eeea75SSimon J. Gerraty opts.printVars = PVM_NONE; 113906b9b3e0SSimon J. Gerraty Lst_Init(&opts.variables); 1140b0c40a00SSimon J. Gerraty opts.parseWarnFatal = false; 1141b0c40a00SSimon J. Gerraty opts.enterFlag = false; 1142b0c40a00SSimon J. Gerraty opts.varNoExportEnv = false; 114306b9b3e0SSimon J. Gerraty Lst_Init(&opts.create); 1144956e45f6SSimon J. Gerraty } 1145956e45f6SSimon J. Gerraty 114606b9b3e0SSimon J. Gerraty /* 114706b9b3e0SSimon J. Gerraty * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1148956e45f6SSimon J. Gerraty * found by execvp(3) and the shells, even after a chdir. 1149956e45f6SSimon J. Gerraty * 1150956e45f6SSimon J. Gerraty * If it's a relative path and contains a '/', resolve it to an absolute path. 115106b9b3e0SSimon J. Gerraty * Otherwise keep it as is, assuming it will be found in the PATH. 115206b9b3e0SSimon J. Gerraty */ 1153956e45f6SSimon J. Gerraty static void 1154956e45f6SSimon J. Gerraty InitVarMake(const char *argv0) 1155956e45f6SSimon J. Gerraty { 1156956e45f6SSimon J. Gerraty const char *make = argv0; 1157956e45f6SSimon J. Gerraty 1158956e45f6SSimon J. Gerraty if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1159956e45f6SSimon J. Gerraty char pathbuf[MAXPATHLEN]; 116006b9b3e0SSimon J. Gerraty const char *abspath = cached_realpath(argv0, pathbuf); 1161956e45f6SSimon J. Gerraty struct stat st; 116206b9b3e0SSimon J. Gerraty if (abspath != NULL && abspath[0] == '/' && 116306b9b3e0SSimon J. Gerraty stat(make, &st) == 0) 116406b9b3e0SSimon J. Gerraty make = abspath; 1165956e45f6SSimon J. Gerraty } 1166956e45f6SSimon J. Gerraty 1167dba7b0efSSimon J. Gerraty Global_Set("MAKE", make); 1168dba7b0efSSimon J. Gerraty Global_Set(".MAKE", make); 1169956e45f6SSimon J. Gerraty } 1170956e45f6SSimon J. Gerraty 117106b9b3e0SSimon J. Gerraty /* 117206b9b3e0SSimon J. Gerraty * Add the directories from the colon-separated syspath to defSysIncPath. 117306b9b3e0SSimon J. Gerraty * After returning, the contents of syspath is unspecified. 117406b9b3e0SSimon J. Gerraty */ 1175956e45f6SSimon J. Gerraty static void 1176956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath) 1177956e45f6SSimon J. Gerraty { 1178956e45f6SSimon J. Gerraty static char defsyspath[] = _PATH_DEFSYSPATH; 1179*d5e0a182SSimon J. Gerraty char *start, *p; 1180956e45f6SSimon J. Gerraty 1181956e45f6SSimon J. Gerraty /* 1182956e45f6SSimon J. Gerraty * If no user-supplied system path was given (through the -m option) 1183956e45f6SSimon J. Gerraty * add the directories from the DEFSYSPATH (more than one may be given 1184956e45f6SSimon J. Gerraty * as dir1:...:dirn) to the system include path. 1185956e45f6SSimon J. Gerraty */ 1186956e45f6SSimon J. Gerraty if (syspath == NULL || syspath[0] == '\0') 1187956e45f6SSimon J. Gerraty syspath = defsyspath; 1188956e45f6SSimon J. Gerraty else 1189956e45f6SSimon J. Gerraty syspath = bmake_strdup(syspath); 1190956e45f6SSimon J. Gerraty 1191*d5e0a182SSimon J. Gerraty for (start = syspath; *start != '\0'; start = p) { 1192*d5e0a182SSimon J. Gerraty for (p = start; *p != '\0' && *p != ':'; p++) 1193956e45f6SSimon J. Gerraty continue; 1194*d5e0a182SSimon J. Gerraty if (*p == ':') 1195*d5e0a182SSimon J. Gerraty *p++ = '\0'; 1196e2eeea75SSimon J. Gerraty 1197956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 1198e2eeea75SSimon J. Gerraty if (strncmp(start, ".../", 4) == 0) { 1199956e45f6SSimon J. Gerraty char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1200956e45f6SSimon J. Gerraty if (dir != NULL) { 1201dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, dir); 1202956e45f6SSimon J. Gerraty free(dir); 1203956e45f6SSimon J. Gerraty } 1204e2eeea75SSimon J. Gerraty } else { 1205dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, start); 1206956e45f6SSimon J. Gerraty } 1207956e45f6SSimon J. Gerraty } 1208956e45f6SSimon J. Gerraty 1209956e45f6SSimon J. Gerraty if (syspath != defsyspath) 1210956e45f6SSimon J. Gerraty free(syspath); 1211956e45f6SSimon J. Gerraty } 1212956e45f6SSimon J. Gerraty 1213956e45f6SSimon J. Gerraty static void 1214956e45f6SSimon J. Gerraty ReadBuiltinRules(void) 1215956e45f6SSimon J. Gerraty { 1216e2eeea75SSimon J. Gerraty StringListNode *ln; 1217dba7b0efSSimon J. Gerraty StringList sysMkFiles = LST_INIT; 1218e2eeea75SSimon J. Gerraty 1219dba7b0efSSimon J. Gerraty SearchPath_Expand( 1220dba7b0efSSimon J. Gerraty Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath, 1221dba7b0efSSimon J. Gerraty _PATH_DEFSYSMK, 1222dba7b0efSSimon J. Gerraty &sysMkFiles); 1223dba7b0efSSimon J. Gerraty if (Lst_IsEmpty(&sysMkFiles)) 1224956e45f6SSimon J. Gerraty Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1225e2eeea75SSimon J. Gerraty 1226dba7b0efSSimon J. Gerraty for (ln = sysMkFiles.first; ln != NULL; ln = ln->next) 12279f45a3c8SSimon J. Gerraty if (ReadMakefile(ln->datum)) 1228e2eeea75SSimon J. Gerraty break; 1229e2eeea75SSimon J. Gerraty 1230e2eeea75SSimon J. Gerraty if (ln == NULL) 1231e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", 1232dba7b0efSSimon J. Gerraty progname, (const char *)sysMkFiles.first->datum); 1233e2eeea75SSimon J. Gerraty 12349f45a3c8SSimon J. Gerraty Lst_DoneCall(&sysMkFiles, free); 1235956e45f6SSimon J. Gerraty } 1236956e45f6SSimon J. Gerraty 1237956e45f6SSimon J. Gerraty static void 1238956e45f6SSimon J. Gerraty InitMaxJobs(void) 1239956e45f6SSimon J. Gerraty { 1240956e45f6SSimon J. Gerraty char *value; 1241956e45f6SSimon J. Gerraty int n; 1242956e45f6SSimon J. Gerraty 1243956e45f6SSimon J. Gerraty if (forceJobs || opts.compatMake || 1244dba7b0efSSimon J. Gerraty !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) 1245956e45f6SSimon J. Gerraty return; 1246956e45f6SSimon J. Gerraty 12478c973ee2SSimon J. Gerraty value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES); 1248956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1249956e45f6SSimon J. Gerraty n = (int)strtol(value, NULL, 0); 1250956e45f6SSimon J. Gerraty if (n < 1) { 1251956e45f6SSimon J. Gerraty (void)fprintf(stderr, 1252956e45f6SSimon J. Gerraty "%s: illegal value for .MAKE.JOBS " 1253956e45f6SSimon J. Gerraty "-- must be positive integer!\n", 1254956e45f6SSimon J. Gerraty progname); 125506b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 1256956e45f6SSimon J. Gerraty } 1257956e45f6SSimon J. Gerraty 1258956e45f6SSimon J. Gerraty if (n != opts.maxJobs) { 1259dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-j"); 1260dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, value); 1261956e45f6SSimon J. Gerraty } 1262956e45f6SSimon J. Gerraty 1263956e45f6SSimon J. Gerraty opts.maxJobs = n; 1264956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1265b0c40a00SSimon J. Gerraty forceJobs = true; 1266956e45f6SSimon J. Gerraty free(value); 1267956e45f6SSimon J. Gerraty } 1268956e45f6SSimon J. Gerraty 1269956e45f6SSimon J. Gerraty /* 1270956e45f6SSimon J. Gerraty * For compatibility, look at the directories in the VPATH variable 1271956e45f6SSimon J. Gerraty * and add them to the search path, if the variable is defined. The 1272956e45f6SSimon J. Gerraty * variable's value is in the same format as the PATH environment 1273956e45f6SSimon J. Gerraty * variable, i.e. <directory>:<directory>:<directory>... 1274956e45f6SSimon J. Gerraty */ 1275956e45f6SSimon J. Gerraty static void 1276956e45f6SSimon J. Gerraty InitVpath(void) 1277956e45f6SSimon J. Gerraty { 1278956e45f6SSimon J. Gerraty char *vpath, savec, *path; 1279dba7b0efSSimon J. Gerraty if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) 1280956e45f6SSimon J. Gerraty return; 1281956e45f6SSimon J. Gerraty 12828c973ee2SSimon J. Gerraty vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES); 1283956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1284956e45f6SSimon J. Gerraty path = vpath; 1285956e45f6SSimon J. Gerraty do { 1286*d5e0a182SSimon J. Gerraty char *p; 1287956e45f6SSimon J. Gerraty /* skip to end of directory */ 1288*d5e0a182SSimon J. Gerraty for (p = path; *p != ':' && *p != '\0'; p++) 1289956e45f6SSimon J. Gerraty continue; 1290956e45f6SSimon J. Gerraty /* Save terminator character so know when to stop */ 1291*d5e0a182SSimon J. Gerraty savec = *p; 1292*d5e0a182SSimon J. Gerraty *p = '\0'; 1293956e45f6SSimon J. Gerraty /* Add directory to search path */ 1294dba7b0efSSimon J. Gerraty (void)SearchPath_Add(&dirSearchPath, path); 1295*d5e0a182SSimon J. Gerraty *p = savec; 1296*d5e0a182SSimon J. Gerraty path = p + 1; 1297956e45f6SSimon J. Gerraty } while (savec == ':'); 1298956e45f6SSimon J. Gerraty free(vpath); 1299956e45f6SSimon J. Gerraty } 1300956e45f6SSimon J. Gerraty 1301956e45f6SSimon J. Gerraty static void 13029f45a3c8SSimon J. Gerraty ReadAllMakefiles(const StringList *makefiles) 1303956e45f6SSimon J. Gerraty { 1304956e45f6SSimon J. Gerraty StringListNode *ln; 1305956e45f6SSimon J. Gerraty 1306e2eeea75SSimon J. Gerraty for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1307e2eeea75SSimon J. Gerraty const char *fname = ln->datum; 13089f45a3c8SSimon J. Gerraty if (!ReadMakefile(fname)) 1309e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", progname, fname); 1310956e45f6SSimon J. Gerraty } 1311956e45f6SSimon J. Gerraty } 1312956e45f6SSimon J. Gerraty 1313956e45f6SSimon J. Gerraty static void 1314e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void) 1315956e45f6SSimon J. Gerraty { 13169f45a3c8SSimon J. Gerraty StringList makefiles = LST_INIT; 1317e2eeea75SSimon J. Gerraty StringListNode *ln; 13188c973ee2SSimon J. Gerraty char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}", 13198c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 1320e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 1321956e45f6SSimon J. Gerraty 1322*d5e0a182SSimon J. Gerraty AppendWords(&makefiles, prefs); 1323956e45f6SSimon J. Gerraty 13249f45a3c8SSimon J. Gerraty for (ln = makefiles.first; ln != NULL; ln = ln->next) 13259f45a3c8SSimon J. Gerraty if (ReadMakefile(ln->datum)) 1326e2eeea75SSimon J. Gerraty break; 1327956e45f6SSimon J. Gerraty 13289f45a3c8SSimon J. Gerraty Lst_Done(&makefiles); 1329e2eeea75SSimon J. Gerraty free(prefs); 1330956e45f6SSimon J. Gerraty } 1331956e45f6SSimon J. Gerraty 133206b9b3e0SSimon J. Gerraty /* 133306b9b3e0SSimon J. Gerraty * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1334e2eeea75SSimon J. Gerraty * Initialize a few modules. 133506b9b3e0SSimon J. Gerraty * Parse the arguments from MAKEFLAGS and the command line. 133606b9b3e0SSimon J. Gerraty */ 1337e2eeea75SSimon J. Gerraty static void 1338e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv) 13393955d011SMarcel Moolenaar { 1340956e45f6SSimon J. Gerraty struct stat sa; 1341956e45f6SSimon J. Gerraty const char *machine; 1342956e45f6SSimon J. Gerraty const char *machine_arch; 13433955d011SMarcel Moolenaar char *syspath = getenv("MAKESYSPATH"); 13443955d011SMarcel Moolenaar struct utsname utsname; 13453955d011SMarcel Moolenaar 13463955d011SMarcel Moolenaar /* default to writing debug to stderr */ 1347956e45f6SSimon J. Gerraty opts.debug_file = stderr; 13483955d011SMarcel Moolenaar 13499f45a3c8SSimon J. Gerraty Str_Intern_Init(); 1350e2eeea75SSimon J. Gerraty HashTable_Init(&cached_realpaths); 1351e2eeea75SSimon J. Gerraty 13523955d011SMarcel Moolenaar #ifdef SIGINFO 13533955d011SMarcel Moolenaar (void)bmake_signal(SIGINFO, siginfo); 13543955d011SMarcel Moolenaar #endif 1355956e45f6SSimon J. Gerraty 1356956e45f6SSimon J. Gerraty InitRandom(); 13573955d011SMarcel Moolenaar 135806b9b3e0SSimon J. Gerraty progname = str_basename(argv[0]); 1359956e45f6SSimon J. Gerraty 1360956e45f6SSimon J. Gerraty UnlimitFiles(); 13613955d011SMarcel Moolenaar 13621748de26SSimon J. Gerraty if (uname(&utsname) == -1) { 13631748de26SSimon J. Gerraty (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 13641748de26SSimon J. Gerraty strerror(errno)); 13651748de26SSimon J. Gerraty exit(2); 13661748de26SSimon J. Gerraty } 13671748de26SSimon J. Gerraty 1368e2eeea75SSimon J. Gerraty machine = InitVarMachine(&utsname); 1369e2eeea75SSimon J. Gerraty machine_arch = InitVarMachineArch(); 13703955d011SMarcel Moolenaar 13713955d011SMarcel Moolenaar myPid = getpid(); /* remember this for vFork() */ 13723955d011SMarcel Moolenaar 1373*d5e0a182SSimon J. Gerraty /* Just in case MAKEOBJDIR wants us to do something tricky. */ 1374e2eeea75SSimon J. Gerraty Targ_Init(); 1375e2eeea75SSimon J. Gerraty Var_Init(); 13764fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.OS", utsname.sysname); 1377dba7b0efSSimon J. Gerraty Global_Set("MACHINE", machine); 1378dba7b0efSSimon J. Gerraty Global_Set("MACHINE_ARCH", machine_arch); 13793955d011SMarcel Moolenaar #ifdef MAKE_VERSION 1380dba7b0efSSimon J. Gerraty Global_Set("MAKE_VERSION", MAKE_VERSION); 13813955d011SMarcel Moolenaar #endif 1382*d5e0a182SSimon J. Gerraty Global_Set_ReadOnly(".newline", "\n"); 13833955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST 13849f45a3c8SSimon J. Gerraty /* This is the traditional preference for makefiles. */ 13853955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 13863955d011SMarcel Moolenaar #endif 13878c973ee2SSimon J. Gerraty Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST); 13884fde40d9SSimon J. Gerraty Global_Set(".MAKE.DEPENDFILE", ".depend"); 138998875883SSimon J. Gerraty /* Tell makefiles like jobs.mk whether we support -jC */ 139098875883SSimon J. Gerraty #ifdef _SC_NPROCESSORS_ONLN 139198875883SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.JOBS.C", "yes"); 139298875883SSimon J. Gerraty #else 139398875883SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.JOBS.C", "no"); 139498875883SSimon J. Gerraty #endif 13953955d011SMarcel Moolenaar 1396956e45f6SSimon J. Gerraty CmdOpts_Init(); 1397b0c40a00SSimon J. Gerraty allPrecious = false; /* Remove targets when interrupted */ 1398b0c40a00SSimon J. Gerraty deleteOnError = false; /* Historical default behavior */ 1399b0c40a00SSimon J. Gerraty jobsRunning = false; 14003955d011SMarcel Moolenaar 1401956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1402b0c40a00SSimon J. Gerraty ignorePWD = false; 14033955d011SMarcel Moolenaar 14043955d011SMarcel Moolenaar /* 14053955d011SMarcel Moolenaar * Initialize the parsing, directory and variable modules to prepare 14063955d011SMarcel Moolenaar * for the reading of inclusion paths and variable settings on the 14073955d011SMarcel Moolenaar * command line 14083955d011SMarcel Moolenaar */ 14093955d011SMarcel Moolenaar 14103955d011SMarcel Moolenaar /* 14113955d011SMarcel Moolenaar * Initialize various variables. 14123955d011SMarcel Moolenaar * MAKE also gets this name, for compatibility 14133955d011SMarcel Moolenaar * .MAKEFLAGS gets set to the empty string just in case. 14143955d011SMarcel Moolenaar * MFLAGS also gets initialized empty, for compatibility. 14153955d011SMarcel Moolenaar */ 14163955d011SMarcel Moolenaar Parse_Init(); 1417956e45f6SSimon J. Gerraty InitVarMake(argv[0]); 1418dba7b0efSSimon J. Gerraty Global_Set(MAKEFLAGS, ""); 14198c973ee2SSimon J. Gerraty Global_Set(".MAKEOVERRIDES", ""); 1420dba7b0efSSimon J. Gerraty Global_Set("MFLAGS", ""); 1421dba7b0efSSimon J. Gerraty Global_Set(".ALLTARGETS", ""); 14224fde40d9SSimon J. Gerraty Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV); 14233955d011SMarcel Moolenaar 1424e2eeea75SSimon J. Gerraty /* Set some other useful variables. */ 14253955d011SMarcel Moolenaar { 14269f45a3c8SSimon J. Gerraty char buf[64], *ep = getenv(MAKE_LEVEL_ENV); 14273955d011SMarcel Moolenaar 1428e2eeea75SSimon J. Gerraty makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 142951ee2c1cSSimon J. Gerraty if (makelevel < 0) 143051ee2c1cSSimon J. Gerraty makelevel = 0; 14319f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%d", makelevel); 14328c973ee2SSimon J. Gerraty Global_Set(".MAKE.LEVEL", buf); 14339f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", myPid); 14344fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.PID", buf); 14359f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getppid()); 14364fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.PPID", buf); 14379f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getuid()); 14384fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.UID", buf); 14399f45a3c8SSimon J. Gerraty snprintf(buf, sizeof buf, "%u", getgid()); 14404fde40d9SSimon J. Gerraty Global_Set_ReadOnly(".MAKE.GID", buf); 14413955d011SMarcel Moolenaar } 144251ee2c1cSSimon J. Gerraty if (makelevel > 0) { 144351ee2c1cSSimon J. Gerraty char pn[1024]; 1444e2eeea75SSimon J. Gerraty snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 144551ee2c1cSSimon J. Gerraty progname = bmake_strdup(pn); 144651ee2c1cSSimon J. Gerraty } 14473955d011SMarcel Moolenaar 14481748de26SSimon J. Gerraty #ifdef USE_META 14491748de26SSimon J. Gerraty meta_init(); 14501748de26SSimon J. Gerraty #endif 14512c3632d1SSimon J. Gerraty Dir_Init(); 14521ce939a7SSimon J. Gerraty 14539f45a3c8SSimon J. Gerraty #ifdef POSIX 14549f45a3c8SSimon J. Gerraty { 14559f45a3c8SSimon J. Gerraty char *makeflags = explode(getenv("MAKEFLAGS")); 14569f45a3c8SSimon J. Gerraty Main_ParseArgLine(makeflags); 14579f45a3c8SSimon J. Gerraty free(makeflags); 14589f45a3c8SSimon J. Gerraty } 14599f45a3c8SSimon J. Gerraty #else 14603955d011SMarcel Moolenaar /* 14613955d011SMarcel Moolenaar * First snag any flags out of the MAKE environment variable. 14623955d011SMarcel Moolenaar * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 14633955d011SMarcel Moolenaar * in a different format). 14643955d011SMarcel Moolenaar */ 14653955d011SMarcel Moolenaar Main_ParseArgLine(getenv("MAKE")); 14663955d011SMarcel Moolenaar #endif 14673955d011SMarcel Moolenaar 14683955d011SMarcel Moolenaar if (getcwd(curdir, MAXPATHLEN) == NULL) { 14693955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: getcwd: %s.\n", 14703955d011SMarcel Moolenaar progname, strerror(errno)); 14713955d011SMarcel Moolenaar exit(2); 14723955d011SMarcel Moolenaar } 14733955d011SMarcel Moolenaar 14743955d011SMarcel Moolenaar MainParseArgs(argc, argv); 14753955d011SMarcel Moolenaar 1476956e45f6SSimon J. Gerraty if (opts.enterFlag) 147751ee2c1cSSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, curdir); 147851ee2c1cSSimon J. Gerraty 14793955d011SMarcel Moolenaar if (stat(curdir, &sa) == -1) { 14803955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: %s: %s.\n", 14813955d011SMarcel Moolenaar progname, curdir, strerror(errno)); 14823955d011SMarcel Moolenaar exit(2); 14833955d011SMarcel Moolenaar } 14843955d011SMarcel Moolenaar 14853955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE 1486956e45f6SSimon J. Gerraty HandlePWD(&sa); 14873955d011SMarcel Moolenaar #endif 1488dba7b0efSSimon J. Gerraty Global_Set(".CURDIR", curdir); 14893955d011SMarcel Moolenaar 1490956e45f6SSimon J. Gerraty InitObjdir(machine, machine_arch); 14913955d011SMarcel Moolenaar 14923955d011SMarcel Moolenaar Arch_Init(); 14933955d011SMarcel Moolenaar Suff_Init(); 14943955d011SMarcel Moolenaar Trace_Init(tracefile); 14953955d011SMarcel Moolenaar 1496e2eeea75SSimon J. Gerraty defaultNode = NULL; 14973955d011SMarcel Moolenaar (void)time(&now); 14983955d011SMarcel Moolenaar 14993955d011SMarcel Moolenaar Trace_Log(MAKESTART, NULL); 15003955d011SMarcel Moolenaar 1501956e45f6SSimon J. Gerraty InitVarTargets(); 15023955d011SMarcel Moolenaar 1503956e45f6SSimon J. Gerraty InitDefSysIncPath(syspath); 1504e2eeea75SSimon J. Gerraty } 15053955d011SMarcel Moolenaar 150606b9b3e0SSimon J. Gerraty /* 150706b9b3e0SSimon J. Gerraty * Read the system makefile followed by either makefile, Makefile or the 150806b9b3e0SSimon J. Gerraty * files given by the -f option. Exit on parse errors. 150906b9b3e0SSimon J. Gerraty */ 1510e2eeea75SSimon J. Gerraty static void 1511e2eeea75SSimon J. Gerraty main_ReadFiles(void) 1512e2eeea75SSimon J. Gerraty { 1513e2eeea75SSimon J. Gerraty 15144fde40d9SSimon J. Gerraty if (Lst_IsEmpty(&sysIncPath->dirs)) 15154fde40d9SSimon J. Gerraty SearchPath_AddAll(sysIncPath, defSysIncPath); 15164fde40d9SSimon J. Gerraty 15174fde40d9SSimon J. Gerraty Dir_SetSYSPATH(); 1518956e45f6SSimon J. Gerraty if (!opts.noBuiltins) 1519956e45f6SSimon J. Gerraty ReadBuiltinRules(); 15203955d011SMarcel Moolenaar 15212f2a5ecdSSimon J. Gerraty posix_state = PS_MAYBE_NEXT_LINE; 152206b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&opts.makefiles)) 152306b9b3e0SSimon J. Gerraty ReadAllMakefiles(&opts.makefiles); 1524e2eeea75SSimon J. Gerraty else 1525e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(); 1526e2eeea75SSimon J. Gerraty } 1527e2eeea75SSimon J. Gerraty 1528e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */ 1529e2eeea75SSimon J. Gerraty static void 1530e2eeea75SSimon J. Gerraty main_PrepareMaking(void) 1531e2eeea75SSimon J. Gerraty { 15323955d011SMarcel Moolenaar /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1533e2eeea75SSimon J. Gerraty if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 15348c973ee2SSimon J. Gerraty makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}", 15358c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 1536956e45f6SSimon J. Gerraty if (makeDependfile[0] != '\0') { 1537956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1538b0c40a00SSimon J. Gerraty doing_depend = true; 15392c3632d1SSimon J. Gerraty (void)ReadMakefile(makeDependfile); 1540b0c40a00SSimon J. Gerraty doing_depend = false; 15413955d011SMarcel Moolenaar } 1542956e45f6SSimon J. Gerraty } 15433955d011SMarcel Moolenaar 15444c620fe5SSimon J. Gerraty if (enterFlagObj) 15454c620fe5SSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, objdir); 15464c620fe5SSimon J. Gerraty 154706b9b3e0SSimon J. Gerraty MakeMode(); 15483955d011SMarcel Moolenaar 1549956e45f6SSimon J. Gerraty { 1550dba7b0efSSimon J. Gerraty FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS); 1551dba7b0efSSimon J. Gerraty Global_Append("MFLAGS", makeflags.str); 155206b9b3e0SSimon J. Gerraty FStr_Done(&makeflags); 1553956e45f6SSimon J. Gerraty } 1554e48f47ddSSimon J. Gerraty 1555956e45f6SSimon J. Gerraty InitMaxJobs(); 1556e48f47ddSSimon J. Gerraty 1557e2eeea75SSimon J. Gerraty if (!opts.compatMake && !forceJobs) 1558b0c40a00SSimon J. Gerraty opts.compatMake = true; 1559e48f47ddSSimon J. Gerraty 1560956e45f6SSimon J. Gerraty if (!opts.compatMake) 15613955d011SMarcel Moolenaar Job_ServerStart(maxJobTokens, jp_0, jp_1); 1562956e45f6SSimon J. Gerraty DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1563956e45f6SSimon J. Gerraty jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 15643955d011SMarcel Moolenaar 1565e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_NONE) 1566b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(true); /* initial export */ 15673955d011SMarcel Moolenaar 1568956e45f6SSimon J. Gerraty InitVpath(); 15693955d011SMarcel Moolenaar 15703955d011SMarcel Moolenaar /* 15713955d011SMarcel Moolenaar * Now that all search paths have been read for suffixes et al, it's 15723955d011SMarcel Moolenaar * time to add the default search path to their lists... 15733955d011SMarcel Moolenaar */ 1574b0c40a00SSimon J. Gerraty Suff_ExtendPaths(); 15753955d011SMarcel Moolenaar 15763955d011SMarcel Moolenaar /* 15773955d011SMarcel Moolenaar * Propagate attributes through :: dependency lists. 15783955d011SMarcel Moolenaar */ 15793955d011SMarcel Moolenaar Targ_Propagate(); 15803955d011SMarcel Moolenaar 15813955d011SMarcel Moolenaar /* print the initial graph, if the user requested it */ 15823955d011SMarcel Moolenaar if (DEBUG(GRAPH1)) 15833955d011SMarcel Moolenaar Targ_PrintGraph(1); 15843955d011SMarcel Moolenaar } 15853955d011SMarcel Moolenaar 158606b9b3e0SSimon J. Gerraty /* 158706b9b3e0SSimon J. Gerraty * Make the targets. 1588e2eeea75SSimon J. Gerraty * If the -v or -V options are given, print variables instead. 158906b9b3e0SSimon J. Gerraty * Return whether any of the targets is out-of-date. 159006b9b3e0SSimon J. Gerraty */ 1591b0c40a00SSimon J. Gerraty static bool 1592e2eeea75SSimon J. Gerraty main_Run(void) 1593e2eeea75SSimon J. Gerraty { 1594e2eeea75SSimon J. Gerraty if (opts.printVars != PVM_NONE) { 1595e2eeea75SSimon J. Gerraty /* print the values of any variables requested by the user */ 1596e2eeea75SSimon J. Gerraty doPrintVars(); 1597b0c40a00SSimon J. Gerraty return false; 1598e2eeea75SSimon J. Gerraty } else { 1599e2eeea75SSimon J. Gerraty return runTargets(); 1600e2eeea75SSimon J. Gerraty } 1601e2eeea75SSimon J. Gerraty } 16023955d011SMarcel Moolenaar 1603e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */ 1604e2eeea75SSimon J. Gerraty static void 1605e2eeea75SSimon J. Gerraty main_CleanUp(void) 1606e2eeea75SSimon J. Gerraty { 1607e2eeea75SSimon J. Gerraty #ifdef CLEANUP 160806b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.variables, free); 16099f45a3c8SSimon J. Gerraty Lst_DoneCall(&opts.makefiles, free); 161006b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.create, free); 1611e2eeea75SSimon J. Gerraty #endif 1612e2eeea75SSimon J. Gerraty 1613e2eeea75SSimon J. Gerraty if (DEBUG(GRAPH2)) 1614e2eeea75SSimon J. Gerraty Targ_PrintGraph(2); 1615e2eeea75SSimon J. Gerraty 1616e2eeea75SSimon J. Gerraty Trace_Log(MAKEEND, NULL); 1617e2eeea75SSimon J. Gerraty 1618e2eeea75SSimon J. Gerraty if (enterFlagObj) 1619e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, objdir); 1620e2eeea75SSimon J. Gerraty if (opts.enterFlag) 1621e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, curdir); 1622e2eeea75SSimon J. Gerraty 1623e2eeea75SSimon J. Gerraty #ifdef USE_META 1624e2eeea75SSimon J. Gerraty meta_finish(); 1625e2eeea75SSimon J. Gerraty #endif 1626e2eeea75SSimon J. Gerraty Suff_End(); 1627e2eeea75SSimon J. Gerraty Targ_End(); 1628e2eeea75SSimon J. Gerraty Arch_End(); 1629e2eeea75SSimon J. Gerraty Var_End(); 1630e2eeea75SSimon J. Gerraty Parse_End(); 1631e2eeea75SSimon J. Gerraty Dir_End(); 1632e2eeea75SSimon J. Gerraty Job_End(); 1633e2eeea75SSimon J. Gerraty Trace_End(); 16349f45a3c8SSimon J. Gerraty Str_Intern_End(); 1635e2eeea75SSimon J. Gerraty } 1636e2eeea75SSimon J. Gerraty 1637e2eeea75SSimon J. Gerraty /* Determine the exit code. */ 1638e2eeea75SSimon J. Gerraty static int 1639b0c40a00SSimon J. Gerraty main_Exit(bool outOfDate) 1640e2eeea75SSimon J. Gerraty { 164112904384SSimon J. Gerraty if (opts.strict && (main_errors > 0 || Parse_NumErrors() > 0)) 1642956e45f6SSimon J. Gerraty return 2; /* Not 1 so -q can distinguish error */ 16433955d011SMarcel Moolenaar return outOfDate ? 1 : 0; 16443955d011SMarcel Moolenaar } 16453955d011SMarcel Moolenaar 1646e2eeea75SSimon J. Gerraty int 1647e2eeea75SSimon J. Gerraty main(int argc, char **argv) 1648e2eeea75SSimon J. Gerraty { 1649b0c40a00SSimon J. Gerraty bool outOfDate; 1650e2eeea75SSimon J. Gerraty 1651e2eeea75SSimon J. Gerraty main_Init(argc, argv); 1652e2eeea75SSimon J. Gerraty main_ReadFiles(); 1653e2eeea75SSimon J. Gerraty main_PrepareMaking(); 1654e2eeea75SSimon J. Gerraty outOfDate = main_Run(); 1655e2eeea75SSimon J. Gerraty main_CleanUp(); 1656e2eeea75SSimon J. Gerraty return main_Exit(outOfDate); 1657e2eeea75SSimon J. Gerraty } 1658e2eeea75SSimon J. Gerraty 165906b9b3e0SSimon J. Gerraty /* 166006b9b3e0SSimon J. Gerraty * Open and parse the given makefile, with all its side effects. 16619f45a3c8SSimon J. Gerraty * Return false if the file could not be opened. 16623955d011SMarcel Moolenaar */ 16639f45a3c8SSimon J. Gerraty static bool 16642c3632d1SSimon J. Gerraty ReadMakefile(const char *fname) 16653955d011SMarcel Moolenaar { 16663955d011SMarcel Moolenaar int fd; 16672c3632d1SSimon J. Gerraty char *name, *path = NULL; 16683955d011SMarcel Moolenaar 1669e2eeea75SSimon J. Gerraty if (strcmp(fname, "-") == 0) { 16709f45a3c8SSimon J. Gerraty Parse_File("(stdin)", -1); 1671dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", ""); 16723955d011SMarcel Moolenaar } else { 16733955d011SMarcel Moolenaar /* if we've chdir'd, rebuild the path name */ 1674e2eeea75SSimon J. Gerraty if (strcmp(curdir, objdir) != 0 && *fname != '/') { 16752c3632d1SSimon J. Gerraty path = str_concat3(curdir, "/", fname); 16763955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 16773955d011SMarcel Moolenaar if (fd != -1) { 16783955d011SMarcel Moolenaar fname = path; 16793955d011SMarcel Moolenaar goto found; 16803955d011SMarcel Moolenaar } 16812c3632d1SSimon J. Gerraty free(path); 16823955d011SMarcel Moolenaar 16833955d011SMarcel Moolenaar /* If curdir failed, try objdir (ala .depend) */ 16842c3632d1SSimon J. Gerraty path = str_concat3(objdir, "/", fname); 16853955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 16863955d011SMarcel Moolenaar if (fd != -1) { 16873955d011SMarcel Moolenaar fname = path; 16883955d011SMarcel Moolenaar goto found; 16893955d011SMarcel Moolenaar } 16903955d011SMarcel Moolenaar } else { 16913955d011SMarcel Moolenaar fd = open(fname, O_RDONLY); 16923955d011SMarcel Moolenaar if (fd != -1) 16933955d011SMarcel Moolenaar goto found; 16943955d011SMarcel Moolenaar } 16953955d011SMarcel Moolenaar /* look in -I and system include directories. */ 16963955d011SMarcel Moolenaar name = Dir_FindFile(fname, parseIncPath); 1697e2eeea75SSimon J. Gerraty if (name == NULL) { 1698dba7b0efSSimon J. Gerraty SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs) 1699956e45f6SSimon J. Gerraty ? defSysIncPath : sysIncPath; 1700956e45f6SSimon J. Gerraty name = Dir_FindFile(fname, sysInc); 1701956e45f6SSimon J. Gerraty } 1702e2eeea75SSimon J. Gerraty if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 17033955d011SMarcel Moolenaar free(name); 17043955d011SMarcel Moolenaar free(path); 17059f45a3c8SSimon J. Gerraty return false; 17063955d011SMarcel Moolenaar } 17073955d011SMarcel Moolenaar fname = name; 17083955d011SMarcel Moolenaar /* 17093955d011SMarcel Moolenaar * set the MAKEFILE variable desired by System V fans -- the 17103955d011SMarcel Moolenaar * placement of the setting here means it gets set to the last 17113955d011SMarcel Moolenaar * makefile specified, as it is set by SysV make. 17123955d011SMarcel Moolenaar */ 17133955d011SMarcel Moolenaar found: 17143955d011SMarcel Moolenaar if (!doing_depend) 1715dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname); 17163955d011SMarcel Moolenaar Parse_File(fname, fd); 17173955d011SMarcel Moolenaar } 17183955d011SMarcel Moolenaar free(path); 17199f45a3c8SSimon J. Gerraty return true; 17203955d011SMarcel Moolenaar } 17213955d011SMarcel Moolenaar 1722dba7b0efSSimon J. Gerraty /* 17239f45a3c8SSimon J. Gerraty * Execute the command in cmd, and return its output (only stdout, not 17249f45a3c8SSimon J. Gerraty * stderr, possibly empty). In the output, replace newlines with spaces. 17253955d011SMarcel Moolenaar */ 17263955d011SMarcel Moolenaar char * 17279f45a3c8SSimon J. Gerraty Cmd_Exec(const char *cmd, char **error) 17283955d011SMarcel Moolenaar { 17299f45a3c8SSimon J. Gerraty const char *args[4]; /* Arguments for invoking the shell */ 173006b9b3e0SSimon J. Gerraty int pipefds[2]; 17313955d011SMarcel Moolenaar int cpid; /* Child PID */ 17323955d011SMarcel Moolenaar int pid; /* PID from wait() */ 1733e2eeea75SSimon J. Gerraty int status; /* command exit status */ 17343955d011SMarcel Moolenaar Buffer buf; /* buffer to store the result */ 17352c3632d1SSimon J. Gerraty ssize_t bytes_read; 17369f45a3c8SSimon J. Gerraty char *output; 1737*d5e0a182SSimon J. Gerraty char *p; 17389f45a3c8SSimon J. Gerraty int saved_errno; 1739*d5e0a182SSimon J. Gerraty char cmd_file[MAXPATHLEN]; 1740*d5e0a182SSimon J. Gerraty size_t cmd_len; 1741*d5e0a182SSimon J. Gerraty int cmd_fd = -1; 17423955d011SMarcel Moolenaar 1743*d5e0a182SSimon J. Gerraty if (shellPath == NULL) 17443955d011SMarcel Moolenaar Shell_Init(); 17459f45a3c8SSimon J. Gerraty 1746*d5e0a182SSimon J. Gerraty cmd_len = strlen(cmd); 1747*d5e0a182SSimon J. Gerraty if (cmd_len > 1000) { 1748*d5e0a182SSimon J. Gerraty cmd_fd = mkTempFile(NULL, cmd_file, sizeof(cmd_file)); 1749*d5e0a182SSimon J. Gerraty if (cmd_fd >= 0) { 1750*d5e0a182SSimon J. Gerraty ssize_t n; 1751*d5e0a182SSimon J. Gerraty 1752*d5e0a182SSimon J. Gerraty n = write(cmd_fd, cmd, cmd_len); 1753*d5e0a182SSimon J. Gerraty close(cmd_fd); 1754*d5e0a182SSimon J. Gerraty if (n < (ssize_t)cmd_len) { 1755*d5e0a182SSimon J. Gerraty unlink(cmd_file); 1756*d5e0a182SSimon J. Gerraty cmd_fd = -1; 1757*d5e0a182SSimon J. Gerraty } 1758*d5e0a182SSimon J. Gerraty } 1759*d5e0a182SSimon J. Gerraty } 1760*d5e0a182SSimon J. Gerraty 17613955d011SMarcel Moolenaar args[0] = shellName; 1762*d5e0a182SSimon J. Gerraty if (cmd_fd >= 0) { 1763*d5e0a182SSimon J. Gerraty args[1] = cmd_file; 1764*d5e0a182SSimon J. Gerraty args[2] = NULL; 1765*d5e0a182SSimon J. Gerraty } else { 1766*d5e0a182SSimon J. Gerraty cmd_file[0] = '\0'; 17673955d011SMarcel Moolenaar args[1] = "-c"; 17683955d011SMarcel Moolenaar args[2] = cmd; 17693955d011SMarcel Moolenaar args[3] = NULL; 1770*d5e0a182SSimon J. Gerraty } 17719f45a3c8SSimon J. Gerraty DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd); 17723955d011SMarcel Moolenaar 177306b9b3e0SSimon J. Gerraty if (pipe(pipefds) == -1) { 17749f45a3c8SSimon J. Gerraty *error = str_concat3( 17759f45a3c8SSimon J. Gerraty "Couldn't create pipe for \"", cmd, "\""); 17769f45a3c8SSimon J. Gerraty return bmake_strdup(""); 17773955d011SMarcel Moolenaar } 17783955d011SMarcel Moolenaar 177906b9b3e0SSimon J. Gerraty Var_ReexportVars(); 178006b9b3e0SSimon J. Gerraty 1781dba7b0efSSimon J. Gerraty switch (cpid = vfork()) { 17823955d011SMarcel Moolenaar case 0: 17839f45a3c8SSimon J. Gerraty (void)close(pipefds[0]); 17849f45a3c8SSimon J. Gerraty (void)dup2(pipefds[1], STDOUT_FILENO); 178506b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); 17863955d011SMarcel Moolenaar 17873955d011SMarcel Moolenaar (void)execv(shellPath, UNCONST(args)); 17883955d011SMarcel Moolenaar _exit(1); 17893955d011SMarcel Moolenaar /* NOTREACHED */ 17903955d011SMarcel Moolenaar 17913955d011SMarcel Moolenaar case -1: 17929f45a3c8SSimon J. Gerraty *error = str_concat3("Couldn't exec \"", cmd, "\""); 17939f45a3c8SSimon J. Gerraty return bmake_strdup(""); 17949f45a3c8SSimon J. Gerraty } 17953955d011SMarcel Moolenaar 179606b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); /* No need for the writing half */ 17973955d011SMarcel Moolenaar 17989f45a3c8SSimon J. Gerraty saved_errno = 0; 1799e2eeea75SSimon J. Gerraty Buf_Init(&buf); 18003955d011SMarcel Moolenaar 18013955d011SMarcel Moolenaar do { 18023955d011SMarcel Moolenaar char result[BUFSIZ]; 180306b9b3e0SSimon J. Gerraty bytes_read = read(pipefds[0], result, sizeof result); 18042c3632d1SSimon J. Gerraty if (bytes_read > 0) 18052c3632d1SSimon J. Gerraty Buf_AddBytes(&buf, result, (size_t)bytes_read); 18069f45a3c8SSimon J. Gerraty } while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); 18072c3632d1SSimon J. Gerraty if (bytes_read == -1) 18089f45a3c8SSimon J. Gerraty saved_errno = errno; 18093955d011SMarcel Moolenaar 181006b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close the input side of the pipe. */ 18113955d011SMarcel Moolenaar 1812e2eeea75SSimon J. Gerraty while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 1813b0c40a00SSimon J. Gerraty JobReapChild(pid, status, false); 1814e2eeea75SSimon J. Gerraty 18159f45a3c8SSimon J. Gerraty if (Buf_EndsWith(&buf, '\n')) 18169f45a3c8SSimon J. Gerraty buf.data[buf.len - 1] = '\0'; 18173955d011SMarcel Moolenaar 18189f45a3c8SSimon J. Gerraty output = Buf_DoneData(&buf); 1819*d5e0a182SSimon J. Gerraty for (p = output; *p != '\0'; p++) 1820*d5e0a182SSimon J. Gerraty if (*p == '\n') 1821*d5e0a182SSimon J. Gerraty *p = ' '; 18229f45a3c8SSimon J. Gerraty 18239f45a3c8SSimon J. Gerraty if (WIFSIGNALED(status)) 18249f45a3c8SSimon J. Gerraty *error = str_concat3("\"", cmd, "\" exited on a signal"); 18259f45a3c8SSimon J. Gerraty else if (WEXITSTATUS(status) != 0) 18269f45a3c8SSimon J. Gerraty *error = str_concat3( 18279f45a3c8SSimon J. Gerraty "\"", cmd, "\" returned non-zero status"); 18289f45a3c8SSimon J. Gerraty else if (saved_errno != 0) 18299f45a3c8SSimon J. Gerraty *error = str_concat3( 18309f45a3c8SSimon J. Gerraty "Couldn't read shell's output for \"", cmd, "\""); 18319f45a3c8SSimon J. Gerraty else 18329f45a3c8SSimon J. Gerraty *error = NULL; 1833*d5e0a182SSimon J. Gerraty if (cmd_file[0] != '\0') 1834*d5e0a182SSimon J. Gerraty unlink(cmd_file); 18359f45a3c8SSimon J. Gerraty return output; 18363955d011SMarcel Moolenaar } 18373955d011SMarcel Moolenaar 183806b9b3e0SSimon J. Gerraty /* 183906b9b3e0SSimon J. Gerraty * Print a printf-style error message. 18403955d011SMarcel Moolenaar * 18419f45a3c8SSimon J. Gerraty * In default mode, this error message has no consequences, for compatibility 18429f45a3c8SSimon J. Gerraty * reasons, in particular it does not affect the exit status. Only in lint 18439f45a3c8SSimon J. Gerraty * mode (-dL) it does. 184406b9b3e0SSimon J. Gerraty */ 18453955d011SMarcel Moolenaar void 18463955d011SMarcel Moolenaar Error(const char *fmt, ...) 18473955d011SMarcel Moolenaar { 18483955d011SMarcel Moolenaar va_list ap; 18499f45a3c8SSimon J. Gerraty FILE *f; 18503955d011SMarcel Moolenaar 18519f45a3c8SSimon J. Gerraty f = opts.debug_file; 18529f45a3c8SSimon J. Gerraty if (f == stdout) 18539f45a3c8SSimon J. Gerraty f = stderr; 18543955d011SMarcel Moolenaar (void)fflush(stdout); 18559f45a3c8SSimon J. Gerraty 18563955d011SMarcel Moolenaar for (;;) { 18579f45a3c8SSimon J. Gerraty fprintf(f, "%s: ", progname); 18583955d011SMarcel Moolenaar va_start(ap, fmt); 18599f45a3c8SSimon J. Gerraty (void)vfprintf(f, fmt, ap); 18603955d011SMarcel Moolenaar va_end(ap); 18619f45a3c8SSimon J. Gerraty (void)fprintf(f, "\n"); 18629f45a3c8SSimon J. Gerraty (void)fflush(f); 18639f45a3c8SSimon J. Gerraty if (f == stderr) 18643955d011SMarcel Moolenaar break; 18659f45a3c8SSimon J. Gerraty f = stderr; 18663955d011SMarcel Moolenaar } 186706b9b3e0SSimon J. Gerraty main_errors++; 18683955d011SMarcel Moolenaar } 18693955d011SMarcel Moolenaar 187006b9b3e0SSimon J. Gerraty /* 187106b9b3e0SSimon J. Gerraty * Wait for any running jobs to finish, then produce an error message, 1872e2eeea75SSimon J. Gerraty * finally exit immediately. 18733955d011SMarcel Moolenaar * 1874e2eeea75SSimon J. Gerraty * Exiting immediately differs from Parse_Error, which exits only after the 187506b9b3e0SSimon J. Gerraty * current top-level makefile has been parsed completely. 187606b9b3e0SSimon J. Gerraty */ 18773955d011SMarcel Moolenaar void 18783955d011SMarcel Moolenaar Fatal(const char *fmt, ...) 18793955d011SMarcel Moolenaar { 18803955d011SMarcel Moolenaar va_list ap; 18813955d011SMarcel Moolenaar 18823955d011SMarcel Moolenaar if (jobsRunning) 18833955d011SMarcel Moolenaar Job_Wait(); 18843955d011SMarcel Moolenaar 18853955d011SMarcel Moolenaar (void)fflush(stdout); 1886*d5e0a182SSimon J. Gerraty fprintf(stderr, "%s: ", progname); 1887e2eeea75SSimon J. Gerraty va_start(ap, fmt); 18883955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 18893955d011SMarcel Moolenaar va_end(ap); 18903955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 18913955d011SMarcel Moolenaar (void)fflush(stderr); 18929f45a3c8SSimon J. Gerraty PrintStackTrace(true); 18933955d011SMarcel Moolenaar 18949f45a3c8SSimon J. Gerraty PrintOnError(NULL, "\n"); 18953955d011SMarcel Moolenaar 18963955d011SMarcel Moolenaar if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 18973955d011SMarcel Moolenaar Targ_PrintGraph(2); 1898e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 18993955d011SMarcel Moolenaar exit(2); /* Not 1 so -q can distinguish error */ 19003955d011SMarcel Moolenaar } 19013955d011SMarcel Moolenaar 190206b9b3e0SSimon J. Gerraty /* 190306b9b3e0SSimon J. Gerraty * Major exception once jobs are being created. 190406b9b3e0SSimon J. Gerraty * Kills all jobs, prints a message and exits. 190506b9b3e0SSimon J. Gerraty */ 19063955d011SMarcel Moolenaar void 19073955d011SMarcel Moolenaar Punt(const char *fmt, ...) 19083955d011SMarcel Moolenaar { 19093955d011SMarcel Moolenaar va_list ap; 19103955d011SMarcel Moolenaar 19113955d011SMarcel Moolenaar (void)fflush(stdout); 19123955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: ", progname); 19139f45a3c8SSimon J. Gerraty va_start(ap, fmt); 19143955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 19153955d011SMarcel Moolenaar va_end(ap); 19163955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 19173955d011SMarcel Moolenaar (void)fflush(stderr); 19183955d011SMarcel Moolenaar 19199f45a3c8SSimon J. Gerraty PrintOnError(NULL, "\n"); 19203955d011SMarcel Moolenaar 19213955d011SMarcel Moolenaar DieHorribly(); 19223955d011SMarcel Moolenaar } 19233955d011SMarcel Moolenaar 1924956e45f6SSimon J. Gerraty /* Exit without giving a message. */ 19253955d011SMarcel Moolenaar void 19263955d011SMarcel Moolenaar DieHorribly(void) 19273955d011SMarcel Moolenaar { 19283955d011SMarcel Moolenaar if (jobsRunning) 19293955d011SMarcel Moolenaar Job_AbortAll(); 19303955d011SMarcel Moolenaar if (DEBUG(GRAPH2)) 19313955d011SMarcel Moolenaar Targ_PrintGraph(2); 1932e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 193306b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 19343955d011SMarcel Moolenaar } 19353955d011SMarcel Moolenaar 193606b9b3e0SSimon J. Gerraty /* 193706b9b3e0SSimon J. Gerraty * Called when aborting due to errors in child shell to signal abnormal exit. 1938956e45f6SSimon J. Gerraty * The program exits. 193906b9b3e0SSimon J. Gerraty * Errors is the number of errors encountered in Make_Make. 194006b9b3e0SSimon J. Gerraty */ 19413955d011SMarcel Moolenaar void 1942956e45f6SSimon J. Gerraty Finish(int errs) 19433955d011SMarcel Moolenaar { 1944e2eeea75SSimon J. Gerraty if (shouldDieQuietly(NULL, -1)) 19453841c287SSimon J. Gerraty exit(2); 1946956e45f6SSimon J. Gerraty Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 19473955d011SMarcel Moolenaar } 19483955d011SMarcel Moolenaar 19494fde40d9SSimon J. Gerraty int 19509f45a3c8SSimon J. Gerraty unlink_file(const char *file) 19513955d011SMarcel Moolenaar { 19523955d011SMarcel Moolenaar struct stat st; 19533955d011SMarcel Moolenaar 19543955d011SMarcel Moolenaar if (lstat(file, &st) == -1) 19554fde40d9SSimon J. Gerraty return -1; 19563955d011SMarcel Moolenaar 19573955d011SMarcel Moolenaar if (S_ISDIR(st.st_mode)) { 19584fde40d9SSimon J. Gerraty /* 19594fde40d9SSimon J. Gerraty * POSIX says for unlink: "The path argument shall not name 19604fde40d9SSimon J. Gerraty * a directory unless [...]". 19614fde40d9SSimon J. Gerraty */ 19623955d011SMarcel Moolenaar errno = EISDIR; 19634fde40d9SSimon J. Gerraty return -1; 19643955d011SMarcel Moolenaar } 19654fde40d9SSimon J. Gerraty return unlink(file); 19663955d011SMarcel Moolenaar } 19673955d011SMarcel Moolenaar 1968956e45f6SSimon J. Gerraty static void 1969956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n) 1970956e45f6SSimon J. Gerraty { 1971956e45f6SSimon J. Gerraty const char *mem = data; 1972956e45f6SSimon J. Gerraty 1973956e45f6SSimon J. Gerraty while (n > 0) { 1974956e45f6SSimon J. Gerraty ssize_t written = write(fd, mem, n); 19759f45a3c8SSimon J. Gerraty /* XXX: Should this EAGAIN be EINTR? */ 1976956e45f6SSimon J. Gerraty if (written == -1 && errno == EAGAIN) 1977956e45f6SSimon J. Gerraty continue; 1978956e45f6SSimon J. Gerraty if (written == -1) 1979956e45f6SSimon J. Gerraty break; 1980956e45f6SSimon J. Gerraty mem += written; 1981956e45f6SSimon J. Gerraty n -= (size_t)written; 1982956e45f6SSimon J. Gerraty } 1983956e45f6SSimon J. Gerraty } 1984956e45f6SSimon J. Gerraty 19859f45a3c8SSimon J. Gerraty /* Print why exec failed, avoiding stdio. */ 1986956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD 1987956e45f6SSimon J. Gerraty execDie(const char *af, const char *av) 19883955d011SMarcel Moolenaar { 1989956e45f6SSimon J. Gerraty Buffer buf; 19903955d011SMarcel Moolenaar 1991e2eeea75SSimon J. Gerraty Buf_Init(&buf); 1992956e45f6SSimon J. Gerraty Buf_AddStr(&buf, progname); 1993956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ": "); 1994956e45f6SSimon J. Gerraty Buf_AddStr(&buf, af); 1995956e45f6SSimon J. Gerraty Buf_AddStr(&buf, "("); 1996956e45f6SSimon J. Gerraty Buf_AddStr(&buf, av); 1997956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ") failed ("); 1998956e45f6SSimon J. Gerraty Buf_AddStr(&buf, strerror(errno)); 1999956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ")\n"); 20003955d011SMarcel Moolenaar 2001dba7b0efSSimon J. Gerraty write_all(STDERR_FILENO, buf.data, buf.len); 2002956e45f6SSimon J. Gerraty 2003dba7b0efSSimon J. Gerraty Buf_Done(&buf); 2004956e45f6SSimon J. Gerraty _exit(1); 20053955d011SMarcel Moolenaar } 20063955d011SMarcel Moolenaar 2007e1cee40dSSimon J. Gerraty static void 2008e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void) 2009e1cee40dSSimon J. Gerraty { 2010*d5e0a182SSimon J. Gerraty HashEntry *he, *next; 2011956e45f6SSimon J. Gerraty HashIter hi; 2012b778b302SSimon J. Gerraty 2013e2eeea75SSimon J. Gerraty HashIter_Init(&hi, &cached_realpaths); 2014956e45f6SSimon J. Gerraty he = HashIter_Next(&hi); 2015956e45f6SSimon J. Gerraty while (he != NULL) { 2016*d5e0a182SSimon J. Gerraty next = HashIter_Next(&hi); 2017956e45f6SSimon J. Gerraty if (he->key[0] != '/') { 2018e2eeea75SSimon J. Gerraty DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 2019e2eeea75SSimon J. Gerraty HashTable_DeleteEntry(&cached_realpaths, he); 20209f45a3c8SSimon J. Gerraty /* 20219f45a3c8SSimon J. Gerraty * XXX: What about the allocated he->value? Either 20229f45a3c8SSimon J. Gerraty * free them or document why they cannot be freed. 20239f45a3c8SSimon J. Gerraty */ 2024b46b9039SSimon J. Gerraty } 2025*d5e0a182SSimon J. Gerraty he = next; 2026b46b9039SSimon J. Gerraty } 2027b46b9039SSimon J. Gerraty } 2028e1cee40dSSimon J. Gerraty 20299f45a3c8SSimon J. Gerraty const char * 2030e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved) 2031e1cee40dSSimon J. Gerraty { 20322c3632d1SSimon J. Gerraty const char *rp; 2033e1cee40dSSimon J. Gerraty 2034e2eeea75SSimon J. Gerraty if (pathname == NULL || pathname[0] == '\0') 2035e1cee40dSSimon J. Gerraty return NULL; 2036e1cee40dSSimon J. Gerraty 2037e2eeea75SSimon J. Gerraty rp = HashTable_FindValue(&cached_realpaths, pathname); 2038e2eeea75SSimon J. Gerraty if (rp != NULL) { 2039b778b302SSimon J. Gerraty /* a hit */ 2040e2eeea75SSimon J. Gerraty strncpy(resolved, rp, MAXPATHLEN); 2041e2eeea75SSimon J. Gerraty resolved[MAXPATHLEN - 1] = '\0'; 2042e2eeea75SSimon J. Gerraty return resolved; 2043e2eeea75SSimon J. Gerraty } 20443841c287SSimon J. Gerraty 2045e2eeea75SSimon J. Gerraty rp = realpath(pathname, resolved); 2046e2eeea75SSimon J. Gerraty if (rp != NULL) { 2047e2eeea75SSimon J. Gerraty HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2048e2eeea75SSimon J. Gerraty DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2049e2eeea75SSimon J. Gerraty return resolved; 2050e2eeea75SSimon J. Gerraty } 2051e2eeea75SSimon J. Gerraty 2052e2eeea75SSimon J. Gerraty /* should we negative-cache? */ 2053e2eeea75SSimon J. Gerraty return NULL; 2054b778b302SSimon J. Gerraty } 2055b778b302SSimon J. Gerraty 20563841c287SSimon J. Gerraty /* 20573841c287SSimon J. Gerraty * Return true if we should die without noise. 2058e2eeea75SSimon J. Gerraty * For example our failing child was a sub-make or failure happened elsewhere. 20593841c287SSimon J. Gerraty */ 2060b0c40a00SSimon J. Gerraty bool 2061e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf) 20623841c287SSimon J. Gerraty { 20633841c287SSimon J. Gerraty static int quietly = -1; 20643841c287SSimon J. Gerraty 20653841c287SSimon J. Gerraty if (quietly < 0) { 2066b0c40a00SSimon J. Gerraty if (DEBUG(JOB) || 2067b0c40a00SSimon J. Gerraty !GetBooleanExpr("${.MAKE.DIE_QUIETLY}", true)) 20683841c287SSimon J. Gerraty quietly = 0; 20693841c287SSimon J. Gerraty else if (bf >= 0) 20703841c287SSimon J. Gerraty quietly = bf; 20713841c287SSimon J. Gerraty else 207206b9b3e0SSimon J. Gerraty quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0; 20733841c287SSimon J. Gerraty } 2074dba7b0efSSimon J. Gerraty return quietly != 0; 20753841c287SSimon J. Gerraty } 20763841c287SSimon J. Gerraty 2077956e45f6SSimon J. Gerraty static void 2078956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn) 2079956e45f6SSimon J. Gerraty { 2080956e45f6SSimon J. Gerraty StringListNode *ln; 2081956e45f6SSimon J. Gerraty 2082956e45f6SSimon J. Gerraty /* 2083956e45f6SSimon J. Gerraty * We can print this even if there is no .ERROR target. 2084956e45f6SSimon J. Gerraty */ 2085dba7b0efSSimon J. Gerraty Global_Set(".ERROR_TARGET", gn->name); 2086dba7b0efSSimon J. Gerraty Global_Delete(".ERROR_CMD"); 2087956e45f6SSimon J. Gerraty 208806b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) { 2089956e45f6SSimon J. Gerraty const char *cmd = ln->datum; 2090956e45f6SSimon J. Gerraty 2091956e45f6SSimon J. Gerraty if (cmd == NULL) 2092956e45f6SSimon J. Gerraty break; 2093dba7b0efSSimon J. Gerraty Global_Append(".ERROR_CMD", cmd); 2094956e45f6SSimon J. Gerraty } 2095956e45f6SSimon J. Gerraty } 2096956e45f6SSimon J. Gerraty 209706b9b3e0SSimon J. Gerraty /* 209806b9b3e0SSimon J. Gerraty * Print some helpful information in case of an error. 209906b9b3e0SSimon J. Gerraty * The caller should exit soon after calling this function. 210006b9b3e0SSimon J. Gerraty */ 21013955d011SMarcel Moolenaar void 2102e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg) 21033955d011SMarcel Moolenaar { 2104e2eeea75SSimon J. Gerraty static GNode *errorNode = NULL; 21053955d011SMarcel Moolenaar 21062c3632d1SSimon J. Gerraty if (DEBUG(HASH)) { 21072c3632d1SSimon J. Gerraty Targ_Stats(); 21082c3632d1SSimon J. Gerraty Var_Stats(); 21092c3632d1SSimon J. Gerraty } 21102c3632d1SSimon J. Gerraty 211106b9b3e0SSimon J. Gerraty if (errorNode != NULL) 211206b9b3e0SSimon J. Gerraty return; /* we've been here! */ 21133841c287SSimon J. Gerraty 21149f45a3c8SSimon J. Gerraty printf("%s%s: stopped in %s\n", msg, progname, curdir); 21153955d011SMarcel Moolenaar 211606b9b3e0SSimon J. Gerraty /* we generally want to keep quiet if a sub-make died */ 211706b9b3e0SSimon J. Gerraty if (shouldDieQuietly(gn, -1)) 211806b9b3e0SSimon J. Gerraty return; 2119e2eeea75SSimon J. Gerraty 2120e2eeea75SSimon J. Gerraty if (gn != NULL) 2121956e45f6SSimon J. Gerraty SetErrorVars(gn); 2122e2eeea75SSimon J. Gerraty 2123e2eeea75SSimon J. Gerraty { 21248c973ee2SSimon J. Gerraty char *errorVarsValues = Var_Subst( 21258c973ee2SSimon J. Gerraty "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 21268c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 2127956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2128e2eeea75SSimon J. Gerraty printf("%s", errorVarsValues); 2129e2eeea75SSimon J. Gerraty free(errorVarsValues); 2130e2eeea75SSimon J. Gerraty } 2131e2eeea75SSimon J. Gerraty 2132ac3446e9SSimon J. Gerraty fflush(stdout); 2133ac3446e9SSimon J. Gerraty 21343955d011SMarcel Moolenaar /* 21353955d011SMarcel Moolenaar * Finally, see if there is a .ERROR target, and run it if so. 21363955d011SMarcel Moolenaar */ 2137e2eeea75SSimon J. Gerraty errorNode = Targ_FindNode(".ERROR"); 2138e2eeea75SSimon J. Gerraty if (errorNode != NULL) { 2139e2eeea75SSimon J. Gerraty errorNode->type |= OP_SPECIAL; 2140e2eeea75SSimon J. Gerraty Compat_Make(errorNode, errorNode); 21413955d011SMarcel Moolenaar } 21423955d011SMarcel Moolenaar } 21433955d011SMarcel Moolenaar 21443955d011SMarcel Moolenaar void 2145b0c40a00SSimon J. Gerraty Main_ExportMAKEFLAGS(bool first) 21463955d011SMarcel Moolenaar { 2147b0c40a00SSimon J. Gerraty static bool once = true; 21489f45a3c8SSimon J. Gerraty char *flags; 21493955d011SMarcel Moolenaar 21503955d011SMarcel Moolenaar if (once != first) 21513955d011SMarcel Moolenaar return; 2152b0c40a00SSimon J. Gerraty once = false; 21533955d011SMarcel Moolenaar 21548c973ee2SSimon J. Gerraty flags = Var_Subst( 21559f45a3c8SSimon J. Gerraty "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 21568c973ee2SSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES); 2157956e45f6SSimon J. Gerraty /* TODO: handle errors */ 21589f45a3c8SSimon J. Gerraty if (flags[0] != '\0') { 21593955d011SMarcel Moolenaar #ifdef POSIX 21609f45a3c8SSimon J. Gerraty setenv("MAKEFLAGS", flags, 1); 21613955d011SMarcel Moolenaar #else 21629f45a3c8SSimon J. Gerraty setenv("MAKE", flags, 1); 21633955d011SMarcel Moolenaar #endif 21643955d011SMarcel Moolenaar } 21653955d011SMarcel Moolenaar } 21663955d011SMarcel Moolenaar 21673955d011SMarcel Moolenaar char * 21683955d011SMarcel Moolenaar getTmpdir(void) 21693955d011SMarcel Moolenaar { 21703955d011SMarcel Moolenaar static char *tmpdir = NULL; 21713955d011SMarcel Moolenaar struct stat st; 21723955d011SMarcel Moolenaar 2173e2eeea75SSimon J. Gerraty if (tmpdir != NULL) 2174e2eeea75SSimon J. Gerraty return tmpdir; 2175e2eeea75SSimon J. Gerraty 21769f45a3c8SSimon J. Gerraty /* Honor $TMPDIR if it is valid, strip a trailing '/'. */ 21778c973ee2SSimon J. Gerraty tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/", 21788c973ee2SSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES); 2179956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2180e2eeea75SSimon J. Gerraty 21813955d011SMarcel Moolenaar if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 21823955d011SMarcel Moolenaar free(tmpdir); 21833955d011SMarcel Moolenaar tmpdir = bmake_strdup(_PATH_TMP); 21843955d011SMarcel Moolenaar } 21853955d011SMarcel Moolenaar return tmpdir; 21863955d011SMarcel Moolenaar } 21873955d011SMarcel Moolenaar 21883955d011SMarcel Moolenaar /* 21893955d011SMarcel Moolenaar * Create and open a temp file using "pattern". 2190*d5e0a182SSimon J. Gerraty * If tfile is provided, set it to a copy of the filename created. 21913955d011SMarcel Moolenaar * Otherwise unlink the file once open. 21923955d011SMarcel Moolenaar */ 21933955d011SMarcel Moolenaar int 2194dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz) 21953955d011SMarcel Moolenaar { 21963955d011SMarcel Moolenaar static char *tmpdir = NULL; 2197dba7b0efSSimon J. Gerraty char tbuf[MAXPATHLEN]; 21983955d011SMarcel Moolenaar int fd; 21993955d011SMarcel Moolenaar 2200e2eeea75SSimon J. Gerraty if (pattern == NULL) 22013955d011SMarcel Moolenaar pattern = TMPPAT; 2202956e45f6SSimon J. Gerraty if (tmpdir == NULL) 22033955d011SMarcel Moolenaar tmpdir = getTmpdir(); 2204dba7b0efSSimon J. Gerraty if (tfile == NULL) { 2205dba7b0efSSimon J. Gerraty tfile = tbuf; 2206dba7b0efSSimon J. Gerraty tfile_sz = sizeof tbuf; 2207dba7b0efSSimon J. Gerraty } 22089f45a3c8SSimon J. Gerraty 22099f45a3c8SSimon J. Gerraty if (pattern[0] == '/') 2210dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s", pattern); 22119f45a3c8SSimon J. Gerraty else 2212dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern); 22139f45a3c8SSimon J. Gerraty 22143955d011SMarcel Moolenaar if ((fd = mkstemp(tfile)) < 0) 2215e2eeea75SSimon J. Gerraty Punt("Could not create temporary file %s: %s", tfile, 2216e2eeea75SSimon J. Gerraty strerror(errno)); 22179f45a3c8SSimon J. Gerraty if (tfile == tbuf) 221806b9b3e0SSimon J. Gerraty unlink(tfile); /* we just want the descriptor */ 22199f45a3c8SSimon J. Gerraty 22203955d011SMarcel Moolenaar return fd; 22213955d011SMarcel Moolenaar } 22223955d011SMarcel Moolenaar 2223be19d90bSSimon J. Gerraty /* 2224e2eeea75SSimon J. Gerraty * Convert a string representation of a boolean into a boolean value. 2225b0c40a00SSimon J. Gerraty * Anything that looks like "No", "False", "Off", "0" etc. is false, 2226b0c40a00SSimon J. Gerraty * the empty string is the fallback, everything else is true. 2227be19d90bSSimon J. Gerraty */ 2228b0c40a00SSimon J. Gerraty bool 2229b0c40a00SSimon J. Gerraty ParseBoolean(const char *s, bool fallback) 2230be19d90bSSimon J. Gerraty { 2231e2eeea75SSimon J. Gerraty char ch = ch_tolower(s[0]); 2232e2eeea75SSimon J. Gerraty if (ch == '\0') 2233e2eeea75SSimon J. Gerraty return fallback; 2234e2eeea75SSimon J. Gerraty if (ch == '0' || ch == 'f' || ch == 'n') 2235b0c40a00SSimon J. Gerraty return false; 2236e2eeea75SSimon J. Gerraty if (ch == 'o') 2237e2eeea75SSimon J. Gerraty return ch_tolower(s[1]) != 'f'; 2238b0c40a00SSimon J. Gerraty return true; 2239be19d90bSSimon J. Gerraty } 2240