1*dba7b0efSSimon J. Gerraty /* $NetBSD: main.c,v 1.533 2021/02/05 19:19:17 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 * 76*dba7b0efSSimon J. Gerraty * Main_ParseArgLine 77*dba7b0efSSimon J. Gerraty * Parse and process command line arguments from a 78*dba7b0efSSimon J. Gerraty * single string. Used to implement the special targets 79*dba7b0efSSimon 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 * 87*dba7b0efSSimon J. Gerraty * Finish Finish things up by printing the number of errors 88*dba7b0efSSimon 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*dba7b0efSSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.533 2021/02/05 19:19:17 sjg Exp $"); 115956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && !defined(lint) 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 */ 1283955d011SMarcel Moolenaar Boolean allPrecious; /* .PRECIOUS given on line by itself */ 12945447996SSimon J. Gerraty Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 1303955d011SMarcel Moolenaar 1313955d011SMarcel Moolenaar static int maxJobTokens; /* -j argument */ 1324c620fe5SSimon J. Gerraty Boolean enterFlagObj; /* -w and objdir != srcdir */ 133956e45f6SSimon J. Gerraty 1343955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 1353955d011SMarcel Moolenaar Boolean doing_depend; /* Set while reading .depend */ 1363955d011SMarcel Moolenaar static Boolean jobsRunning; /* TRUE if the jobs might be running */ 1373955d011SMarcel Moolenaar static const char *tracefile; 1382c3632d1SSimon J. Gerraty static int ReadMakefile(const char *); 139e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void); 1403955d011SMarcel Moolenaar 1413955d011SMarcel Moolenaar static Boolean 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 1493955d011SMarcel Moolenaar Boolean 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 { 16051ee2c1cSSimon J. Gerraty size_t len; 16151ee2c1cSSimon J. Gerraty char *nf, *st; 16251ee2c1cSSimon J. Gerraty const char *f; 16351ee2c1cSSimon J. Gerraty 16451ee2c1cSSimon J. Gerraty if (flags == NULL) 16551ee2c1cSSimon J. Gerraty return NULL; 16651ee2c1cSSimon J. Gerraty 16706b9b3e0SSimon J. Gerraty for (f = flags; *f != '\0'; f++) 168956e45f6SSimon J. Gerraty if (!ch_isalpha(*f)) 16951ee2c1cSSimon J. Gerraty break; 17051ee2c1cSSimon J. Gerraty 17106b9b3e0SSimon J. Gerraty if (*f != '\0') 17251ee2c1cSSimon J. Gerraty return bmake_strdup(flags); 17351ee2c1cSSimon J. Gerraty 17451ee2c1cSSimon J. Gerraty len = strlen(flags); 17551ee2c1cSSimon J. Gerraty st = nf = bmake_malloc(len * 3 + 1); 17606b9b3e0SSimon J. Gerraty while (*flags != '\0') { 17751ee2c1cSSimon J. Gerraty *nf++ = '-'; 17851ee2c1cSSimon J. Gerraty *nf++ = *flags++; 17951ee2c1cSSimon J. Gerraty *nf++ = ' '; 18051ee2c1cSSimon J. Gerraty } 18151ee2c1cSSimon J. Gerraty *nf = '\0'; 18251ee2c1cSSimon J. Gerraty return st; 18351ee2c1cSSimon J. Gerraty } 18451ee2c1cSSimon J. Gerraty 185e2eeea75SSimon J. Gerraty /* 186e2eeea75SSimon J. Gerraty * usage -- 187e2eeea75SSimon J. Gerraty * exit with usage message 188e2eeea75SSimon J. Gerraty */ 189e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void 190e2eeea75SSimon J. Gerraty usage(void) 191e2eeea75SSimon J. Gerraty { 192e2eeea75SSimon J. Gerraty size_t prognameLen = strcspn(progname, "["); 193e2eeea75SSimon J. Gerraty 194e2eeea75SSimon J. Gerraty (void)fprintf(stderr, 195e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n" 196e2eeea75SSimon J. Gerraty " [-C directory] [-D variable] [-d flags] [-f makefile]\n" 197e2eeea75SSimon J. Gerraty " [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 198e2eeea75SSimon J. Gerraty " [-V variable] [-v variable] [variable=value] [target ...]\n", 199e2eeea75SSimon J. Gerraty (int)prognameLen, progname); 200e2eeea75SSimon J. Gerraty exit(2); 201e2eeea75SSimon J. Gerraty } 202e2eeea75SSimon J. Gerraty 2033955d011SMarcel Moolenaar static void 204*dba7b0efSSimon J. Gerraty MainParseArgDebugFile(const char *arg) 2053955d011SMarcel Moolenaar { 2063955d011SMarcel Moolenaar const char *mode; 207956e45f6SSimon J. Gerraty size_t len; 2083955d011SMarcel Moolenaar char *fname; 2093955d011SMarcel Moolenaar 210956e45f6SSimon J. Gerraty if (opts.debug_file != stdout && opts.debug_file != stderr) 211956e45f6SSimon J. Gerraty fclose(opts.debug_file); 212956e45f6SSimon J. Gerraty 213*dba7b0efSSimon J. Gerraty if (*arg == '+') { 214*dba7b0efSSimon J. Gerraty arg++; 2153955d011SMarcel Moolenaar mode = "a"; 2163955d011SMarcel Moolenaar } else 2173955d011SMarcel Moolenaar mode = "w"; 218956e45f6SSimon J. Gerraty 219*dba7b0efSSimon J. Gerraty if (strcmp(arg, "stdout") == 0) { 220956e45f6SSimon J. Gerraty opts.debug_file = stdout; 221956e45f6SSimon J. Gerraty return; 2223955d011SMarcel Moolenaar } 223*dba7b0efSSimon J. Gerraty if (strcmp(arg, "stderr") == 0) { 224956e45f6SSimon J. Gerraty opts.debug_file = stderr; 225956e45f6SSimon J. Gerraty return; 2263955d011SMarcel Moolenaar } 227956e45f6SSimon J. Gerraty 228*dba7b0efSSimon J. Gerraty len = strlen(arg); 229e1cee40dSSimon J. Gerraty fname = bmake_malloc(len + 20); 230*dba7b0efSSimon J. Gerraty memcpy(fname, arg, len + 1); 231956e45f6SSimon J. Gerraty 2323955d011SMarcel Moolenaar /* Let the filename be modified by the pid */ 2333955d011SMarcel Moolenaar if (strcmp(fname + len - 3, ".%d") == 0) 2343955d011SMarcel Moolenaar snprintf(fname + len - 2, 20, "%d", getpid()); 235956e45f6SSimon J. Gerraty 236956e45f6SSimon J. Gerraty opts.debug_file = fopen(fname, mode); 237e2eeea75SSimon J. Gerraty if (opts.debug_file == NULL) { 2383955d011SMarcel Moolenaar fprintf(stderr, "Cannot open debug file %s\n", 2393955d011SMarcel Moolenaar fname); 2403955d011SMarcel Moolenaar usage(); 2413955d011SMarcel Moolenaar } 2423955d011SMarcel Moolenaar free(fname); 243956e45f6SSimon J. Gerraty } 244956e45f6SSimon J. Gerraty 245956e45f6SSimon J. Gerraty static void 246*dba7b0efSSimon J. Gerraty MainParseArgDebug(const char *argvalue) 247956e45f6SSimon J. Gerraty { 248956e45f6SSimon J. Gerraty const char *modules; 249e2eeea75SSimon J. Gerraty DebugFlags debug = opts.debug; 250956e45f6SSimon J. Gerraty 251*dba7b0efSSimon J. Gerraty for (modules = argvalue; *modules != '\0'; modules++) { 252956e45f6SSimon J. Gerraty switch (*modules) { 253956e45f6SSimon J. Gerraty case '0': /* undocumented, only intended for tests */ 254e2eeea75SSimon J. Gerraty debug = DEBUG_NONE; 255956e45f6SSimon J. Gerraty break; 256956e45f6SSimon J. Gerraty case 'A': 257e2eeea75SSimon J. Gerraty debug = DEBUG_ALL; 258956e45f6SSimon J. Gerraty break; 259956e45f6SSimon J. Gerraty case 'a': 260e2eeea75SSimon J. Gerraty debug |= DEBUG_ARCH; 261956e45f6SSimon J. Gerraty break; 262956e45f6SSimon J. Gerraty case 'C': 263e2eeea75SSimon J. Gerraty debug |= DEBUG_CWD; 264956e45f6SSimon J. Gerraty break; 265956e45f6SSimon J. Gerraty case 'c': 266e2eeea75SSimon J. Gerraty debug |= DEBUG_COND; 267956e45f6SSimon J. Gerraty break; 268956e45f6SSimon J. Gerraty case 'd': 269e2eeea75SSimon J. Gerraty debug |= DEBUG_DIR; 270956e45f6SSimon J. Gerraty break; 271956e45f6SSimon J. Gerraty case 'e': 272e2eeea75SSimon J. Gerraty debug |= DEBUG_ERROR; 273956e45f6SSimon J. Gerraty break; 274956e45f6SSimon J. Gerraty case 'f': 275e2eeea75SSimon J. Gerraty debug |= DEBUG_FOR; 276956e45f6SSimon J. Gerraty break; 277956e45f6SSimon J. Gerraty case 'g': 278956e45f6SSimon J. Gerraty if (modules[1] == '1') { 279e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH1; 280e2eeea75SSimon J. Gerraty modules++; 281e2eeea75SSimon J. Gerraty } else if (modules[1] == '2') { 282e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH2; 283e2eeea75SSimon J. Gerraty modules++; 284e2eeea75SSimon J. Gerraty } else if (modules[1] == '3') { 285e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH3; 286e2eeea75SSimon J. Gerraty modules++; 287956e45f6SSimon J. Gerraty } 288956e45f6SSimon J. Gerraty break; 289956e45f6SSimon J. Gerraty case 'h': 290e2eeea75SSimon J. Gerraty debug |= DEBUG_HASH; 291956e45f6SSimon J. Gerraty break; 292956e45f6SSimon J. Gerraty case 'j': 293e2eeea75SSimon J. Gerraty debug |= DEBUG_JOB; 294956e45f6SSimon J. Gerraty break; 295956e45f6SSimon J. Gerraty case 'L': 29606b9b3e0SSimon J. Gerraty opts.strict = TRUE; 297956e45f6SSimon J. Gerraty break; 298956e45f6SSimon J. Gerraty case 'l': 299e2eeea75SSimon J. Gerraty debug |= DEBUG_LOUD; 300956e45f6SSimon J. Gerraty break; 301956e45f6SSimon J. Gerraty case 'M': 302e2eeea75SSimon J. Gerraty debug |= DEBUG_META; 303956e45f6SSimon J. Gerraty break; 304956e45f6SSimon J. Gerraty case 'm': 305e2eeea75SSimon J. Gerraty debug |= DEBUG_MAKE; 306956e45f6SSimon J. Gerraty break; 307956e45f6SSimon J. Gerraty case 'n': 308e2eeea75SSimon J. Gerraty debug |= DEBUG_SCRIPT; 309956e45f6SSimon J. Gerraty break; 310956e45f6SSimon J. Gerraty case 'p': 311e2eeea75SSimon J. Gerraty debug |= DEBUG_PARSE; 312956e45f6SSimon J. Gerraty break; 313956e45f6SSimon J. Gerraty case 's': 314e2eeea75SSimon J. Gerraty debug |= DEBUG_SUFF; 315956e45f6SSimon J. Gerraty break; 316956e45f6SSimon J. Gerraty case 't': 317e2eeea75SSimon J. Gerraty debug |= DEBUG_TARG; 318956e45f6SSimon J. Gerraty break; 319956e45f6SSimon J. Gerraty case 'V': 320956e45f6SSimon J. Gerraty opts.debugVflag = TRUE; 321956e45f6SSimon J. Gerraty break; 322956e45f6SSimon J. Gerraty case 'v': 323e2eeea75SSimon J. Gerraty debug |= DEBUG_VAR; 324956e45f6SSimon J. Gerraty break; 325956e45f6SSimon J. Gerraty case 'x': 326e2eeea75SSimon J. Gerraty debug |= DEBUG_SHELL; 327956e45f6SSimon J. Gerraty break; 328956e45f6SSimon J. Gerraty case 'F': 329*dba7b0efSSimon J. Gerraty MainParseArgDebugFile(modules + 1); 3303955d011SMarcel Moolenaar goto debug_setbuf; 3313955d011SMarcel Moolenaar default: 3323955d011SMarcel Moolenaar (void)fprintf(stderr, 3333955d011SMarcel Moolenaar "%s: illegal argument to d option -- %c\n", 3343955d011SMarcel Moolenaar progname, *modules); 3353955d011SMarcel Moolenaar usage(); 3363955d011SMarcel Moolenaar } 3373955d011SMarcel Moolenaar } 338e2eeea75SSimon J. Gerraty 3393955d011SMarcel Moolenaar debug_setbuf: 340e2eeea75SSimon J. Gerraty opts.debug = debug; 341e2eeea75SSimon J. Gerraty 3423955d011SMarcel Moolenaar /* 3433955d011SMarcel Moolenaar * Make the debug_file unbuffered, and make 3443955d011SMarcel Moolenaar * stdout line buffered (unless debugfile == stdout). 3453955d011SMarcel Moolenaar */ 346956e45f6SSimon J. Gerraty setvbuf(opts.debug_file, NULL, _IONBF, 0); 347956e45f6SSimon J. Gerraty if (opts.debug_file != stdout) { 3483955d011SMarcel Moolenaar setvbuf(stdout, NULL, _IOLBF, 0); 3493955d011SMarcel Moolenaar } 3503955d011SMarcel Moolenaar } 3513955d011SMarcel Moolenaar 352*dba7b0efSSimon J. Gerraty /* Is path relative, or does it contain any relative component "." or ".."? */ 3532c3632d1SSimon J. Gerraty static Boolean 354*dba7b0efSSimon J. Gerraty IsRelativePath(const char *path) 355e1cee40dSSimon J. Gerraty { 356e1cee40dSSimon J. Gerraty const char *cp; 357e1cee40dSSimon J. Gerraty 358e1cee40dSSimon J. Gerraty if (path[0] != '/') 359e1cee40dSSimon J. Gerraty return TRUE; 360e1cee40dSSimon J. Gerraty cp = path; 3612c3632d1SSimon J. Gerraty while ((cp = strstr(cp, "/.")) != NULL) { 362e1cee40dSSimon J. Gerraty cp += 2; 363e2eeea75SSimon J. Gerraty if (*cp == '.') 364e2eeea75SSimon J. Gerraty cp++; 365e1cee40dSSimon J. Gerraty if (cp[0] == '/' || cp[0] == '\0') 366e1cee40dSSimon J. Gerraty return TRUE; 3672c3632d1SSimon J. Gerraty } 368e1cee40dSSimon J. Gerraty return FALSE; 369e1cee40dSSimon J. Gerraty } 370e1cee40dSSimon J. Gerraty 371956e45f6SSimon J. Gerraty static void 372956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue) 373956e45f6SSimon J. Gerraty { 374956e45f6SSimon J. Gerraty struct stat sa, sb; 375956e45f6SSimon J. Gerraty 376956e45f6SSimon J. Gerraty if (chdir(argvalue) == -1) { 377956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: chdir %s: %s\n", 378956e45f6SSimon J. Gerraty progname, argvalue, strerror(errno)); 37906b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 380956e45f6SSimon J. Gerraty } 381956e45f6SSimon J. Gerraty if (getcwd(curdir, MAXPATHLEN) == NULL) { 382956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 383956e45f6SSimon J. Gerraty exit(2); 384956e45f6SSimon J. Gerraty } 385*dba7b0efSSimon J. Gerraty if (!IsRelativePath(argvalue) && 386956e45f6SSimon J. Gerraty stat(argvalue, &sa) != -1 && 387956e45f6SSimon J. Gerraty stat(curdir, &sb) != -1 && 388956e45f6SSimon J. Gerraty sa.st_ino == sb.st_ino && 389956e45f6SSimon J. Gerraty sa.st_dev == sb.st_dev) 390956e45f6SSimon J. Gerraty strncpy(curdir, argvalue, MAXPATHLEN); 391956e45f6SSimon J. Gerraty ignorePWD = TRUE; 392956e45f6SSimon J. Gerraty } 393956e45f6SSimon J. Gerraty 394956e45f6SSimon J. Gerraty static void 395956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue) 396956e45f6SSimon J. Gerraty { 397e2eeea75SSimon J. Gerraty char end; 398e2eeea75SSimon J. Gerraty if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { 399956e45f6SSimon J. Gerraty (void)fprintf(stderr, 400956e45f6SSimon J. Gerraty "%s: internal error -- J option malformed (%s)\n", 401956e45f6SSimon J. Gerraty progname, argvalue); 402956e45f6SSimon J. Gerraty usage(); 403956e45f6SSimon J. Gerraty } 404956e45f6SSimon J. Gerraty if ((fcntl(jp_0, F_GETFD, 0) < 0) || 405956e45f6SSimon J. Gerraty (fcntl(jp_1, F_GETFD, 0) < 0)) { 406956e45f6SSimon J. Gerraty #if 0 407956e45f6SSimon J. Gerraty (void)fprintf(stderr, 408956e45f6SSimon J. Gerraty "%s: ###### warning -- J descriptors were closed!\n", 409956e45f6SSimon J. Gerraty progname); 410956e45f6SSimon J. Gerraty exit(2); 411956e45f6SSimon J. Gerraty #endif 412956e45f6SSimon J. Gerraty jp_0 = -1; 413956e45f6SSimon J. Gerraty jp_1 = -1; 414956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 415956e45f6SSimon J. Gerraty } else { 416*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-J"); 417*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 418956e45f6SSimon J. Gerraty } 419956e45f6SSimon J. Gerraty } 420956e45f6SSimon J. Gerraty 421956e45f6SSimon J. Gerraty static void 422956e45f6SSimon J. Gerraty MainParseArgJobs(const char *argvalue) 423956e45f6SSimon J. Gerraty { 424956e45f6SSimon J. Gerraty char *p; 425956e45f6SSimon J. Gerraty 426956e45f6SSimon J. Gerraty forceJobs = TRUE; 427956e45f6SSimon J. Gerraty opts.maxJobs = (int)strtol(argvalue, &p, 0); 428956e45f6SSimon J. Gerraty if (*p != '\0' || opts.maxJobs < 1) { 429956e45f6SSimon J. Gerraty (void)fprintf(stderr, 430956e45f6SSimon J. Gerraty "%s: illegal argument to -j -- must be positive integer!\n", 431956e45f6SSimon J. Gerraty progname); 43206b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 433956e45f6SSimon J. Gerraty } 434*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-j"); 435*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 436*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.JOBS", argvalue); 437956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 438956e45f6SSimon J. Gerraty } 439956e45f6SSimon J. Gerraty 440956e45f6SSimon J. Gerraty static void 441956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue) 442956e45f6SSimon J. Gerraty { 443956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 444956e45f6SSimon J. Gerraty if (strncmp(".../", argvalue, 4) == 0) { 445956e45f6SSimon J. Gerraty char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 446956e45f6SSimon J. Gerraty if (found_path == NULL) 447956e45f6SSimon J. Gerraty return; 448*dba7b0efSSimon J. Gerraty (void)SearchPath_Add(sysIncPath, found_path); 449956e45f6SSimon J. Gerraty free(found_path); 450956e45f6SSimon J. Gerraty } else { 451*dba7b0efSSimon J. Gerraty (void)SearchPath_Add(sysIncPath, argvalue); 452956e45f6SSimon J. Gerraty } 453*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-m"); 454*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 455956e45f6SSimon J. Gerraty } 456956e45f6SSimon J. Gerraty 457956e45f6SSimon J. Gerraty static Boolean 458956e45f6SSimon J. Gerraty MainParseArg(char c, const char *argvalue) 459956e45f6SSimon J. Gerraty { 460956e45f6SSimon J. Gerraty switch (c) { 461956e45f6SSimon J. Gerraty case '\0': 462956e45f6SSimon J. Gerraty break; 463956e45f6SSimon J. Gerraty case 'B': 464956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 465*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-B"); 466*dba7b0efSSimon J. Gerraty Global_Set(MAKE_MODE, "compat"); 467956e45f6SSimon J. Gerraty break; 468956e45f6SSimon J. Gerraty case 'C': 469956e45f6SSimon J. Gerraty MainParseArgChdir(argvalue); 470956e45f6SSimon J. Gerraty break; 471956e45f6SSimon J. Gerraty case 'D': 472956e45f6SSimon J. Gerraty if (argvalue[0] == '\0') return FALSE; 473*dba7b0efSSimon J. Gerraty Global_SetExpand(argvalue, "1"); 474*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-D"); 475*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 476956e45f6SSimon J. Gerraty break; 477956e45f6SSimon J. Gerraty case 'I': 478956e45f6SSimon J. Gerraty Parse_AddIncludeDir(argvalue); 479*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-I"); 480*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 481956e45f6SSimon J. Gerraty break; 482956e45f6SSimon J. Gerraty case 'J': 483956e45f6SSimon J. Gerraty MainParseArgJobsInternal(argvalue); 484956e45f6SSimon J. Gerraty break; 485956e45f6SSimon J. Gerraty case 'N': 486956e45f6SSimon J. Gerraty opts.noExecute = TRUE; 487956e45f6SSimon J. Gerraty opts.noRecursiveExecute = TRUE; 488*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-N"); 489956e45f6SSimon J. Gerraty break; 490956e45f6SSimon J. Gerraty case 'S': 491956e45f6SSimon J. Gerraty opts.keepgoing = FALSE; 492*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-S"); 493956e45f6SSimon J. Gerraty break; 494956e45f6SSimon J. Gerraty case 'T': 495956e45f6SSimon J. Gerraty tracefile = bmake_strdup(argvalue); 496*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-T"); 497*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 498956e45f6SSimon J. Gerraty break; 499956e45f6SSimon J. Gerraty case 'V': 500956e45f6SSimon J. Gerraty case 'v': 501e2eeea75SSimon J. Gerraty opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED; 50206b9b3e0SSimon J. Gerraty Lst_Append(&opts.variables, bmake_strdup(argvalue)); 503956e45f6SSimon J. Gerraty /* XXX: Why always -V? */ 504*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-V"); 505*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 506956e45f6SSimon J. Gerraty break; 507956e45f6SSimon J. Gerraty case 'W': 508956e45f6SSimon J. Gerraty opts.parseWarnFatal = TRUE; 509e2eeea75SSimon J. Gerraty /* XXX: why no Var_Append? */ 510956e45f6SSimon J. Gerraty break; 511956e45f6SSimon J. Gerraty case 'X': 512956e45f6SSimon J. Gerraty opts.varNoExportEnv = TRUE; 513*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-X"); 514956e45f6SSimon J. Gerraty break; 515956e45f6SSimon J. Gerraty case 'd': 516956e45f6SSimon J. Gerraty /* If '-d-opts' don't pass to children */ 517956e45f6SSimon J. Gerraty if (argvalue[0] == '-') 518956e45f6SSimon J. Gerraty argvalue++; 519956e45f6SSimon J. Gerraty else { 520*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-d"); 521*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, argvalue); 522956e45f6SSimon J. Gerraty } 523*dba7b0efSSimon J. Gerraty MainParseArgDebug(argvalue); 524956e45f6SSimon J. Gerraty break; 525956e45f6SSimon J. Gerraty case 'e': 526956e45f6SSimon J. Gerraty opts.checkEnvFirst = TRUE; 527*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-e"); 528956e45f6SSimon J. Gerraty break; 529956e45f6SSimon J. Gerraty case 'f': 53006b9b3e0SSimon J. Gerraty Lst_Append(&opts.makefiles, bmake_strdup(argvalue)); 531956e45f6SSimon J. Gerraty break; 532956e45f6SSimon J. Gerraty case 'i': 533956e45f6SSimon J. Gerraty opts.ignoreErrors = TRUE; 534*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-i"); 535956e45f6SSimon J. Gerraty break; 536956e45f6SSimon J. Gerraty case 'j': 537956e45f6SSimon J. Gerraty MainParseArgJobs(argvalue); 538956e45f6SSimon J. Gerraty break; 539956e45f6SSimon J. Gerraty case 'k': 540956e45f6SSimon J. Gerraty opts.keepgoing = TRUE; 541*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-k"); 542956e45f6SSimon J. Gerraty break; 543956e45f6SSimon J. Gerraty case 'm': 544956e45f6SSimon J. Gerraty MainParseArgSysInc(argvalue); 545e2eeea75SSimon J. Gerraty /* XXX: why no Var_Append? */ 546956e45f6SSimon J. Gerraty break; 547956e45f6SSimon J. Gerraty case 'n': 548956e45f6SSimon J. Gerraty opts.noExecute = TRUE; 549*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-n"); 550956e45f6SSimon J. Gerraty break; 551956e45f6SSimon J. Gerraty case 'q': 552956e45f6SSimon J. Gerraty opts.queryFlag = TRUE; 553956e45f6SSimon J. Gerraty /* Kind of nonsensical, wot? */ 554*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-q"); 555956e45f6SSimon J. Gerraty break; 556956e45f6SSimon J. Gerraty case 'r': 557956e45f6SSimon J. Gerraty opts.noBuiltins = TRUE; 558*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-r"); 559956e45f6SSimon J. Gerraty break; 560956e45f6SSimon J. Gerraty case 's': 561956e45f6SSimon J. Gerraty opts.beSilent = TRUE; 562*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-s"); 563956e45f6SSimon J. Gerraty break; 564956e45f6SSimon J. Gerraty case 't': 565956e45f6SSimon J. Gerraty opts.touchFlag = TRUE; 566*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-t"); 567956e45f6SSimon J. Gerraty break; 568956e45f6SSimon J. Gerraty case 'w': 569956e45f6SSimon J. Gerraty opts.enterFlag = TRUE; 570*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-w"); 571956e45f6SSimon J. Gerraty break; 572956e45f6SSimon J. Gerraty default: 573956e45f6SSimon J. Gerraty case '?': 574956e45f6SSimon J. Gerraty usage(); 575956e45f6SSimon J. Gerraty } 576956e45f6SSimon J. Gerraty return TRUE; 577956e45f6SSimon J. Gerraty } 578956e45f6SSimon J. Gerraty 57906b9b3e0SSimon J. Gerraty /* 58006b9b3e0SSimon J. Gerraty * Parse the given arguments. Called from main() and from 5813955d011SMarcel Moolenaar * Main_ParseArgLine() when the .MAKEFLAGS target is used. 5823955d011SMarcel Moolenaar * 583956e45f6SSimon J. Gerraty * The arguments must be treated as read-only and will be freed after the 584956e45f6SSimon J. Gerraty * call. 5853955d011SMarcel Moolenaar * 58606b9b3e0SSimon J. Gerraty * XXX: Deal with command line overriding .MAKEFLAGS in makefile 58706b9b3e0SSimon J. Gerraty */ 5883955d011SMarcel Moolenaar static void 5893955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv) 5903955d011SMarcel Moolenaar { 591956e45f6SSimon J. Gerraty char c; 5923955d011SMarcel Moolenaar int arginc; 5933955d011SMarcel Moolenaar char *argvalue; 5943955d011SMarcel Moolenaar char *optscan; 5953955d011SMarcel Moolenaar Boolean inOption, dashDash = FALSE; 5963955d011SMarcel Moolenaar 597956e45f6SSimon J. Gerraty const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 5983955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */ 5993955d011SMarcel Moolenaar 6003955d011SMarcel Moolenaar rearg: 6013955d011SMarcel Moolenaar inOption = FALSE; 6023955d011SMarcel Moolenaar optscan = NULL; 6033955d011SMarcel Moolenaar while (argc > 1) { 604956e45f6SSimon J. Gerraty const char *optspec; 6053955d011SMarcel Moolenaar if (!inOption) 6063955d011SMarcel Moolenaar optscan = argv[1]; 6073955d011SMarcel Moolenaar c = *optscan++; 6083955d011SMarcel Moolenaar arginc = 0; 6093955d011SMarcel Moolenaar if (inOption) { 6103955d011SMarcel Moolenaar if (c == '\0') { 611e2eeea75SSimon J. Gerraty argv++; 612e2eeea75SSimon J. Gerraty argc--; 6133955d011SMarcel Moolenaar inOption = FALSE; 6143955d011SMarcel Moolenaar continue; 6153955d011SMarcel Moolenaar } 6163955d011SMarcel Moolenaar } else { 6173955d011SMarcel Moolenaar if (c != '-' || dashDash) 6183955d011SMarcel Moolenaar break; 6193955d011SMarcel Moolenaar inOption = TRUE; 6203955d011SMarcel Moolenaar c = *optscan++; 6213955d011SMarcel Moolenaar } 6223955d011SMarcel Moolenaar /* '-' found at some earlier point */ 623956e45f6SSimon J. Gerraty optspec = strchr(optspecs, c); 624956e45f6SSimon J. Gerraty if (c != '\0' && optspec != NULL && optspec[1] == ':') { 6253955d011SMarcel Moolenaar /* -<something> found, and <something> should have an arg */ 6263955d011SMarcel Moolenaar inOption = FALSE; 6273955d011SMarcel Moolenaar arginc = 1; 6283955d011SMarcel Moolenaar argvalue = optscan; 6293955d011SMarcel Moolenaar if (*argvalue == '\0') { 6303955d011SMarcel Moolenaar if (argc < 3) 6313955d011SMarcel Moolenaar goto noarg; 6323955d011SMarcel Moolenaar argvalue = argv[2]; 6333955d011SMarcel Moolenaar arginc = 2; 6343955d011SMarcel Moolenaar } 6353955d011SMarcel Moolenaar } else { 6363955d011SMarcel Moolenaar argvalue = NULL; 6373955d011SMarcel Moolenaar } 6383955d011SMarcel Moolenaar switch (c) { 6393955d011SMarcel Moolenaar case '\0': 6403955d011SMarcel Moolenaar arginc = 1; 6413955d011SMarcel Moolenaar inOption = FALSE; 6423955d011SMarcel Moolenaar break; 6433955d011SMarcel Moolenaar case '-': 6443955d011SMarcel Moolenaar dashDash = TRUE; 6453955d011SMarcel Moolenaar break; 6463955d011SMarcel Moolenaar default: 647956e45f6SSimon J. Gerraty if (!MainParseArg(c, argvalue)) 648956e45f6SSimon J. Gerraty goto noarg; 6493955d011SMarcel Moolenaar } 6503955d011SMarcel Moolenaar argv += arginc; 6513955d011SMarcel Moolenaar argc -= arginc; 6523955d011SMarcel Moolenaar } 6533955d011SMarcel Moolenaar 6543955d011SMarcel Moolenaar /* 6553955d011SMarcel Moolenaar * See if the rest of the arguments are variable assignments and 6563955d011SMarcel Moolenaar * perform them if so. Else take them to be targets and stuff them 6573955d011SMarcel Moolenaar * on the end of the "create" list. 6583955d011SMarcel Moolenaar */ 659*dba7b0efSSimon J. Gerraty for (; argc > 1; argv++, argc--) { 660956e45f6SSimon J. Gerraty VarAssign var; 661956e45f6SSimon J. Gerraty if (Parse_IsVar(argv[1], &var)) { 662*dba7b0efSSimon J. Gerraty Parse_DoVar(&var, SCOPE_CMDLINE); 6633955d011SMarcel Moolenaar } else { 664e2eeea75SSimon J. Gerraty if (argv[1][0] == '\0') 6653955d011SMarcel Moolenaar Punt("illegal (null) argument."); 666e2eeea75SSimon J. Gerraty if (argv[1][0] == '-' && !dashDash) 6673955d011SMarcel Moolenaar goto rearg; 66806b9b3e0SSimon J. Gerraty Lst_Append(&opts.create, bmake_strdup(argv[1])); 669956e45f6SSimon J. Gerraty } 6703955d011SMarcel Moolenaar } 6713955d011SMarcel Moolenaar 6723955d011SMarcel Moolenaar return; 6733955d011SMarcel Moolenaar noarg: 6743955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 6753955d011SMarcel Moolenaar progname, c); 6763955d011SMarcel Moolenaar usage(); 6773955d011SMarcel Moolenaar } 6783955d011SMarcel Moolenaar 67906b9b3e0SSimon J. Gerraty /* 68006b9b3e0SSimon J. Gerraty * Break a line of arguments into words and parse them. 6813955d011SMarcel Moolenaar * 682956e45f6SSimon J. Gerraty * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 68306b9b3e0SSimon J. Gerraty * by main() when reading the MAKEFLAGS environment variable. 68406b9b3e0SSimon J. Gerraty */ 6853955d011SMarcel Moolenaar void 6863955d011SMarcel Moolenaar Main_ParseArgLine(const char *line) 6873955d011SMarcel Moolenaar { 6882c3632d1SSimon J. Gerraty Words words; 6892c3632d1SSimon J. Gerraty char *buf; 6903955d011SMarcel Moolenaar 6913955d011SMarcel Moolenaar if (line == NULL) 6923955d011SMarcel Moolenaar return; 69306b9b3e0SSimon J. Gerraty /* XXX: don't use line as an iterator variable */ 694*dba7b0efSSimon J. Gerraty for (; *line == ' '; line++) 6953955d011SMarcel Moolenaar continue; 696e2eeea75SSimon J. Gerraty if (line[0] == '\0') 6973955d011SMarcel Moolenaar return; 6983955d011SMarcel Moolenaar 6993955d011SMarcel Moolenaar #ifndef POSIX 7003955d011SMarcel Moolenaar { 7013955d011SMarcel Moolenaar /* 7023955d011SMarcel Moolenaar * $MAKE may simply be naming the make(1) binary 7033955d011SMarcel Moolenaar */ 7043955d011SMarcel Moolenaar char *cp; 7053955d011SMarcel Moolenaar 7063955d011SMarcel Moolenaar if (!(cp = strrchr(line, '/'))) 7073955d011SMarcel Moolenaar cp = line; 7083955d011SMarcel Moolenaar if ((cp = strstr(cp, "make")) && 7093955d011SMarcel Moolenaar strcmp(cp, "make") == 0) 7103955d011SMarcel Moolenaar return; 7113955d011SMarcel Moolenaar } 7123955d011SMarcel Moolenaar #endif 713e2eeea75SSimon J. Gerraty { 714*dba7b0efSSimon J. Gerraty FStr argv0 = Var_Value(SCOPE_GLOBAL, ".MAKE"); 71506b9b3e0SSimon J. Gerraty buf = str_concat3(argv0.str, " ", line); 71606b9b3e0SSimon J. Gerraty FStr_Done(&argv0); 717e2eeea75SSimon J. Gerraty } 7183955d011SMarcel Moolenaar 7192c3632d1SSimon J. Gerraty words = Str_Words(buf, TRUE); 7202c3632d1SSimon J. Gerraty if (words.words == NULL) { 7213955d011SMarcel Moolenaar Error("Unterminated quoted string [%s]", buf); 7223955d011SMarcel Moolenaar free(buf); 7233955d011SMarcel Moolenaar return; 7243955d011SMarcel Moolenaar } 7253955d011SMarcel Moolenaar free(buf); 7262c3632d1SSimon J. Gerraty MainParseArgs((int)words.len, words.words); 7273955d011SMarcel Moolenaar 7282c3632d1SSimon J. Gerraty Words_Free(words); 7293955d011SMarcel Moolenaar } 7303955d011SMarcel Moolenaar 7313955d011SMarcel Moolenaar Boolean 732e2eeea75SSimon J. Gerraty Main_SetObjdir(Boolean writable, const char *fmt, ...) 7333955d011SMarcel Moolenaar { 7343955d011SMarcel Moolenaar struct stat sb; 735b46b9039SSimon J. Gerraty char *path; 736b46b9039SSimon J. Gerraty char buf[MAXPATHLEN + 1]; 737e23f3f6eSSimon J. Gerraty char buf2[MAXPATHLEN + 1]; 7383955d011SMarcel Moolenaar Boolean rc = FALSE; 73945447996SSimon J. Gerraty va_list ap; 74045447996SSimon J. Gerraty 74145447996SSimon J. Gerraty va_start(ap, fmt); 742b46b9039SSimon J. Gerraty vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 74345447996SSimon J. Gerraty va_end(ap); 7443955d011SMarcel Moolenaar 7453955d011SMarcel Moolenaar if (path[0] != '/') { 746e1cee40dSSimon J. Gerraty snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 747e1cee40dSSimon J. Gerraty path = buf2; 7483955d011SMarcel Moolenaar } 7493955d011SMarcel Moolenaar 7503955d011SMarcel Moolenaar /* look for the directory and try to chdir there */ 7513955d011SMarcel Moolenaar if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 752e2eeea75SSimon J. Gerraty if ((writable && access(path, W_OK) != 0) || 753e2eeea75SSimon J. Gerraty (chdir(path) != 0)) { 754e2eeea75SSimon J. Gerraty (void)fprintf(stderr, "%s warning: %s: %s.\n", 755e2eeea75SSimon J. Gerraty progname, path, strerror(errno)); 7563955d011SMarcel Moolenaar } else { 7572c3632d1SSimon J. Gerraty snprintf(objdir, sizeof objdir, "%s", path); 758*dba7b0efSSimon J. Gerraty Global_Set(".OBJDIR", objdir); 7593955d011SMarcel Moolenaar setenv("PWD", objdir, 1); 7603955d011SMarcel Moolenaar Dir_InitDot(); 761e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(); 7623955d011SMarcel Moolenaar rc = TRUE; 763956e45f6SSimon J. Gerraty if (opts.enterFlag && strcmp(objdir, curdir) != 0) 7644c620fe5SSimon J. Gerraty enterFlagObj = TRUE; 7653955d011SMarcel Moolenaar } 7663955d011SMarcel Moolenaar } 7673955d011SMarcel Moolenaar 7683955d011SMarcel Moolenaar return rc; 7693955d011SMarcel Moolenaar } 7703955d011SMarcel Moolenaar 77145447996SSimon J. Gerraty static Boolean 772e2eeea75SSimon J. Gerraty SetVarObjdir(Boolean writable, const char *var, const char *suffix) 77345447996SSimon J. Gerraty { 774*dba7b0efSSimon J. Gerraty FStr path = Var_Value(SCOPE_CMDLINE, var); 77506b9b3e0SSimon J. Gerraty FStr xpath; 776b46b9039SSimon J. Gerraty 77706b9b3e0SSimon J. Gerraty if (path.str == NULL || path.str[0] == '\0') { 77806b9b3e0SSimon J. Gerraty FStr_Done(&path); 77945447996SSimon J. Gerraty return FALSE; 7802c3632d1SSimon J. Gerraty } 78145447996SSimon J. Gerraty 782b46b9039SSimon J. Gerraty /* expand variable substitutions */ 78306b9b3e0SSimon J. Gerraty xpath = FStr_InitRefer(path.str); 78406b9b3e0SSimon J. Gerraty if (strchr(path.str, '$') != 0) { 78506b9b3e0SSimon J. Gerraty char *expanded; 786*dba7b0efSSimon J. Gerraty (void)Var_Subst(path.str, SCOPE_GLOBAL, VARE_WANTRES, &expanded); 787956e45f6SSimon J. Gerraty /* TODO: handle errors */ 78806b9b3e0SSimon J. Gerraty xpath = FStr_InitOwn(expanded); 789956e45f6SSimon J. Gerraty } 790b46b9039SSimon J. Gerraty 79106b9b3e0SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix); 792b46b9039SSimon J. Gerraty 79306b9b3e0SSimon J. Gerraty FStr_Done(&xpath); 79406b9b3e0SSimon J. Gerraty FStr_Done(&path); 79545447996SSimon J. Gerraty return TRUE; 79645447996SSimon J. Gerraty } 79745447996SSimon J. Gerraty 79806b9b3e0SSimon J. Gerraty /* 79906b9b3e0SSimon J. Gerraty * Splits str into words, adding them to the list. 80006b9b3e0SSimon J. Gerraty * The string must be kept alive as long as the list. 80106b9b3e0SSimon J. Gerraty */ 8023955d011SMarcel Moolenaar int 803e2eeea75SSimon J. Gerraty str2Lst_Append(StringList *lp, char *str) 8043955d011SMarcel Moolenaar { 8053955d011SMarcel Moolenaar char *cp; 8063955d011SMarcel Moolenaar int n; 8073955d011SMarcel Moolenaar 808e2eeea75SSimon J. Gerraty const char *sep = " \t"; 8093955d011SMarcel Moolenaar 81006b9b3e0SSimon J. Gerraty for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) { 8112c3632d1SSimon J. Gerraty Lst_Append(lp, cp); 8123955d011SMarcel Moolenaar n++; 8133955d011SMarcel Moolenaar } 8143841c287SSimon J. Gerraty return n; 8153955d011SMarcel Moolenaar } 8163955d011SMarcel Moolenaar 8173955d011SMarcel Moolenaar #ifdef SIGINFO 8183955d011SMarcel Moolenaar /*ARGSUSED*/ 8193955d011SMarcel Moolenaar static void 8203955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED) 8213955d011SMarcel Moolenaar { 8223955d011SMarcel Moolenaar char dir[MAXPATHLEN]; 8233955d011SMarcel Moolenaar char str[2 * MAXPATHLEN]; 8243955d011SMarcel Moolenaar int len; 825e2eeea75SSimon J. Gerraty if (getcwd(dir, sizeof dir) == NULL) 8263955d011SMarcel Moolenaar return; 827e2eeea75SSimon J. Gerraty len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir); 8283955d011SMarcel Moolenaar if (len > 0) 8293955d011SMarcel Moolenaar (void)write(STDERR_FILENO, str, (size_t)len); 8303955d011SMarcel Moolenaar } 8313955d011SMarcel Moolenaar #endif 8323955d011SMarcel Moolenaar 83306b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */ 83406b9b3e0SSimon J. Gerraty static void 83506b9b3e0SSimon J. Gerraty MakeMode(void) 8363955d011SMarcel Moolenaar { 837*dba7b0efSSimon J. Gerraty char *mode; 8383955d011SMarcel Moolenaar 839*dba7b0efSSimon J. Gerraty (void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode); 840956e45f6SSimon J. Gerraty /* TODO: handle errors */ 8413955d011SMarcel Moolenaar 842*dba7b0efSSimon J. Gerraty if (mode[0] != '\0') { 843*dba7b0efSSimon J. Gerraty if (strstr(mode, "compat") != NULL) { 844956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 8453955d011SMarcel Moolenaar forceJobs = FALSE; 8463955d011SMarcel Moolenaar } 8473955d011SMarcel Moolenaar #if USE_META 848*dba7b0efSSimon J. Gerraty if (strstr(mode, "meta") != NULL) 849*dba7b0efSSimon J. Gerraty meta_mode_init(mode); 8503955d011SMarcel Moolenaar #endif 8513955d011SMarcel Moolenaar } 852be19d90bSSimon J. Gerraty 853*dba7b0efSSimon J. Gerraty free(mode); 8543955d011SMarcel Moolenaar } 8553955d011SMarcel Moolenaar 8568695518cSSimon J. Gerraty static void 857956e45f6SSimon J. Gerraty PrintVar(const char *varname, Boolean expandVars) 858956e45f6SSimon J. Gerraty { 85906b9b3e0SSimon J. Gerraty if (strchr(varname, '$') != NULL) { 860956e45f6SSimon J. Gerraty char *evalue; 861*dba7b0efSSimon J. Gerraty (void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue); 862956e45f6SSimon J. Gerraty /* TODO: handle errors */ 863956e45f6SSimon J. Gerraty printf("%s\n", evalue); 864956e45f6SSimon J. Gerraty bmake_free(evalue); 865956e45f6SSimon J. Gerraty 866956e45f6SSimon J. Gerraty } else if (expandVars) { 867956e45f6SSimon J. Gerraty char *expr = str_concat3("${", varname, "}"); 868956e45f6SSimon J. Gerraty char *evalue; 869*dba7b0efSSimon J. Gerraty (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue); 870956e45f6SSimon J. Gerraty /* TODO: handle errors */ 871956e45f6SSimon J. Gerraty free(expr); 872956e45f6SSimon J. Gerraty printf("%s\n", evalue); 873956e45f6SSimon J. Gerraty bmake_free(evalue); 874956e45f6SSimon J. Gerraty 875956e45f6SSimon J. Gerraty } else { 876*dba7b0efSSimon J. Gerraty FStr value = Var_Value(SCOPE_GLOBAL, varname); 87706b9b3e0SSimon J. Gerraty printf("%s\n", value.str != NULL ? value.str : ""); 87806b9b3e0SSimon J. Gerraty FStr_Done(&value); 879956e45f6SSimon J. Gerraty } 880956e45f6SSimon J. Gerraty } 881956e45f6SSimon J. Gerraty 882e2eeea75SSimon J. Gerraty /* 883e2eeea75SSimon J. Gerraty * Return a Boolean based on a variable. 884e2eeea75SSimon J. Gerraty * 885e2eeea75SSimon J. Gerraty * If the knob is not set, return the fallback. 886e2eeea75SSimon J. Gerraty * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 887e2eeea75SSimon J. Gerraty * is FALSE, otherwise TRUE. 888e2eeea75SSimon J. Gerraty */ 889e2eeea75SSimon J. Gerraty Boolean 890e2eeea75SSimon J. Gerraty GetBooleanVar(const char *varname, Boolean fallback) 891e2eeea75SSimon J. Gerraty { 892e2eeea75SSimon J. Gerraty char *expr = str_concat3("${", varname, ":U}"); 893e2eeea75SSimon J. Gerraty char *value; 894e2eeea75SSimon J. Gerraty Boolean res; 895e2eeea75SSimon J. Gerraty 896*dba7b0efSSimon J. Gerraty (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value); 897e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 898e2eeea75SSimon J. Gerraty res = ParseBoolean(value, fallback); 899e2eeea75SSimon J. Gerraty free(value); 900e2eeea75SSimon J. Gerraty free(expr); 901e2eeea75SSimon J. Gerraty return res; 902e2eeea75SSimon J. Gerraty } 903e2eeea75SSimon J. Gerraty 904956e45f6SSimon J. Gerraty static void 9058695518cSSimon J. Gerraty doPrintVars(void) 9068695518cSSimon J. Gerraty { 907956e45f6SSimon J. Gerraty StringListNode *ln; 9088695518cSSimon J. Gerraty Boolean expandVars; 9098695518cSSimon J. Gerraty 910e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_EXPANDED) 9118695518cSSimon J. Gerraty expandVars = TRUE; 912956e45f6SSimon J. Gerraty else if (opts.debugVflag) 9138695518cSSimon J. Gerraty expandVars = FALSE; 9148695518cSSimon J. Gerraty else 915e2eeea75SSimon J. Gerraty expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE); 9168695518cSSimon J. Gerraty 91706b9b3e0SSimon J. Gerraty for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 918956e45f6SSimon J. Gerraty const char *varname = ln->datum; 919956e45f6SSimon J. Gerraty PrintVar(varname, expandVars); 9208695518cSSimon J. Gerraty } 9218695518cSSimon J. Gerraty } 9228695518cSSimon J. Gerraty 9238695518cSSimon J. Gerraty static Boolean 9248695518cSSimon J. Gerraty runTargets(void) 9258695518cSSimon J. Gerraty { 92606b9b3e0SSimon J. Gerraty GNodeList targs = LST_INIT; /* target nodes to create */ 9278695518cSSimon J. Gerraty Boolean outOfDate; /* FALSE if all targets up to date */ 9288695518cSSimon J. Gerraty 9298695518cSSimon J. Gerraty /* 9308695518cSSimon J. Gerraty * Have now read the entire graph and need to make a list of 9318695518cSSimon J. Gerraty * targets to create. If none was given on the command line, 9328695518cSSimon J. Gerraty * we consult the parsing module to find the main target(s) 9338695518cSSimon J. Gerraty * to create. 9348695518cSSimon J. Gerraty */ 93506b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) 93606b9b3e0SSimon J. Gerraty Parse_MainName(&targs); 9378695518cSSimon J. Gerraty else 93806b9b3e0SSimon J. Gerraty Targ_FindList(&targs, &opts.create); 9398695518cSSimon J. Gerraty 940956e45f6SSimon J. Gerraty if (!opts.compatMake) { 9418695518cSSimon J. Gerraty /* 9428695518cSSimon J. Gerraty * Initialize job module before traversing the graph 9438695518cSSimon J. Gerraty * now that any .BEGIN and .END targets have been read. 9448695518cSSimon J. Gerraty * This is done only if the -q flag wasn't given 9458695518cSSimon J. Gerraty * (to prevent the .BEGIN from being executed should 9468695518cSSimon J. Gerraty * it exist). 9478695518cSSimon J. Gerraty */ 948956e45f6SSimon J. Gerraty if (!opts.queryFlag) { 9498695518cSSimon J. Gerraty Job_Init(); 9508695518cSSimon J. Gerraty jobsRunning = TRUE; 9518695518cSSimon J. Gerraty } 9528695518cSSimon J. Gerraty 9538695518cSSimon J. Gerraty /* Traverse the graph, checking on all the targets */ 95406b9b3e0SSimon J. Gerraty outOfDate = Make_Run(&targs); 9558695518cSSimon J. Gerraty } else { 9568695518cSSimon J. Gerraty /* 9578695518cSSimon J. Gerraty * Compat_Init will take care of creating all the 9588695518cSSimon J. Gerraty * targets as well as initializing the module. 9598695518cSSimon J. Gerraty */ 96006b9b3e0SSimon J. Gerraty Compat_Run(&targs); 9618695518cSSimon J. Gerraty outOfDate = FALSE; 9628695518cSSimon J. Gerraty } 963*dba7b0efSSimon J. Gerraty Lst_Done(&targs); /* Don't free the targets themselves. */ 9648695518cSSimon J. Gerraty return outOfDate; 9658695518cSSimon J. Gerraty } 9668695518cSSimon J. Gerraty 967956e45f6SSimon J. Gerraty /* 968956e45f6SSimon J. Gerraty * Set up the .TARGETS variable to contain the list of targets to be 969956e45f6SSimon J. Gerraty * created. If none specified, make the variable empty -- the parser 970956e45f6SSimon J. Gerraty * will fill the thing in with the default or .MAIN target. 971956e45f6SSimon J. Gerraty */ 972956e45f6SSimon J. Gerraty static void 973956e45f6SSimon J. Gerraty InitVarTargets(void) 974956e45f6SSimon J. Gerraty { 975956e45f6SSimon J. Gerraty StringListNode *ln; 976956e45f6SSimon J. Gerraty 97706b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) { 978*dba7b0efSSimon J. Gerraty Global_Set(".TARGETS", ""); 979956e45f6SSimon J. Gerraty return; 980956e45f6SSimon J. Gerraty } 981956e45f6SSimon J. Gerraty 98206b9b3e0SSimon J. Gerraty for (ln = opts.create.first; ln != NULL; ln = ln->next) { 983*dba7b0efSSimon J. Gerraty const char *name = ln->datum; 984*dba7b0efSSimon J. Gerraty Global_Append(".TARGETS", name); 985956e45f6SSimon J. Gerraty } 986956e45f6SSimon J. Gerraty } 987956e45f6SSimon J. Gerraty 988956e45f6SSimon J. Gerraty static void 989956e45f6SSimon J. Gerraty InitRandom(void) 990956e45f6SSimon J. Gerraty { 991956e45f6SSimon J. Gerraty struct timeval tv; 992956e45f6SSimon J. Gerraty 993956e45f6SSimon J. Gerraty gettimeofday(&tv, NULL); 994956e45f6SSimon J. Gerraty srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 995956e45f6SSimon J. Gerraty } 996956e45f6SSimon J. Gerraty 997956e45f6SSimon J. Gerraty static const char * 998*dba7b0efSSimon J. Gerraty InitVarMachine(const struct utsname *utsname MAKE_ATTR_UNUSED) 999956e45f6SSimon J. Gerraty { 1000956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE 1001e2eeea75SSimon J. Gerraty return FORCE_MACHINE; 1002956e45f6SSimon J. Gerraty #else 1003956e45f6SSimon J. Gerraty const char *machine = getenv("MACHINE"); 1004e2eeea75SSimon J. Gerraty 1005956e45f6SSimon J. Gerraty if (machine != NULL) 1006956e45f6SSimon J. Gerraty return machine; 1007956e45f6SSimon J. Gerraty 1008e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE) 1009956e45f6SSimon J. Gerraty return utsname->machine; 1010e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE) 1011956e45f6SSimon J. Gerraty return MAKE_MACHINE; 1012956e45f6SSimon J. Gerraty #else 1013956e45f6SSimon J. Gerraty return "unknown"; 1014956e45f6SSimon J. Gerraty #endif 1015956e45f6SSimon J. Gerraty #endif 1016956e45f6SSimon J. Gerraty } 1017956e45f6SSimon J. Gerraty 1018956e45f6SSimon J. Gerraty static const char * 1019e2eeea75SSimon J. Gerraty InitVarMachineArch(void) 1020956e45f6SSimon J. Gerraty { 1021e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH 1022e2eeea75SSimon J. Gerraty return FORCE_MACHINE_ARCH; 1023e2eeea75SSimon J. Gerraty #else 1024956e45f6SSimon J. Gerraty const char *env = getenv("MACHINE_ARCH"); 1025956e45f6SSimon J. Gerraty if (env != NULL) 1026956e45f6SSimon J. Gerraty return env; 1027956e45f6SSimon J. Gerraty 1028956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW) 1029956e45f6SSimon J. Gerraty { 1030956e45f6SSimon J. Gerraty struct utsname utsname; 1031e2eeea75SSimon J. Gerraty static char machine_arch_buf[sizeof utsname.machine]; 1032956e45f6SSimon J. Gerraty const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1033e2eeea75SSimon J. Gerraty size_t len = sizeof machine_arch_buf; 1034956e45f6SSimon J. Gerraty 103506b9b3e0SSimon J. Gerraty if (sysctl(mib, (unsigned int)__arraycount(mib), 103606b9b3e0SSimon J. Gerraty machine_arch_buf, &len, NULL, 0) < 0) { 103706b9b3e0SSimon J. Gerraty (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 103806b9b3e0SSimon J. Gerraty progname, strerror(errno)); 1039956e45f6SSimon J. Gerraty exit(2); 1040956e45f6SSimon J. Gerraty } 1041956e45f6SSimon J. Gerraty 1042956e45f6SSimon J. Gerraty return machine_arch_buf; 1043956e45f6SSimon J. Gerraty } 1044e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH) 1045e2eeea75SSimon J. Gerraty return MACHINE_ARCH; 1046e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH) 1047956e45f6SSimon J. Gerraty return MAKE_MACHINE_ARCH; 1048956e45f6SSimon J. Gerraty #else 1049956e45f6SSimon J. Gerraty return "unknown"; 1050956e45f6SSimon J. Gerraty #endif 1051956e45f6SSimon J. Gerraty #endif 1052956e45f6SSimon J. Gerraty } 1053956e45f6SSimon J. Gerraty 1054956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE 1055956e45f6SSimon J. Gerraty /* 1056956e45f6SSimon J. Gerraty * All this code is so that we know where we are when we start up 1057956e45f6SSimon J. Gerraty * on a different machine with pmake. 1058956e45f6SSimon J. Gerraty * 1059*dba7b0efSSimon J. Gerraty * XXX: Make no longer has "local" and "remote" mode. Is this code still 1060*dba7b0efSSimon J. Gerraty * necessary? 1061*dba7b0efSSimon J. Gerraty * 1062956e45f6SSimon J. Gerraty * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1063956e45f6SSimon J. Gerraty * since the value of curdir can vary depending on how we got 1064956e45f6SSimon J. Gerraty * here. Ie sitting at a shell prompt (shell that provides $PWD) 1065956e45f6SSimon J. Gerraty * or via subdir.mk in which case its likely a shell which does 1066956e45f6SSimon J. Gerraty * not provide it. 1067956e45f6SSimon J. Gerraty * 1068956e45f6SSimon J. Gerraty * So, to stop it breaking this case only, we ignore PWD if 1069956e45f6SSimon J. Gerraty * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1070956e45f6SSimon J. Gerraty */ 1071956e45f6SSimon J. Gerraty static void 1072956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st) 1073956e45f6SSimon J. Gerraty { 1074956e45f6SSimon J. Gerraty char *pwd; 107506b9b3e0SSimon J. Gerraty FStr prefix, makeobjdir; 1076956e45f6SSimon J. Gerraty struct stat pwd_st; 1077956e45f6SSimon J. Gerraty 1078956e45f6SSimon J. Gerraty if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1079956e45f6SSimon J. Gerraty return; 1080956e45f6SSimon J. Gerraty 1081*dba7b0efSSimon J. Gerraty prefix = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIRPREFIX"); 108206b9b3e0SSimon J. Gerraty if (prefix.str != NULL) { 108306b9b3e0SSimon J. Gerraty FStr_Done(&prefix); 1084956e45f6SSimon J. Gerraty return; 1085956e45f6SSimon J. Gerraty } 1086956e45f6SSimon J. Gerraty 1087*dba7b0efSSimon J. Gerraty makeobjdir = Var_Value(SCOPE_CMDLINE, "MAKEOBJDIR"); 108806b9b3e0SSimon J. Gerraty if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1089956e45f6SSimon J. Gerraty goto ignore_pwd; 1090956e45f6SSimon J. Gerraty 1091956e45f6SSimon J. Gerraty if (stat(pwd, &pwd_st) == 0 && 1092956e45f6SSimon J. Gerraty curdir_st->st_ino == pwd_st.st_ino && 1093956e45f6SSimon J. Gerraty curdir_st->st_dev == pwd_st.st_dev) 1094956e45f6SSimon J. Gerraty (void)strncpy(curdir, pwd, MAXPATHLEN); 1095956e45f6SSimon J. Gerraty 1096956e45f6SSimon J. Gerraty ignore_pwd: 109706b9b3e0SSimon J. Gerraty FStr_Done(&makeobjdir); 1098956e45f6SSimon J. Gerraty } 1099956e45f6SSimon J. Gerraty #endif 1100956e45f6SSimon J. Gerraty 1101956e45f6SSimon J. Gerraty /* 1102956e45f6SSimon J. Gerraty * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1103956e45f6SSimon J. Gerraty * MAKEOBJDIR is set in the environment, try only that value 1104956e45f6SSimon J. Gerraty * and fall back to .CURDIR if it does not exist. 1105956e45f6SSimon J. Gerraty * 1106956e45f6SSimon J. Gerraty * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1107956e45f6SSimon J. Gerraty * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1108956e45f6SSimon J. Gerraty * of these paths exist, just use .CURDIR. 1109956e45f6SSimon J. Gerraty */ 1110956e45f6SSimon J. Gerraty static void 1111956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch) 1112956e45f6SSimon J. Gerraty { 1113e2eeea75SSimon J. Gerraty Boolean writable; 1114956e45f6SSimon J. Gerraty 111506b9b3e0SSimon J. Gerraty Dir_InitCur(curdir); 1116e2eeea75SSimon J. Gerraty writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE); 1117e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(FALSE, "%s", curdir); 1118e2eeea75SSimon J. Gerraty 1119e2eeea75SSimon J. Gerraty if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1120e2eeea75SSimon J. Gerraty !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1121e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1122e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1123e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1124e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1125956e45f6SSimon J. Gerraty } 1126956e45f6SSimon J. Gerraty 1127956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */ 1128956e45f6SSimon J. Gerraty static void 1129956e45f6SSimon J. Gerraty UnlimitFiles(void) 1130956e45f6SSimon J. Gerraty { 1131956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1132956e45f6SSimon J. Gerraty struct rlimit rl; 1133956e45f6SSimon J. Gerraty if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1134956e45f6SSimon J. Gerraty rl.rlim_cur != rl.rlim_max) { 1135956e45f6SSimon J. Gerraty rl.rlim_cur = rl.rlim_max; 1136956e45f6SSimon J. Gerraty (void)setrlimit(RLIMIT_NOFILE, &rl); 1137956e45f6SSimon J. Gerraty } 1138956e45f6SSimon J. Gerraty #endif 1139956e45f6SSimon J. Gerraty } 1140956e45f6SSimon J. Gerraty 1141956e45f6SSimon J. Gerraty static void 1142956e45f6SSimon J. Gerraty CmdOpts_Init(void) 1143956e45f6SSimon J. Gerraty { 114406b9b3e0SSimon J. Gerraty opts.compatMake = FALSE; 114506b9b3e0SSimon J. Gerraty opts.debug = DEBUG_NONE; 1146*dba7b0efSSimon J. Gerraty /* opts.debug_file has already been initialized earlier */ 114706b9b3e0SSimon J. Gerraty opts.strict = FALSE; 1148956e45f6SSimon J. Gerraty opts.debugVflag = FALSE; 1149956e45f6SSimon J. Gerraty opts.checkEnvFirst = FALSE; 115006b9b3e0SSimon J. Gerraty Lst_Init(&opts.makefiles); 1151956e45f6SSimon J. Gerraty opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 115206b9b3e0SSimon J. Gerraty opts.maxJobs = 1; 1153956e45f6SSimon J. Gerraty opts.keepgoing = FALSE; /* Stop on error */ 1154956e45f6SSimon J. Gerraty opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1155956e45f6SSimon J. Gerraty opts.noExecute = FALSE; /* Execute all commands */ 115606b9b3e0SSimon J. Gerraty opts.queryFlag = FALSE; 1157956e45f6SSimon J. Gerraty opts.noBuiltins = FALSE; /* Read the built-in rules */ 1158956e45f6SSimon J. Gerraty opts.beSilent = FALSE; /* Print commands as executed */ 115906b9b3e0SSimon J. Gerraty opts.touchFlag = FALSE; 1160e2eeea75SSimon J. Gerraty opts.printVars = PVM_NONE; 116106b9b3e0SSimon J. Gerraty Lst_Init(&opts.variables); 1162956e45f6SSimon J. Gerraty opts.parseWarnFatal = FALSE; 1163956e45f6SSimon J. Gerraty opts.enterFlag = FALSE; 1164956e45f6SSimon J. Gerraty opts.varNoExportEnv = FALSE; 116506b9b3e0SSimon J. Gerraty Lst_Init(&opts.create); 1166956e45f6SSimon J. Gerraty } 1167956e45f6SSimon J. Gerraty 116806b9b3e0SSimon J. Gerraty /* 116906b9b3e0SSimon J. Gerraty * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1170956e45f6SSimon J. Gerraty * found by execvp(3) and the shells, even after a chdir. 1171956e45f6SSimon J. Gerraty * 1172956e45f6SSimon J. Gerraty * If it's a relative path and contains a '/', resolve it to an absolute path. 117306b9b3e0SSimon J. Gerraty * Otherwise keep it as is, assuming it will be found in the PATH. 117406b9b3e0SSimon J. Gerraty */ 1175956e45f6SSimon J. Gerraty static void 1176956e45f6SSimon J. Gerraty InitVarMake(const char *argv0) 1177956e45f6SSimon J. Gerraty { 1178956e45f6SSimon J. Gerraty const char *make = argv0; 1179956e45f6SSimon J. Gerraty 1180956e45f6SSimon J. Gerraty if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1181956e45f6SSimon J. Gerraty char pathbuf[MAXPATHLEN]; 118206b9b3e0SSimon J. Gerraty const char *abspath = cached_realpath(argv0, pathbuf); 1183956e45f6SSimon J. Gerraty struct stat st; 118406b9b3e0SSimon J. Gerraty if (abspath != NULL && abspath[0] == '/' && 118506b9b3e0SSimon J. Gerraty stat(make, &st) == 0) 118606b9b3e0SSimon J. Gerraty make = abspath; 1187956e45f6SSimon J. Gerraty } 1188956e45f6SSimon J. Gerraty 1189*dba7b0efSSimon J. Gerraty Global_Set("MAKE", make); 1190*dba7b0efSSimon J. Gerraty Global_Set(".MAKE", make); 1191956e45f6SSimon J. Gerraty } 1192956e45f6SSimon J. Gerraty 119306b9b3e0SSimon J. Gerraty /* 119406b9b3e0SSimon J. Gerraty * Add the directories from the colon-separated syspath to defSysIncPath. 119506b9b3e0SSimon J. Gerraty * After returning, the contents of syspath is unspecified. 119606b9b3e0SSimon J. Gerraty */ 1197956e45f6SSimon J. Gerraty static void 1198956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath) 1199956e45f6SSimon J. Gerraty { 1200956e45f6SSimon J. Gerraty static char defsyspath[] = _PATH_DEFSYSPATH; 1201956e45f6SSimon J. Gerraty char *start, *cp; 1202956e45f6SSimon J. Gerraty 1203956e45f6SSimon J. Gerraty /* 1204956e45f6SSimon J. Gerraty * If no user-supplied system path was given (through the -m option) 1205956e45f6SSimon J. Gerraty * add the directories from the DEFSYSPATH (more than one may be given 1206956e45f6SSimon J. Gerraty * as dir1:...:dirn) to the system include path. 1207956e45f6SSimon J. Gerraty */ 1208956e45f6SSimon J. Gerraty if (syspath == NULL || syspath[0] == '\0') 1209956e45f6SSimon J. Gerraty syspath = defsyspath; 1210956e45f6SSimon J. Gerraty else 1211956e45f6SSimon J. Gerraty syspath = bmake_strdup(syspath); 1212956e45f6SSimon J. Gerraty 1213956e45f6SSimon J. Gerraty for (start = syspath; *start != '\0'; start = cp) { 1214956e45f6SSimon J. Gerraty for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1215956e45f6SSimon J. Gerraty continue; 1216e2eeea75SSimon J. Gerraty if (*cp == ':') 1217956e45f6SSimon J. Gerraty *cp++ = '\0'; 1218e2eeea75SSimon J. Gerraty 1219956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 1220e2eeea75SSimon J. Gerraty if (strncmp(start, ".../", 4) == 0) { 1221956e45f6SSimon J. Gerraty char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1222956e45f6SSimon J. Gerraty if (dir != NULL) { 1223*dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, dir); 1224956e45f6SSimon J. Gerraty free(dir); 1225956e45f6SSimon J. Gerraty } 1226e2eeea75SSimon J. Gerraty } else { 1227*dba7b0efSSimon J. Gerraty (void)SearchPath_Add(defSysIncPath, start); 1228956e45f6SSimon J. Gerraty } 1229956e45f6SSimon J. Gerraty } 1230956e45f6SSimon J. Gerraty 1231956e45f6SSimon J. Gerraty if (syspath != defsyspath) 1232956e45f6SSimon J. Gerraty free(syspath); 1233956e45f6SSimon J. Gerraty } 1234956e45f6SSimon J. Gerraty 1235956e45f6SSimon J. Gerraty static void 1236956e45f6SSimon J. Gerraty ReadBuiltinRules(void) 1237956e45f6SSimon J. Gerraty { 1238e2eeea75SSimon J. Gerraty StringListNode *ln; 1239*dba7b0efSSimon J. Gerraty StringList sysMkFiles = LST_INIT; 1240e2eeea75SSimon J. Gerraty 1241*dba7b0efSSimon J. Gerraty SearchPath_Expand( 1242*dba7b0efSSimon J. Gerraty Lst_IsEmpty(&sysIncPath->dirs) ? defSysIncPath : sysIncPath, 1243*dba7b0efSSimon J. Gerraty _PATH_DEFSYSMK, 1244*dba7b0efSSimon J. Gerraty &sysMkFiles); 1245*dba7b0efSSimon J. Gerraty if (Lst_IsEmpty(&sysMkFiles)) 1246956e45f6SSimon J. Gerraty Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1247e2eeea75SSimon J. Gerraty 1248*dba7b0efSSimon J. Gerraty for (ln = sysMkFiles.first; ln != NULL; ln = ln->next) 1249e2eeea75SSimon J. Gerraty if (ReadMakefile(ln->datum) == 0) 1250e2eeea75SSimon J. Gerraty break; 1251e2eeea75SSimon J. Gerraty 1252e2eeea75SSimon J. Gerraty if (ln == NULL) 1253e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", 1254*dba7b0efSSimon J. Gerraty progname, (const char *)sysMkFiles.first->datum); 1255e2eeea75SSimon J. Gerraty 1256*dba7b0efSSimon J. Gerraty /* Free the list nodes but not the actual filenames since these may 1257*dba7b0efSSimon J. Gerraty * still be used in GNodes. */ 1258*dba7b0efSSimon J. Gerraty Lst_Done(&sysMkFiles); 1259956e45f6SSimon J. Gerraty } 1260956e45f6SSimon J. Gerraty 1261956e45f6SSimon J. Gerraty static void 1262956e45f6SSimon J. Gerraty InitMaxJobs(void) 1263956e45f6SSimon J. Gerraty { 1264956e45f6SSimon J. Gerraty char *value; 1265956e45f6SSimon J. Gerraty int n; 1266956e45f6SSimon J. Gerraty 1267956e45f6SSimon J. Gerraty if (forceJobs || opts.compatMake || 1268*dba7b0efSSimon J. Gerraty !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) 1269956e45f6SSimon J. Gerraty return; 1270956e45f6SSimon J. Gerraty 1271*dba7b0efSSimon J. Gerraty (void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value); 1272956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1273956e45f6SSimon J. Gerraty n = (int)strtol(value, NULL, 0); 1274956e45f6SSimon J. Gerraty if (n < 1) { 1275956e45f6SSimon J. Gerraty (void)fprintf(stderr, 1276956e45f6SSimon J. Gerraty "%s: illegal value for .MAKE.JOBS " 1277956e45f6SSimon J. Gerraty "-- must be positive integer!\n", 1278956e45f6SSimon J. Gerraty progname); 127906b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 1280956e45f6SSimon J. Gerraty } 1281956e45f6SSimon J. Gerraty 1282956e45f6SSimon J. Gerraty if (n != opts.maxJobs) { 1283*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, "-j"); 1284*dba7b0efSSimon J. Gerraty Global_Append(MAKEFLAGS, value); 1285956e45f6SSimon J. Gerraty } 1286956e45f6SSimon J. Gerraty 1287956e45f6SSimon J. Gerraty opts.maxJobs = n; 1288956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1289956e45f6SSimon J. Gerraty forceJobs = TRUE; 1290956e45f6SSimon J. Gerraty free(value); 1291956e45f6SSimon J. Gerraty } 1292956e45f6SSimon J. Gerraty 1293956e45f6SSimon J. Gerraty /* 1294956e45f6SSimon J. Gerraty * For compatibility, look at the directories in the VPATH variable 1295956e45f6SSimon J. Gerraty * and add them to the search path, if the variable is defined. The 1296956e45f6SSimon J. Gerraty * variable's value is in the same format as the PATH environment 1297956e45f6SSimon J. Gerraty * variable, i.e. <directory>:<directory>:<directory>... 1298956e45f6SSimon J. Gerraty */ 1299956e45f6SSimon J. Gerraty static void 1300956e45f6SSimon J. Gerraty InitVpath(void) 1301956e45f6SSimon J. Gerraty { 1302956e45f6SSimon J. Gerraty char *vpath, savec, *path; 1303*dba7b0efSSimon J. Gerraty if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) 1304956e45f6SSimon J. Gerraty return; 1305956e45f6SSimon J. Gerraty 1306*dba7b0efSSimon J. Gerraty (void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath); 1307956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1308956e45f6SSimon J. Gerraty path = vpath; 1309956e45f6SSimon J. Gerraty do { 1310956e45f6SSimon J. Gerraty char *cp; 1311956e45f6SSimon J. Gerraty /* skip to end of directory */ 1312956e45f6SSimon J. Gerraty for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1313956e45f6SSimon J. Gerraty continue; 1314956e45f6SSimon J. Gerraty /* Save terminator character so know when to stop */ 1315956e45f6SSimon J. Gerraty savec = *cp; 1316956e45f6SSimon J. Gerraty *cp = '\0'; 1317956e45f6SSimon J. Gerraty /* Add directory to search path */ 1318*dba7b0efSSimon J. Gerraty (void)SearchPath_Add(&dirSearchPath, path); 1319956e45f6SSimon J. Gerraty *cp = savec; 1320956e45f6SSimon J. Gerraty path = cp + 1; 1321956e45f6SSimon J. Gerraty } while (savec == ':'); 1322956e45f6SSimon J. Gerraty free(vpath); 1323956e45f6SSimon J. Gerraty } 1324956e45f6SSimon J. Gerraty 1325956e45f6SSimon J. Gerraty static void 1326e2eeea75SSimon J. Gerraty ReadAllMakefiles(StringList *makefiles) 1327956e45f6SSimon J. Gerraty { 1328956e45f6SSimon J. Gerraty StringListNode *ln; 1329956e45f6SSimon J. Gerraty 1330e2eeea75SSimon J. Gerraty for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1331e2eeea75SSimon J. Gerraty const char *fname = ln->datum; 1332e2eeea75SSimon J. Gerraty if (ReadMakefile(fname) != 0) 1333e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", progname, fname); 1334956e45f6SSimon J. Gerraty } 1335956e45f6SSimon J. Gerraty } 1336956e45f6SSimon J. Gerraty 1337956e45f6SSimon J. Gerraty static void 1338e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void) 1339956e45f6SSimon J. Gerraty { 1340e2eeea75SSimon J. Gerraty StringListNode *ln; 1341e2eeea75SSimon J. Gerraty char *prefs; 1342956e45f6SSimon J. Gerraty 1343e2eeea75SSimon J. Gerraty (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", 1344*dba7b0efSSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES, &prefs); 1345e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 1346956e45f6SSimon J. Gerraty 1347e2eeea75SSimon J. Gerraty /* XXX: This should use a local list instead of opts.makefiles 1348e2eeea75SSimon J. Gerraty * since these makefiles do not come from the command line. They 1349e2eeea75SSimon J. Gerraty * also have different semantics in that only the first file that 1350e2eeea75SSimon J. Gerraty * is found is processed. See ReadAllMakefiles. */ 135106b9b3e0SSimon J. Gerraty (void)str2Lst_Append(&opts.makefiles, prefs); 1352956e45f6SSimon J. Gerraty 135306b9b3e0SSimon J. Gerraty for (ln = opts.makefiles.first; ln != NULL; ln = ln->next) 1354e2eeea75SSimon J. Gerraty if (ReadMakefile(ln->datum) == 0) 1355e2eeea75SSimon J. Gerraty break; 1356956e45f6SSimon J. Gerraty 1357e2eeea75SSimon J. Gerraty free(prefs); 1358956e45f6SSimon J. Gerraty } 1359956e45f6SSimon J. Gerraty 136006b9b3e0SSimon J. Gerraty /* 136106b9b3e0SSimon J. Gerraty * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1362e2eeea75SSimon J. Gerraty * Initialize a few modules. 136306b9b3e0SSimon J. Gerraty * Parse the arguments from MAKEFLAGS and the command line. 136406b9b3e0SSimon J. Gerraty */ 1365e2eeea75SSimon J. Gerraty static void 1366e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv) 13673955d011SMarcel Moolenaar { 1368956e45f6SSimon J. Gerraty struct stat sa; 1369956e45f6SSimon J. Gerraty const char *machine; 1370956e45f6SSimon J. Gerraty const char *machine_arch; 13713955d011SMarcel Moolenaar char *syspath = getenv("MAKESYSPATH"); 13723955d011SMarcel Moolenaar struct utsname utsname; 13733955d011SMarcel Moolenaar 13743955d011SMarcel Moolenaar /* default to writing debug to stderr */ 1375956e45f6SSimon J. Gerraty opts.debug_file = stderr; 13763955d011SMarcel Moolenaar 1377e2eeea75SSimon J. Gerraty HashTable_Init(&cached_realpaths); 1378e2eeea75SSimon J. Gerraty 13793955d011SMarcel Moolenaar #ifdef SIGINFO 13803955d011SMarcel Moolenaar (void)bmake_signal(SIGINFO, siginfo); 13813955d011SMarcel Moolenaar #endif 1382956e45f6SSimon J. Gerraty 1383956e45f6SSimon J. Gerraty InitRandom(); 13843955d011SMarcel Moolenaar 138506b9b3e0SSimon J. Gerraty progname = str_basename(argv[0]); 1386956e45f6SSimon J. Gerraty 1387956e45f6SSimon J. Gerraty UnlimitFiles(); 13883955d011SMarcel Moolenaar 13891748de26SSimon J. Gerraty if (uname(&utsname) == -1) { 13901748de26SSimon J. Gerraty (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 13911748de26SSimon J. Gerraty strerror(errno)); 13921748de26SSimon J. Gerraty exit(2); 13931748de26SSimon J. Gerraty } 13941748de26SSimon J. Gerraty 13953955d011SMarcel Moolenaar /* 13963955d011SMarcel Moolenaar * Get the name of this type of MACHINE from utsname 13973955d011SMarcel Moolenaar * so we can share an executable for similar machines. 13983955d011SMarcel Moolenaar * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 13993955d011SMarcel Moolenaar * 14003955d011SMarcel Moolenaar * Note that both MACHINE and MACHINE_ARCH are decided at 14013955d011SMarcel Moolenaar * run-time. 14023955d011SMarcel Moolenaar */ 1403e2eeea75SSimon J. Gerraty machine = InitVarMachine(&utsname); 1404e2eeea75SSimon J. Gerraty machine_arch = InitVarMachineArch(); 14053955d011SMarcel Moolenaar 14063955d011SMarcel Moolenaar myPid = getpid(); /* remember this for vFork() */ 14073955d011SMarcel Moolenaar 14083955d011SMarcel Moolenaar /* 14093955d011SMarcel Moolenaar * Just in case MAKEOBJDIR wants us to do something tricky. 14103955d011SMarcel Moolenaar */ 1411e2eeea75SSimon J. Gerraty Targ_Init(); 1412e2eeea75SSimon J. Gerraty Var_Init(); 1413*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.OS", utsname.sysname); 1414*dba7b0efSSimon J. Gerraty Global_Set("MACHINE", machine); 1415*dba7b0efSSimon J. Gerraty Global_Set("MACHINE_ARCH", machine_arch); 14163955d011SMarcel Moolenaar #ifdef MAKE_VERSION 1417*dba7b0efSSimon J. Gerraty Global_Set("MAKE_VERSION", MAKE_VERSION); 14183955d011SMarcel Moolenaar #endif 1419*dba7b0efSSimon J. Gerraty Global_Set(".newline", "\n"); /* handy for :@ loops */ 14203955d011SMarcel Moolenaar /* 14213955d011SMarcel Moolenaar * This is the traditional preference for makefiles. 14223955d011SMarcel Moolenaar */ 14233955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST 14243955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 14253955d011SMarcel Moolenaar #endif 1426*dba7b0efSSimon J. Gerraty Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST); 1427*dba7b0efSSimon J. Gerraty Global_Set(MAKE_DEPENDFILE, ".depend"); 14283955d011SMarcel Moolenaar 1429956e45f6SSimon J. Gerraty CmdOpts_Init(); 14303955d011SMarcel Moolenaar allPrecious = FALSE; /* Remove targets when interrupted */ 143145447996SSimon J. Gerraty deleteOnError = FALSE; /* Historical default behavior */ 14323955d011SMarcel Moolenaar jobsRunning = FALSE; 14333955d011SMarcel Moolenaar 1434956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 14353955d011SMarcel Moolenaar ignorePWD = FALSE; 14363955d011SMarcel Moolenaar 14373955d011SMarcel Moolenaar /* 14383955d011SMarcel Moolenaar * Initialize the parsing, directory and variable modules to prepare 14393955d011SMarcel Moolenaar * for the reading of inclusion paths and variable settings on the 14403955d011SMarcel Moolenaar * command line 14413955d011SMarcel Moolenaar */ 14423955d011SMarcel Moolenaar 14433955d011SMarcel Moolenaar /* 14443955d011SMarcel Moolenaar * Initialize various variables. 14453955d011SMarcel Moolenaar * MAKE also gets this name, for compatibility 14463955d011SMarcel Moolenaar * .MAKEFLAGS gets set to the empty string just in case. 14473955d011SMarcel Moolenaar * MFLAGS also gets initialized empty, for compatibility. 14483955d011SMarcel Moolenaar */ 14493955d011SMarcel Moolenaar Parse_Init(); 1450956e45f6SSimon J. Gerraty InitVarMake(argv[0]); 1451*dba7b0efSSimon J. Gerraty Global_Set(MAKEFLAGS, ""); 1452*dba7b0efSSimon J. Gerraty Global_Set(MAKEOVERRIDES, ""); 1453*dba7b0efSSimon J. Gerraty Global_Set("MFLAGS", ""); 1454*dba7b0efSSimon J. Gerraty Global_Set(".ALLTARGETS", ""); 145551ee2c1cSSimon J. Gerraty /* some makefiles need to know this */ 1456*dba7b0efSSimon J. Gerraty Var_Set(SCOPE_CMDLINE, MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV); 14573955d011SMarcel Moolenaar 1458e2eeea75SSimon J. Gerraty /* Set some other useful variables. */ 14593955d011SMarcel Moolenaar { 1460e2eeea75SSimon J. Gerraty char tmp[64], *ep = getenv(MAKE_LEVEL_ENV); 14613955d011SMarcel Moolenaar 1462e2eeea75SSimon J. Gerraty makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 146351ee2c1cSSimon J. Gerraty if (makelevel < 0) 146451ee2c1cSSimon J. Gerraty makelevel = 0; 1465e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%d", makelevel); 1466*dba7b0efSSimon J. Gerraty Global_Set(MAKE_LEVEL, tmp); 1467e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", myPid); 1468*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.PID", tmp); 1469e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getppid()); 1470*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.PPID", tmp); 147106b9b3e0SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getuid()); 1472*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.UID", tmp); 147306b9b3e0SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getgid()); 1474*dba7b0efSSimon J. Gerraty Global_Set(".MAKE.GID", tmp); 14753955d011SMarcel Moolenaar } 147651ee2c1cSSimon J. Gerraty if (makelevel > 0) { 147751ee2c1cSSimon J. Gerraty char pn[1024]; 1478e2eeea75SSimon J. Gerraty snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 147951ee2c1cSSimon J. Gerraty progname = bmake_strdup(pn); 148051ee2c1cSSimon J. Gerraty } 14813955d011SMarcel Moolenaar 14821748de26SSimon J. Gerraty #ifdef USE_META 14831748de26SSimon J. Gerraty meta_init(); 14841748de26SSimon J. Gerraty #endif 14852c3632d1SSimon J. Gerraty Dir_Init(); 14861ce939a7SSimon J. Gerraty 14873955d011SMarcel Moolenaar /* 14883955d011SMarcel Moolenaar * First snag any flags out of the MAKE environment variable. 14893955d011SMarcel Moolenaar * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 14903955d011SMarcel Moolenaar * in a different format). 14913955d011SMarcel Moolenaar */ 14923955d011SMarcel Moolenaar #ifdef POSIX 1493956e45f6SSimon J. Gerraty { 1494956e45f6SSimon J. Gerraty char *p1 = explode(getenv("MAKEFLAGS")); 149551ee2c1cSSimon J. Gerraty Main_ParseArgLine(p1); 149651ee2c1cSSimon J. Gerraty free(p1); 1497956e45f6SSimon J. Gerraty } 14983955d011SMarcel Moolenaar #else 14993955d011SMarcel Moolenaar Main_ParseArgLine(getenv("MAKE")); 15003955d011SMarcel Moolenaar #endif 15013955d011SMarcel Moolenaar 15023955d011SMarcel Moolenaar /* 15033955d011SMarcel Moolenaar * Find where we are (now). 15043955d011SMarcel Moolenaar * We take care of PWD for the automounter below... 15053955d011SMarcel Moolenaar */ 15063955d011SMarcel Moolenaar if (getcwd(curdir, MAXPATHLEN) == NULL) { 15073955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: getcwd: %s.\n", 15083955d011SMarcel Moolenaar progname, strerror(errno)); 15093955d011SMarcel Moolenaar exit(2); 15103955d011SMarcel Moolenaar } 15113955d011SMarcel Moolenaar 15123955d011SMarcel Moolenaar MainParseArgs(argc, argv); 15133955d011SMarcel Moolenaar 1514956e45f6SSimon J. Gerraty if (opts.enterFlag) 151551ee2c1cSSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, curdir); 151651ee2c1cSSimon J. Gerraty 15173955d011SMarcel Moolenaar /* 15183955d011SMarcel Moolenaar * Verify that cwd is sane. 15193955d011SMarcel Moolenaar */ 15203955d011SMarcel Moolenaar if (stat(curdir, &sa) == -1) { 15213955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: %s: %s.\n", 15223955d011SMarcel Moolenaar progname, curdir, strerror(errno)); 15233955d011SMarcel Moolenaar exit(2); 15243955d011SMarcel Moolenaar } 15253955d011SMarcel Moolenaar 15263955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE 1527956e45f6SSimon J. Gerraty HandlePWD(&sa); 15283955d011SMarcel Moolenaar #endif 1529*dba7b0efSSimon J. Gerraty Global_Set(".CURDIR", curdir); 15303955d011SMarcel Moolenaar 1531956e45f6SSimon J. Gerraty InitObjdir(machine, machine_arch); 15323955d011SMarcel Moolenaar 15333955d011SMarcel Moolenaar /* 15343955d011SMarcel Moolenaar * Initialize archive, target and suffix modules in preparation for 15353955d011SMarcel Moolenaar * parsing the makefile(s) 15363955d011SMarcel Moolenaar */ 15373955d011SMarcel Moolenaar Arch_Init(); 15383955d011SMarcel Moolenaar Suff_Init(); 15393955d011SMarcel Moolenaar Trace_Init(tracefile); 15403955d011SMarcel Moolenaar 1541e2eeea75SSimon J. Gerraty defaultNode = NULL; 15423955d011SMarcel Moolenaar (void)time(&now); 15433955d011SMarcel Moolenaar 15443955d011SMarcel Moolenaar Trace_Log(MAKESTART, NULL); 15453955d011SMarcel Moolenaar 1546956e45f6SSimon J. Gerraty InitVarTargets(); 15473955d011SMarcel Moolenaar 1548956e45f6SSimon J. Gerraty InitDefSysIncPath(syspath); 1549e2eeea75SSimon J. Gerraty } 15503955d011SMarcel Moolenaar 155106b9b3e0SSimon J. Gerraty /* 155206b9b3e0SSimon J. Gerraty * Read the system makefile followed by either makefile, Makefile or the 155306b9b3e0SSimon J. Gerraty * files given by the -f option. Exit on parse errors. 155406b9b3e0SSimon J. Gerraty */ 1555e2eeea75SSimon J. Gerraty static void 1556e2eeea75SSimon J. Gerraty main_ReadFiles(void) 1557e2eeea75SSimon J. Gerraty { 1558e2eeea75SSimon J. Gerraty 1559956e45f6SSimon J. Gerraty if (!opts.noBuiltins) 1560956e45f6SSimon J. Gerraty ReadBuiltinRules(); 15613955d011SMarcel Moolenaar 156206b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&opts.makefiles)) 156306b9b3e0SSimon J. Gerraty ReadAllMakefiles(&opts.makefiles); 1564e2eeea75SSimon J. Gerraty else 1565e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(); 1566e2eeea75SSimon J. Gerraty } 1567e2eeea75SSimon J. Gerraty 1568e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */ 1569e2eeea75SSimon J. Gerraty static void 1570e2eeea75SSimon J. Gerraty main_PrepareMaking(void) 1571e2eeea75SSimon J. Gerraty { 15723955d011SMarcel Moolenaar /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1573e2eeea75SSimon J. Gerraty if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 157406b9b3e0SSimon J. Gerraty (void)Var_Subst("${.MAKE.DEPENDFILE}", 1575*dba7b0efSSimon J. Gerraty SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile); 1576956e45f6SSimon J. Gerraty if (makeDependfile[0] != '\0') { 1577956e45f6SSimon J. Gerraty /* TODO: handle errors */ 15783955d011SMarcel Moolenaar doing_depend = TRUE; 15792c3632d1SSimon J. Gerraty (void)ReadMakefile(makeDependfile); 15803955d011SMarcel Moolenaar doing_depend = FALSE; 15813955d011SMarcel Moolenaar } 1582956e45f6SSimon J. Gerraty } 15833955d011SMarcel Moolenaar 15844c620fe5SSimon J. Gerraty if (enterFlagObj) 15854c620fe5SSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, objdir); 15864c620fe5SSimon J. Gerraty 158706b9b3e0SSimon J. Gerraty MakeMode(); 15883955d011SMarcel Moolenaar 1589956e45f6SSimon J. Gerraty { 1590*dba7b0efSSimon J. Gerraty FStr makeflags = Var_Value(SCOPE_GLOBAL, MAKEFLAGS); 1591*dba7b0efSSimon J. Gerraty Global_Append("MFLAGS", makeflags.str); 159206b9b3e0SSimon J. Gerraty FStr_Done(&makeflags); 1593956e45f6SSimon J. Gerraty } 1594e48f47ddSSimon J. Gerraty 1595956e45f6SSimon J. Gerraty InitMaxJobs(); 1596e48f47ddSSimon J. Gerraty 1597e48f47ddSSimon J. Gerraty /* 1598e2eeea75SSimon J. Gerraty * Be compatible if the user did not specify -j and did not explicitly 1599e2eeea75SSimon J. Gerraty * turn compatibility on. 1600e48f47ddSSimon J. Gerraty */ 1601e2eeea75SSimon J. Gerraty if (!opts.compatMake && !forceJobs) 1602956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 1603e48f47ddSSimon J. Gerraty 1604956e45f6SSimon J. Gerraty if (!opts.compatMake) 16053955d011SMarcel Moolenaar Job_ServerStart(maxJobTokens, jp_0, jp_1); 1606956e45f6SSimon J. Gerraty DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1607956e45f6SSimon J. Gerraty jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 16083955d011SMarcel Moolenaar 1609e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_NONE) 16103955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(TRUE); /* initial export */ 16113955d011SMarcel Moolenaar 1612956e45f6SSimon J. Gerraty InitVpath(); 16133955d011SMarcel Moolenaar 16143955d011SMarcel Moolenaar /* 16153955d011SMarcel Moolenaar * Now that all search paths have been read for suffixes et al, it's 16163955d011SMarcel Moolenaar * time to add the default search path to their lists... 16173955d011SMarcel Moolenaar */ 16183955d011SMarcel Moolenaar Suff_DoPaths(); 16193955d011SMarcel Moolenaar 16203955d011SMarcel Moolenaar /* 16213955d011SMarcel Moolenaar * Propagate attributes through :: dependency lists. 16223955d011SMarcel Moolenaar */ 16233955d011SMarcel Moolenaar Targ_Propagate(); 16243955d011SMarcel Moolenaar 16253955d011SMarcel Moolenaar /* print the initial graph, if the user requested it */ 16263955d011SMarcel Moolenaar if (DEBUG(GRAPH1)) 16273955d011SMarcel Moolenaar Targ_PrintGraph(1); 16283955d011SMarcel Moolenaar } 16293955d011SMarcel Moolenaar 163006b9b3e0SSimon J. Gerraty /* 163106b9b3e0SSimon J. Gerraty * Make the targets. 1632e2eeea75SSimon J. Gerraty * If the -v or -V options are given, print variables instead. 163306b9b3e0SSimon J. Gerraty * Return whether any of the targets is out-of-date. 163406b9b3e0SSimon J. Gerraty */ 1635e2eeea75SSimon J. Gerraty static Boolean 1636e2eeea75SSimon J. Gerraty main_Run(void) 1637e2eeea75SSimon J. Gerraty { 1638e2eeea75SSimon J. Gerraty if (opts.printVars != PVM_NONE) { 1639e2eeea75SSimon J. Gerraty /* print the values of any variables requested by the user */ 1640e2eeea75SSimon J. Gerraty doPrintVars(); 1641e2eeea75SSimon J. Gerraty return FALSE; 1642e2eeea75SSimon J. Gerraty } else { 1643e2eeea75SSimon J. Gerraty return runTargets(); 1644e2eeea75SSimon J. Gerraty } 1645e2eeea75SSimon J. Gerraty } 16463955d011SMarcel Moolenaar 1647e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */ 1648e2eeea75SSimon J. Gerraty static void 1649e2eeea75SSimon J. Gerraty main_CleanUp(void) 1650e2eeea75SSimon J. Gerraty { 1651e2eeea75SSimon J. Gerraty #ifdef CLEANUP 165206b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.variables, free); 165306b9b3e0SSimon J. Gerraty /* 165406b9b3e0SSimon J. Gerraty * Don't free the actual strings from opts.makefiles, they may be 165506b9b3e0SSimon J. Gerraty * used in GNodes. 165606b9b3e0SSimon J. Gerraty */ 165706b9b3e0SSimon J. Gerraty Lst_Done(&opts.makefiles); 165806b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.create, free); 1659e2eeea75SSimon J. Gerraty #endif 1660e2eeea75SSimon J. Gerraty 1661e2eeea75SSimon J. Gerraty /* print the graph now it's been processed if the user requested it */ 1662e2eeea75SSimon J. Gerraty if (DEBUG(GRAPH2)) 1663e2eeea75SSimon J. Gerraty Targ_PrintGraph(2); 1664e2eeea75SSimon J. Gerraty 1665e2eeea75SSimon J. Gerraty Trace_Log(MAKEEND, NULL); 1666e2eeea75SSimon J. Gerraty 1667e2eeea75SSimon J. Gerraty if (enterFlagObj) 1668e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, objdir); 1669e2eeea75SSimon J. Gerraty if (opts.enterFlag) 1670e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, curdir); 1671e2eeea75SSimon J. Gerraty 1672e2eeea75SSimon J. Gerraty #ifdef USE_META 1673e2eeea75SSimon J. Gerraty meta_finish(); 1674e2eeea75SSimon J. Gerraty #endif 1675e2eeea75SSimon J. Gerraty Suff_End(); 1676e2eeea75SSimon J. Gerraty Targ_End(); 1677e2eeea75SSimon J. Gerraty Arch_End(); 1678e2eeea75SSimon J. Gerraty Var_End(); 1679e2eeea75SSimon J. Gerraty Parse_End(); 1680e2eeea75SSimon J. Gerraty Dir_End(); 1681e2eeea75SSimon J. Gerraty Job_End(); 1682e2eeea75SSimon J. Gerraty Trace_End(); 1683e2eeea75SSimon J. Gerraty } 1684e2eeea75SSimon J. Gerraty 1685e2eeea75SSimon J. Gerraty /* Determine the exit code. */ 1686e2eeea75SSimon J. Gerraty static int 1687e2eeea75SSimon J. Gerraty main_Exit(Boolean outOfDate) 1688e2eeea75SSimon J. Gerraty { 168906b9b3e0SSimon J. Gerraty if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0)) 1690956e45f6SSimon J. Gerraty return 2; /* Not 1 so -q can distinguish error */ 16913955d011SMarcel Moolenaar return outOfDate ? 1 : 0; 16923955d011SMarcel Moolenaar } 16933955d011SMarcel Moolenaar 1694e2eeea75SSimon J. Gerraty int 1695e2eeea75SSimon J. Gerraty main(int argc, char **argv) 1696e2eeea75SSimon J. Gerraty { 1697e2eeea75SSimon J. Gerraty Boolean outOfDate; 1698e2eeea75SSimon J. Gerraty 1699e2eeea75SSimon J. Gerraty main_Init(argc, argv); 1700e2eeea75SSimon J. Gerraty main_ReadFiles(); 1701e2eeea75SSimon J. Gerraty main_PrepareMaking(); 1702e2eeea75SSimon J. Gerraty outOfDate = main_Run(); 1703e2eeea75SSimon J. Gerraty main_CleanUp(); 1704e2eeea75SSimon J. Gerraty return main_Exit(outOfDate); 1705e2eeea75SSimon J. Gerraty } 1706e2eeea75SSimon J. Gerraty 170706b9b3e0SSimon J. Gerraty /* 170806b9b3e0SSimon J. Gerraty * Open and parse the given makefile, with all its side effects. 17093955d011SMarcel Moolenaar * 17103955d011SMarcel Moolenaar * Results: 17113955d011SMarcel Moolenaar * 0 if ok. -1 if couldn't open file. 17123955d011SMarcel Moolenaar */ 17133955d011SMarcel Moolenaar static int 17142c3632d1SSimon J. Gerraty ReadMakefile(const char *fname) 17153955d011SMarcel Moolenaar { 17163955d011SMarcel Moolenaar int fd; 17172c3632d1SSimon J. Gerraty char *name, *path = NULL; 17183955d011SMarcel Moolenaar 1719e2eeea75SSimon J. Gerraty if (strcmp(fname, "-") == 0) { 17203955d011SMarcel Moolenaar Parse_File(NULL /*stdin*/, -1); 1721*dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", ""); 17223955d011SMarcel Moolenaar } else { 17233955d011SMarcel Moolenaar /* if we've chdir'd, rebuild the path name */ 1724e2eeea75SSimon J. Gerraty if (strcmp(curdir, objdir) != 0 && *fname != '/') { 17252c3632d1SSimon J. Gerraty path = str_concat3(curdir, "/", fname); 17263955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 17273955d011SMarcel Moolenaar if (fd != -1) { 17283955d011SMarcel Moolenaar fname = path; 17293955d011SMarcel Moolenaar goto found; 17303955d011SMarcel Moolenaar } 17312c3632d1SSimon J. Gerraty free(path); 17323955d011SMarcel Moolenaar 17333955d011SMarcel Moolenaar /* If curdir failed, try objdir (ala .depend) */ 17342c3632d1SSimon J. Gerraty path = str_concat3(objdir, "/", fname); 17353955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 17363955d011SMarcel Moolenaar if (fd != -1) { 17373955d011SMarcel Moolenaar fname = path; 17383955d011SMarcel Moolenaar goto found; 17393955d011SMarcel Moolenaar } 17403955d011SMarcel Moolenaar } else { 17413955d011SMarcel Moolenaar fd = open(fname, O_RDONLY); 17423955d011SMarcel Moolenaar if (fd != -1) 17433955d011SMarcel Moolenaar goto found; 17443955d011SMarcel Moolenaar } 17453955d011SMarcel Moolenaar /* look in -I and system include directories. */ 17463955d011SMarcel Moolenaar name = Dir_FindFile(fname, parseIncPath); 1747e2eeea75SSimon J. Gerraty if (name == NULL) { 1748*dba7b0efSSimon J. Gerraty SearchPath *sysInc = Lst_IsEmpty(&sysIncPath->dirs) 1749956e45f6SSimon J. Gerraty ? defSysIncPath : sysIncPath; 1750956e45f6SSimon J. Gerraty name = Dir_FindFile(fname, sysInc); 1751956e45f6SSimon J. Gerraty } 1752e2eeea75SSimon J. Gerraty if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 17533955d011SMarcel Moolenaar free(name); 17543955d011SMarcel Moolenaar free(path); 17553841c287SSimon J. Gerraty return -1; 17563955d011SMarcel Moolenaar } 17573955d011SMarcel Moolenaar fname = name; 17583955d011SMarcel Moolenaar /* 17593955d011SMarcel Moolenaar * set the MAKEFILE variable desired by System V fans -- the 17603955d011SMarcel Moolenaar * placement of the setting here means it gets set to the last 17613955d011SMarcel Moolenaar * makefile specified, as it is set by SysV make. 17623955d011SMarcel Moolenaar */ 17633955d011SMarcel Moolenaar found: 17643955d011SMarcel Moolenaar if (!doing_depend) 1765*dba7b0efSSimon J. Gerraty Var_Set(SCOPE_INTERNAL, "MAKEFILE", fname); 17663955d011SMarcel Moolenaar Parse_File(fname, fd); 17673955d011SMarcel Moolenaar } 17683955d011SMarcel Moolenaar free(path); 17693841c287SSimon J. Gerraty return 0; 17703955d011SMarcel Moolenaar } 17713955d011SMarcel Moolenaar 1772*dba7b0efSSimon J. Gerraty /* 17733955d011SMarcel Moolenaar * Cmd_Exec -- 17743955d011SMarcel Moolenaar * Execute the command in cmd, and return the output of that command 17752c3632d1SSimon J. Gerraty * in a string. In the output, newlines are replaced with spaces. 17763955d011SMarcel Moolenaar * 17773955d011SMarcel Moolenaar * Results: 17782c3632d1SSimon J. Gerraty * A string containing the output of the command, or the empty string. 17792c3632d1SSimon J. Gerraty * *errfmt returns a format string describing the command failure, 17802c3632d1SSimon J. Gerraty * if any, using a single %s conversion specification. 17813955d011SMarcel Moolenaar * 17823955d011SMarcel Moolenaar * Side Effects: 17833955d011SMarcel Moolenaar * The string must be freed by the caller. 17843955d011SMarcel Moolenaar */ 17853955d011SMarcel Moolenaar char * 17862c3632d1SSimon J. Gerraty Cmd_Exec(const char *cmd, const char **errfmt) 17873955d011SMarcel Moolenaar { 17883955d011SMarcel Moolenaar const char *args[4]; /* Args for invoking the shell */ 178906b9b3e0SSimon J. Gerraty int pipefds[2]; 17903955d011SMarcel Moolenaar int cpid; /* Child PID */ 17913955d011SMarcel Moolenaar int pid; /* PID from wait() */ 1792e2eeea75SSimon J. Gerraty int status; /* command exit status */ 17933955d011SMarcel Moolenaar Buffer buf; /* buffer to store the result */ 17942c3632d1SSimon J. Gerraty ssize_t bytes_read; 17952c3632d1SSimon J. Gerraty char *res; /* result */ 17962c3632d1SSimon J. Gerraty size_t res_len; 17973955d011SMarcel Moolenaar char *cp; 1798db29cad8SSimon J. Gerraty int savederr; /* saved errno */ 17993955d011SMarcel Moolenaar 18002c3632d1SSimon J. Gerraty *errfmt = NULL; 18013955d011SMarcel Moolenaar 180206b9b3e0SSimon J. Gerraty if (shellName == NULL) 18033955d011SMarcel Moolenaar Shell_Init(); 18043955d011SMarcel Moolenaar /* 18053955d011SMarcel Moolenaar * Set up arguments for shell 18063955d011SMarcel Moolenaar */ 18073955d011SMarcel Moolenaar args[0] = shellName; 18083955d011SMarcel Moolenaar args[1] = "-c"; 18093955d011SMarcel Moolenaar args[2] = cmd; 18103955d011SMarcel Moolenaar args[3] = NULL; 18113955d011SMarcel Moolenaar 18123955d011SMarcel Moolenaar /* 18133955d011SMarcel Moolenaar * Open a pipe for fetching its output 18143955d011SMarcel Moolenaar */ 181506b9b3e0SSimon J. Gerraty if (pipe(pipefds) == -1) { 18162c3632d1SSimon J. Gerraty *errfmt = "Couldn't create pipe for \"%s\""; 18173955d011SMarcel Moolenaar goto bad; 18183955d011SMarcel Moolenaar } 18193955d011SMarcel Moolenaar 182006b9b3e0SSimon J. Gerraty Var_ReexportVars(); 182106b9b3e0SSimon J. Gerraty 18223955d011SMarcel Moolenaar /* 18233955d011SMarcel Moolenaar * Fork 18243955d011SMarcel Moolenaar */ 1825*dba7b0efSSimon J. Gerraty switch (cpid = vfork()) { 18263955d011SMarcel Moolenaar case 0: 182706b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close input side of pipe */ 18283955d011SMarcel Moolenaar 18293955d011SMarcel Moolenaar /* 18303955d011SMarcel Moolenaar * Duplicate the output stream to the shell's output, then 18313955d011SMarcel Moolenaar * shut the extra thing down. Note we don't fetch the error 18323955d011SMarcel Moolenaar * stream...why not? Why? 18333955d011SMarcel Moolenaar */ 183406b9b3e0SSimon J. Gerraty (void)dup2(pipefds[1], 1); 183506b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); 18363955d011SMarcel Moolenaar 18373955d011SMarcel Moolenaar (void)execv(shellPath, UNCONST(args)); 18383955d011SMarcel Moolenaar _exit(1); 18393955d011SMarcel Moolenaar /*NOTREACHED*/ 18403955d011SMarcel Moolenaar 18413955d011SMarcel Moolenaar case -1: 18422c3632d1SSimon J. Gerraty *errfmt = "Couldn't exec \"%s\""; 18433955d011SMarcel Moolenaar goto bad; 18443955d011SMarcel Moolenaar 18453955d011SMarcel Moolenaar default: 184606b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); /* No need for the writing half */ 18473955d011SMarcel Moolenaar 1848db29cad8SSimon J. Gerraty savederr = 0; 1849e2eeea75SSimon J. Gerraty Buf_Init(&buf); 18503955d011SMarcel Moolenaar 18513955d011SMarcel Moolenaar do { 18523955d011SMarcel Moolenaar char result[BUFSIZ]; 185306b9b3e0SSimon J. Gerraty bytes_read = read(pipefds[0], result, sizeof result); 18542c3632d1SSimon J. Gerraty if (bytes_read > 0) 18552c3632d1SSimon J. Gerraty Buf_AddBytes(&buf, result, (size_t)bytes_read); 1856e2eeea75SSimon J. Gerraty } while (bytes_read > 0 || 1857e2eeea75SSimon J. Gerraty (bytes_read == -1 && errno == EINTR)); 18582c3632d1SSimon J. Gerraty if (bytes_read == -1) 1859db29cad8SSimon J. Gerraty savederr = errno; 18603955d011SMarcel Moolenaar 186106b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close the input side of the pipe. */ 18623955d011SMarcel Moolenaar 1863e2eeea75SSimon J. Gerraty /* Wait for the process to exit. */ 1864e2eeea75SSimon J. Gerraty while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 18653955d011SMarcel Moolenaar JobReapChild(pid, status, FALSE); 1866e2eeea75SSimon J. Gerraty 1867*dba7b0efSSimon J. Gerraty res_len = buf.len; 1868*dba7b0efSSimon J. Gerraty res = Buf_DoneData(&buf); 18693955d011SMarcel Moolenaar 1870db29cad8SSimon J. Gerraty if (savederr != 0) 18712c3632d1SSimon J. Gerraty *errfmt = "Couldn't read shell's output for \"%s\""; 18723955d011SMarcel Moolenaar 18733955d011SMarcel Moolenaar if (WIFSIGNALED(status)) 18742c3632d1SSimon J. Gerraty *errfmt = "\"%s\" exited on a signal"; 18753955d011SMarcel Moolenaar else if (WEXITSTATUS(status) != 0) 18762c3632d1SSimon J. Gerraty *errfmt = "\"%s\" returned non-zero status"; 18773955d011SMarcel Moolenaar 18782c3632d1SSimon J. Gerraty /* Convert newlines to spaces. A final newline is just stripped */ 18792c3632d1SSimon J. Gerraty if (res_len > 0 && res[res_len - 1] == '\n') 18802c3632d1SSimon J. Gerraty res[res_len - 1] = '\0'; 18812c3632d1SSimon J. Gerraty for (cp = res; *cp != '\0'; cp++) 18822c3632d1SSimon J. Gerraty if (*cp == '\n') 18833955d011SMarcel Moolenaar *cp = ' '; 18843955d011SMarcel Moolenaar break; 18853955d011SMarcel Moolenaar } 18863955d011SMarcel Moolenaar return res; 18873955d011SMarcel Moolenaar bad: 18882c3632d1SSimon J. Gerraty return bmake_strdup(""); 18893955d011SMarcel Moolenaar } 18903955d011SMarcel Moolenaar 189106b9b3e0SSimon J. Gerraty /* 189206b9b3e0SSimon J. Gerraty * Print a printf-style error message. 18933955d011SMarcel Moolenaar * 1894e2eeea75SSimon J. Gerraty * In default mode, this error message has no consequences, in particular it 189506b9b3e0SSimon J. Gerraty * does not affect the exit status. Only in lint mode (-dL) it does. 189606b9b3e0SSimon J. Gerraty */ 18973955d011SMarcel Moolenaar void 18983955d011SMarcel Moolenaar Error(const char *fmt, ...) 18993955d011SMarcel Moolenaar { 19003955d011SMarcel Moolenaar va_list ap; 19013955d011SMarcel Moolenaar FILE *err_file; 19023955d011SMarcel Moolenaar 1903956e45f6SSimon J. Gerraty err_file = opts.debug_file; 19043955d011SMarcel Moolenaar if (err_file == stdout) 19053955d011SMarcel Moolenaar err_file = stderr; 19063955d011SMarcel Moolenaar (void)fflush(stdout); 19073955d011SMarcel Moolenaar for (;;) { 19083955d011SMarcel Moolenaar va_start(ap, fmt); 19093955d011SMarcel Moolenaar fprintf(err_file, "%s: ", progname); 19103955d011SMarcel Moolenaar (void)vfprintf(err_file, fmt, ap); 19113955d011SMarcel Moolenaar va_end(ap); 19123955d011SMarcel Moolenaar (void)fprintf(err_file, "\n"); 19133955d011SMarcel Moolenaar (void)fflush(err_file); 19143955d011SMarcel Moolenaar if (err_file == stderr) 19153955d011SMarcel Moolenaar break; 19163955d011SMarcel Moolenaar err_file = stderr; 19173955d011SMarcel Moolenaar } 191806b9b3e0SSimon J. Gerraty main_errors++; 19193955d011SMarcel Moolenaar } 19203955d011SMarcel Moolenaar 192106b9b3e0SSimon J. Gerraty /* 192206b9b3e0SSimon J. Gerraty * Wait for any running jobs to finish, then produce an error message, 1923e2eeea75SSimon J. Gerraty * finally exit immediately. 19243955d011SMarcel Moolenaar * 1925e2eeea75SSimon J. Gerraty * Exiting immediately differs from Parse_Error, which exits only after the 192606b9b3e0SSimon J. Gerraty * current top-level makefile has been parsed completely. 192706b9b3e0SSimon J. Gerraty */ 19283955d011SMarcel Moolenaar void 19293955d011SMarcel Moolenaar Fatal(const char *fmt, ...) 19303955d011SMarcel Moolenaar { 19313955d011SMarcel Moolenaar va_list ap; 19323955d011SMarcel Moolenaar 19333955d011SMarcel Moolenaar if (jobsRunning) 19343955d011SMarcel Moolenaar Job_Wait(); 19353955d011SMarcel Moolenaar 19363955d011SMarcel Moolenaar (void)fflush(stdout); 1937e2eeea75SSimon J. Gerraty va_start(ap, fmt); 19383955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 19393955d011SMarcel Moolenaar va_end(ap); 19403955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 19413955d011SMarcel Moolenaar (void)fflush(stderr); 19423955d011SMarcel Moolenaar 19433955d011SMarcel Moolenaar PrintOnError(NULL, NULL); 19443955d011SMarcel Moolenaar 19453955d011SMarcel Moolenaar if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 19463955d011SMarcel Moolenaar Targ_PrintGraph(2); 1947e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 19483955d011SMarcel Moolenaar exit(2); /* Not 1 so -q can distinguish error */ 19493955d011SMarcel Moolenaar } 19503955d011SMarcel Moolenaar 195106b9b3e0SSimon J. Gerraty /* 195206b9b3e0SSimon J. Gerraty * Major exception once jobs are being created. 195306b9b3e0SSimon J. Gerraty * Kills all jobs, prints a message and exits. 195406b9b3e0SSimon J. Gerraty */ 19553955d011SMarcel Moolenaar void 19563955d011SMarcel Moolenaar Punt(const char *fmt, ...) 19573955d011SMarcel Moolenaar { 19583955d011SMarcel Moolenaar va_list ap; 19593955d011SMarcel Moolenaar 19603955d011SMarcel Moolenaar va_start(ap, fmt); 19613955d011SMarcel Moolenaar (void)fflush(stdout); 19623955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: ", progname); 19633955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 19643955d011SMarcel Moolenaar va_end(ap); 19653955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 19663955d011SMarcel Moolenaar (void)fflush(stderr); 19673955d011SMarcel Moolenaar 19683955d011SMarcel Moolenaar PrintOnError(NULL, NULL); 19693955d011SMarcel Moolenaar 19703955d011SMarcel Moolenaar DieHorribly(); 19713955d011SMarcel Moolenaar } 19723955d011SMarcel Moolenaar 1973956e45f6SSimon J. Gerraty /* Exit without giving a message. */ 19743955d011SMarcel Moolenaar void 19753955d011SMarcel Moolenaar DieHorribly(void) 19763955d011SMarcel Moolenaar { 19773955d011SMarcel Moolenaar if (jobsRunning) 19783955d011SMarcel Moolenaar Job_AbortAll(); 19793955d011SMarcel Moolenaar if (DEBUG(GRAPH2)) 19803955d011SMarcel Moolenaar Targ_PrintGraph(2); 1981e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 198206b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 19833955d011SMarcel Moolenaar } 19843955d011SMarcel Moolenaar 198506b9b3e0SSimon J. Gerraty /* 198606b9b3e0SSimon J. Gerraty * Called when aborting due to errors in child shell to signal abnormal exit. 1987956e45f6SSimon J. Gerraty * The program exits. 198806b9b3e0SSimon J. Gerraty * Errors is the number of errors encountered in Make_Make. 198906b9b3e0SSimon J. Gerraty */ 19903955d011SMarcel Moolenaar void 1991956e45f6SSimon J. Gerraty Finish(int errs) 19923955d011SMarcel Moolenaar { 1993e2eeea75SSimon J. Gerraty if (shouldDieQuietly(NULL, -1)) 19943841c287SSimon J. Gerraty exit(2); 1995956e45f6SSimon J. Gerraty Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 19963955d011SMarcel Moolenaar } 19973955d011SMarcel Moolenaar 19983955d011SMarcel Moolenaar /* 19991748de26SSimon J. Gerraty * eunlink -- 20003955d011SMarcel Moolenaar * Remove a file carefully, avoiding directories. 20013955d011SMarcel Moolenaar */ 20023955d011SMarcel Moolenaar int 20033955d011SMarcel Moolenaar eunlink(const char *file) 20043955d011SMarcel Moolenaar { 20053955d011SMarcel Moolenaar struct stat st; 20063955d011SMarcel Moolenaar 20073955d011SMarcel Moolenaar if (lstat(file, &st) == -1) 20083955d011SMarcel Moolenaar return -1; 20093955d011SMarcel Moolenaar 20103955d011SMarcel Moolenaar if (S_ISDIR(st.st_mode)) { 20113955d011SMarcel Moolenaar errno = EISDIR; 20123955d011SMarcel Moolenaar return -1; 20133955d011SMarcel Moolenaar } 20143955d011SMarcel Moolenaar return unlink(file); 20153955d011SMarcel Moolenaar } 20163955d011SMarcel Moolenaar 2017956e45f6SSimon J. Gerraty static void 2018956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n) 2019956e45f6SSimon J. Gerraty { 2020956e45f6SSimon J. Gerraty const char *mem = data; 2021956e45f6SSimon J. Gerraty 2022956e45f6SSimon J. Gerraty while (n > 0) { 2023956e45f6SSimon J. Gerraty ssize_t written = write(fd, mem, n); 2024956e45f6SSimon J. Gerraty if (written == -1 && errno == EAGAIN) 2025956e45f6SSimon J. Gerraty continue; 2026956e45f6SSimon J. Gerraty if (written == -1) 2027956e45f6SSimon J. Gerraty break; 2028956e45f6SSimon J. Gerraty mem += written; 2029956e45f6SSimon J. Gerraty n -= (size_t)written; 2030956e45f6SSimon J. Gerraty } 2031956e45f6SSimon J. Gerraty } 2032956e45f6SSimon J. Gerraty 20333955d011SMarcel Moolenaar /* 2034956e45f6SSimon J. Gerraty * execDie -- 20353955d011SMarcel Moolenaar * Print why exec failed, avoiding stdio. 20363955d011SMarcel Moolenaar */ 2037956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD 2038956e45f6SSimon J. Gerraty execDie(const char *af, const char *av) 20393955d011SMarcel Moolenaar { 2040956e45f6SSimon J. Gerraty Buffer buf; 20413955d011SMarcel Moolenaar 2042e2eeea75SSimon J. Gerraty Buf_Init(&buf); 2043956e45f6SSimon J. Gerraty Buf_AddStr(&buf, progname); 2044956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ": "); 2045956e45f6SSimon J. Gerraty Buf_AddStr(&buf, af); 2046956e45f6SSimon J. Gerraty Buf_AddStr(&buf, "("); 2047956e45f6SSimon J. Gerraty Buf_AddStr(&buf, av); 2048956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ") failed ("); 2049956e45f6SSimon J. Gerraty Buf_AddStr(&buf, strerror(errno)); 2050956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ")\n"); 20513955d011SMarcel Moolenaar 2052*dba7b0efSSimon J. Gerraty write_all(STDERR_FILENO, buf.data, buf.len); 2053956e45f6SSimon J. Gerraty 2054*dba7b0efSSimon J. Gerraty Buf_Done(&buf); 2055956e45f6SSimon J. Gerraty _exit(1); 20563955d011SMarcel Moolenaar } 20573955d011SMarcel Moolenaar 2058b46b9039SSimon J. Gerraty /* purge any relative paths */ 2059e1cee40dSSimon J. Gerraty static void 2060e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void) 2061e1cee40dSSimon J. Gerraty { 2062956e45f6SSimon J. Gerraty HashEntry *he, *nhe; 2063956e45f6SSimon J. Gerraty HashIter hi; 2064b778b302SSimon J. Gerraty 2065e2eeea75SSimon J. Gerraty HashIter_Init(&hi, &cached_realpaths); 2066956e45f6SSimon J. Gerraty he = HashIter_Next(&hi); 2067956e45f6SSimon J. Gerraty while (he != NULL) { 2068956e45f6SSimon J. Gerraty nhe = HashIter_Next(&hi); 2069956e45f6SSimon J. Gerraty if (he->key[0] != '/') { 2070e2eeea75SSimon J. Gerraty DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 2071e2eeea75SSimon J. Gerraty HashTable_DeleteEntry(&cached_realpaths, he); 2072e2eeea75SSimon J. Gerraty /* XXX: What about the allocated he->value? Either 2073e2eeea75SSimon J. Gerraty * free them or document why they cannot be freed. */ 2074b46b9039SSimon J. Gerraty } 2075b46b9039SSimon J. Gerraty he = nhe; 2076b46b9039SSimon J. Gerraty } 2077b46b9039SSimon J. Gerraty } 2078e1cee40dSSimon J. Gerraty 2079e1cee40dSSimon J. Gerraty char * 2080e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved) 2081e1cee40dSSimon J. Gerraty { 20822c3632d1SSimon J. Gerraty const char *rp; 2083e1cee40dSSimon J. Gerraty 2084e2eeea75SSimon J. Gerraty if (pathname == NULL || pathname[0] == '\0') 2085e1cee40dSSimon J. Gerraty return NULL; 2086e1cee40dSSimon J. Gerraty 2087e2eeea75SSimon J. Gerraty rp = HashTable_FindValue(&cached_realpaths, pathname); 2088e2eeea75SSimon J. Gerraty if (rp != NULL) { 2089b778b302SSimon J. Gerraty /* a hit */ 2090e2eeea75SSimon J. Gerraty strncpy(resolved, rp, MAXPATHLEN); 2091e2eeea75SSimon J. Gerraty resolved[MAXPATHLEN - 1] = '\0'; 2092e2eeea75SSimon J. Gerraty return resolved; 2093e2eeea75SSimon J. Gerraty } 20943841c287SSimon J. Gerraty 2095e2eeea75SSimon J. Gerraty rp = realpath(pathname, resolved); 2096e2eeea75SSimon J. Gerraty if (rp != NULL) { 2097e2eeea75SSimon J. Gerraty HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2098e2eeea75SSimon J. Gerraty DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2099e2eeea75SSimon J. Gerraty return resolved; 2100e2eeea75SSimon J. Gerraty } 2101e2eeea75SSimon J. Gerraty 2102e2eeea75SSimon J. Gerraty /* should we negative-cache? */ 2103e2eeea75SSimon J. Gerraty return NULL; 2104b778b302SSimon J. Gerraty } 2105b778b302SSimon J. Gerraty 21063841c287SSimon J. Gerraty /* 21073841c287SSimon J. Gerraty * Return true if we should die without noise. 2108e2eeea75SSimon J. Gerraty * For example our failing child was a sub-make or failure happened elsewhere. 21093841c287SSimon J. Gerraty */ 2110e2eeea75SSimon J. Gerraty Boolean 2111e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf) 21123841c287SSimon J. Gerraty { 21133841c287SSimon J. Gerraty static int quietly = -1; 21143841c287SSimon J. Gerraty 21153841c287SSimon J. Gerraty if (quietly < 0) { 2116e2eeea75SSimon J. Gerraty if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE)) 21173841c287SSimon J. Gerraty quietly = 0; 21183841c287SSimon J. Gerraty else if (bf >= 0) 21193841c287SSimon J. Gerraty quietly = bf; 21203841c287SSimon J. Gerraty else 212106b9b3e0SSimon J. Gerraty quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0; 21223841c287SSimon J. Gerraty } 2123*dba7b0efSSimon J. Gerraty return quietly != 0; 21243841c287SSimon J. Gerraty } 21253841c287SSimon J. Gerraty 2126956e45f6SSimon J. Gerraty static void 2127956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn) 2128956e45f6SSimon J. Gerraty { 2129956e45f6SSimon J. Gerraty StringListNode *ln; 2130956e45f6SSimon J. Gerraty 2131956e45f6SSimon J. Gerraty /* 2132956e45f6SSimon J. Gerraty * We can print this even if there is no .ERROR target. 2133956e45f6SSimon J. Gerraty */ 2134*dba7b0efSSimon J. Gerraty Global_Set(".ERROR_TARGET", gn->name); 2135*dba7b0efSSimon J. Gerraty Global_Delete(".ERROR_CMD"); 2136956e45f6SSimon J. Gerraty 213706b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) { 2138956e45f6SSimon J. Gerraty const char *cmd = ln->datum; 2139956e45f6SSimon J. Gerraty 2140956e45f6SSimon J. Gerraty if (cmd == NULL) 2141956e45f6SSimon J. Gerraty break; 2142*dba7b0efSSimon J. Gerraty Global_Append(".ERROR_CMD", cmd); 2143956e45f6SSimon J. Gerraty } 2144956e45f6SSimon J. Gerraty } 2145956e45f6SSimon J. Gerraty 214606b9b3e0SSimon J. Gerraty /* 214706b9b3e0SSimon J. Gerraty * Print some helpful information in case of an error. 214806b9b3e0SSimon J. Gerraty * The caller should exit soon after calling this function. 214906b9b3e0SSimon J. Gerraty */ 21503955d011SMarcel Moolenaar void 2151e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg) 21523955d011SMarcel Moolenaar { 2153e2eeea75SSimon J. Gerraty static GNode *errorNode = NULL; 21543955d011SMarcel Moolenaar 21552c3632d1SSimon J. Gerraty if (DEBUG(HASH)) { 21562c3632d1SSimon J. Gerraty Targ_Stats(); 21572c3632d1SSimon J. Gerraty Var_Stats(); 21582c3632d1SSimon J. Gerraty } 21592c3632d1SSimon J. Gerraty 216006b9b3e0SSimon J. Gerraty if (errorNode != NULL) 216106b9b3e0SSimon J. Gerraty return; /* we've been here! */ 21623841c287SSimon J. Gerraty 2163e2eeea75SSimon J. Gerraty if (msg != NULL) 2164e2eeea75SSimon J. Gerraty printf("%s", msg); 21653955d011SMarcel Moolenaar printf("\n%s: stopped in %s\n", progname, curdir); 21663955d011SMarcel Moolenaar 216706b9b3e0SSimon J. Gerraty /* we generally want to keep quiet if a sub-make died */ 216806b9b3e0SSimon J. Gerraty if (shouldDieQuietly(gn, -1)) 216906b9b3e0SSimon J. Gerraty return; 2170e2eeea75SSimon J. Gerraty 2171e2eeea75SSimon J. Gerraty if (gn != NULL) 2172956e45f6SSimon J. Gerraty SetErrorVars(gn); 2173e2eeea75SSimon J. Gerraty 2174e2eeea75SSimon J. Gerraty { 2175e2eeea75SSimon J. Gerraty char *errorVarsValues; 2176e2eeea75SSimon J. Gerraty (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 2177*dba7b0efSSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues); 2178956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2179e2eeea75SSimon J. Gerraty printf("%s", errorVarsValues); 2180e2eeea75SSimon J. Gerraty free(errorVarsValues); 2181e2eeea75SSimon J. Gerraty } 2182e2eeea75SSimon J. Gerraty 2183ac3446e9SSimon J. Gerraty fflush(stdout); 2184ac3446e9SSimon J. Gerraty 21853955d011SMarcel Moolenaar /* 21863955d011SMarcel Moolenaar * Finally, see if there is a .ERROR target, and run it if so. 21873955d011SMarcel Moolenaar */ 2188e2eeea75SSimon J. Gerraty errorNode = Targ_FindNode(".ERROR"); 2189e2eeea75SSimon J. Gerraty if (errorNode != NULL) { 2190e2eeea75SSimon J. Gerraty errorNode->type |= OP_SPECIAL; 2191e2eeea75SSimon J. Gerraty Compat_Make(errorNode, errorNode); 21923955d011SMarcel Moolenaar } 21933955d011SMarcel Moolenaar } 21943955d011SMarcel Moolenaar 21953955d011SMarcel Moolenaar void 21963955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(Boolean first) 21973955d011SMarcel Moolenaar { 21982c3632d1SSimon J. Gerraty static Boolean once = TRUE; 21992c3632d1SSimon J. Gerraty const char *expr; 22003955d011SMarcel Moolenaar char *s; 22013955d011SMarcel Moolenaar 22023955d011SMarcel Moolenaar if (once != first) 22033955d011SMarcel Moolenaar return; 22042c3632d1SSimon J. Gerraty once = FALSE; 22053955d011SMarcel Moolenaar 22062c3632d1SSimon J. Gerraty expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2207*dba7b0efSSimon J. Gerraty (void)Var_Subst(expr, SCOPE_CMDLINE, VARE_WANTRES, &s); 2208956e45f6SSimon J. Gerraty /* TODO: handle errors */ 22092c3632d1SSimon J. Gerraty if (s[0] != '\0') { 22103955d011SMarcel Moolenaar #ifdef POSIX 22113955d011SMarcel Moolenaar setenv("MAKEFLAGS", s, 1); 22123955d011SMarcel Moolenaar #else 22133955d011SMarcel Moolenaar setenv("MAKE", s, 1); 22143955d011SMarcel Moolenaar #endif 22153955d011SMarcel Moolenaar } 22163955d011SMarcel Moolenaar } 22173955d011SMarcel Moolenaar 22183955d011SMarcel Moolenaar char * 22193955d011SMarcel Moolenaar getTmpdir(void) 22203955d011SMarcel Moolenaar { 22213955d011SMarcel Moolenaar static char *tmpdir = NULL; 22223955d011SMarcel Moolenaar struct stat st; 22233955d011SMarcel Moolenaar 2224e2eeea75SSimon J. Gerraty if (tmpdir != NULL) 2225e2eeea75SSimon J. Gerraty return tmpdir; 2226e2eeea75SSimon J. Gerraty 2227e2eeea75SSimon J. Gerraty /* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */ 2228e2eeea75SSimon J. Gerraty (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", 2229*dba7b0efSSimon J. Gerraty SCOPE_GLOBAL, VARE_WANTRES, &tmpdir); 2230956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2231e2eeea75SSimon J. Gerraty 22323955d011SMarcel Moolenaar if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 22333955d011SMarcel Moolenaar free(tmpdir); 22343955d011SMarcel Moolenaar tmpdir = bmake_strdup(_PATH_TMP); 22353955d011SMarcel Moolenaar } 22363955d011SMarcel Moolenaar return tmpdir; 22373955d011SMarcel Moolenaar } 22383955d011SMarcel Moolenaar 22393955d011SMarcel Moolenaar /* 22403955d011SMarcel Moolenaar * Create and open a temp file using "pattern". 2241956e45f6SSimon J. Gerraty * If out_fname is provided, set it to a copy of the filename created. 22423955d011SMarcel Moolenaar * Otherwise unlink the file once open. 22433955d011SMarcel Moolenaar */ 22443955d011SMarcel Moolenaar int 2245*dba7b0efSSimon J. Gerraty mkTempFile(const char *pattern, char *tfile, size_t tfile_sz) 22463955d011SMarcel Moolenaar { 22473955d011SMarcel Moolenaar static char *tmpdir = NULL; 2248*dba7b0efSSimon J. Gerraty char tbuf[MAXPATHLEN]; 22493955d011SMarcel Moolenaar int fd; 22503955d011SMarcel Moolenaar 2251e2eeea75SSimon J. Gerraty if (pattern == NULL) 22523955d011SMarcel Moolenaar pattern = TMPPAT; 2253956e45f6SSimon J. Gerraty if (tmpdir == NULL) 22543955d011SMarcel Moolenaar tmpdir = getTmpdir(); 2255*dba7b0efSSimon J. Gerraty if (tfile == NULL) { 2256*dba7b0efSSimon J. Gerraty tfile = tbuf; 2257*dba7b0efSSimon J. Gerraty tfile_sz = sizeof tbuf; 2258*dba7b0efSSimon J. Gerraty } 22593955d011SMarcel Moolenaar if (pattern[0] == '/') { 2260*dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s", pattern); 22613955d011SMarcel Moolenaar } else { 2262*dba7b0efSSimon J. Gerraty snprintf(tfile, tfile_sz, "%s%s", tmpdir, pattern); 22633955d011SMarcel Moolenaar } 22643955d011SMarcel Moolenaar if ((fd = mkstemp(tfile)) < 0) 2265e2eeea75SSimon J. Gerraty Punt("Could not create temporary file %s: %s", tfile, 2266e2eeea75SSimon J. Gerraty strerror(errno)); 2267*dba7b0efSSimon J. Gerraty if (tfile == tbuf) { 226806b9b3e0SSimon J. Gerraty unlink(tfile); /* we just want the descriptor */ 22693955d011SMarcel Moolenaar } 22703955d011SMarcel Moolenaar return fd; 22713955d011SMarcel Moolenaar } 22723955d011SMarcel Moolenaar 2273be19d90bSSimon J. Gerraty /* 2274e2eeea75SSimon J. Gerraty * Convert a string representation of a boolean into a boolean value. 2275e2eeea75SSimon J. Gerraty * Anything that looks like "No", "False", "Off", "0" etc. is FALSE, 2276e2eeea75SSimon J. Gerraty * the empty string is the fallback, everything else is TRUE. 2277be19d90bSSimon J. Gerraty */ 2278be19d90bSSimon J. Gerraty Boolean 2279e2eeea75SSimon J. Gerraty ParseBoolean(const char *s, Boolean fallback) 2280be19d90bSSimon J. Gerraty { 2281e2eeea75SSimon J. Gerraty char ch = ch_tolower(s[0]); 2282e2eeea75SSimon J. Gerraty if (ch == '\0') 2283e2eeea75SSimon J. Gerraty return fallback; 2284e2eeea75SSimon J. Gerraty if (ch == '0' || ch == 'f' || ch == 'n') 2285956e45f6SSimon J. Gerraty return FALSE; 2286e2eeea75SSimon J. Gerraty if (ch == 'o') 2287e2eeea75SSimon J. Gerraty return ch_tolower(s[1]) != 'f'; 2288956e45f6SSimon J. Gerraty return TRUE; 2289be19d90bSSimon J. Gerraty } 2290