1*06b9b3e0SSimon J. Gerraty /* $NetBSD: main.c,v 1.512 2021/01/10 23:59:53 rillig 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 71*06b9b3e0SSimon J. Gerraty /* 72*06b9b3e0SSimon 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 * 76e2eeea75SSimon J. Gerraty * Main_ParseArgLine Parse and process command line arguments from 77e2eeea75SSimon J. Gerraty * a single string. Used to implement the 78e2eeea75SSimon J. Gerraty * special targets .MFLAGS and .MAKEFLAGS. 793955d011SMarcel Moolenaar * 80e2eeea75SSimon J. Gerraty * Error Print a tagged error message. 813955d011SMarcel Moolenaar * 82e2eeea75SSimon J. Gerraty * Fatal Print an error message and exit. 83e2eeea75SSimon J. Gerraty * 84e2eeea75SSimon J. Gerraty * Punt Abort all jobs and exit with a message. 853955d011SMarcel Moolenaar * 863955d011SMarcel Moolenaar * Finish Finish things up by printing the number of 87e2eeea75SSimon J. Gerraty * errors which occurred, and exit. 883955d011SMarcel Moolenaar */ 893955d011SMarcel Moolenaar 903955d011SMarcel Moolenaar #include <sys/types.h> 913955d011SMarcel Moolenaar #include <sys/time.h> 923955d011SMarcel Moolenaar #include <sys/param.h> 933955d011SMarcel Moolenaar #include <sys/resource.h> 943955d011SMarcel Moolenaar #include <sys/stat.h> 950dede8b0SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 960dede8b0SSimon J. Gerraty #include <sys/sysctl.h> 970dede8b0SSimon J. Gerraty #endif 983955d011SMarcel Moolenaar #include <sys/utsname.h> 993955d011SMarcel Moolenaar #include "wait.h" 1003955d011SMarcel Moolenaar 1013955d011SMarcel Moolenaar #include <errno.h> 10251ee2c1cSSimon J. Gerraty #include <signal.h> 1033955d011SMarcel Moolenaar #include <stdarg.h> 1043955d011SMarcel Moolenaar #include <time.h> 1053955d011SMarcel Moolenaar 1063955d011SMarcel Moolenaar #include "make.h" 1073955d011SMarcel Moolenaar #include "dir.h" 1083955d011SMarcel Moolenaar #include "job.h" 1093955d011SMarcel Moolenaar #include "pathnames.h" 1103955d011SMarcel Moolenaar #include "trace.h" 1113955d011SMarcel Moolenaar 112956e45f6SSimon J. Gerraty /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 113*06b9b3e0SSimon J. Gerraty MAKE_RCSID("$NetBSD: main.c,v 1.512 2021/01/10 23:59:53 rillig Exp $"); 114956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && !defined(lint) 115956e45f6SSimon J. Gerraty __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 116956e45f6SSimon J. Gerraty "The Regents of the University of California. " 117956e45f6SSimon J. Gerraty "All rights reserved."); 1183955d011SMarcel Moolenaar #endif 1193955d011SMarcel Moolenaar 1200dede8b0SSimon J. Gerraty #ifndef __arraycount 1210dede8b0SSimon J. Gerraty # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 1220dede8b0SSimon J. Gerraty #endif 1230dede8b0SSimon J. Gerraty 124956e45f6SSimon J. Gerraty CmdOpts opts; 1253955d011SMarcel Moolenaar time_t now; /* Time at start of make */ 126e2eeea75SSimon J. Gerraty GNode *defaultNode; /* .DEFAULT node */ 1273955d011SMarcel Moolenaar Boolean allPrecious; /* .PRECIOUS given on line by itself */ 12845447996SSimon J. Gerraty Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 1293955d011SMarcel Moolenaar 1303955d011SMarcel Moolenaar static int maxJobTokens; /* -j argument */ 1314c620fe5SSimon J. Gerraty Boolean enterFlagObj; /* -w and objdir != srcdir */ 132956e45f6SSimon J. Gerraty 1333955d011SMarcel Moolenaar static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 1343955d011SMarcel Moolenaar Boolean doing_depend; /* Set while reading .depend */ 1353955d011SMarcel Moolenaar static Boolean jobsRunning; /* TRUE if the jobs might be running */ 1363955d011SMarcel Moolenaar static const char *tracefile; 1372c3632d1SSimon J. Gerraty static int ReadMakefile(const char *); 138e2eeea75SSimon J. Gerraty static void purge_relative_cached_realpaths(void); 1393955d011SMarcel Moolenaar 1403955d011SMarcel Moolenaar static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 1413955d011SMarcel Moolenaar static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 1423955d011SMarcel Moolenaar char curdir[MAXPATHLEN + 1]; /* Startup directory */ 143*06b9b3e0SSimon J. Gerraty const char *progname; 1443955d011SMarcel Moolenaar char *makeDependfile; 1453955d011SMarcel Moolenaar pid_t myPid; 14651ee2c1cSSimon J. Gerraty int makelevel; 1473955d011SMarcel Moolenaar 1483955d011SMarcel Moolenaar Boolean forceJobs = FALSE; 149*06b9b3e0SSimon J. Gerraty static int main_errors = 0; 150e2eeea75SSimon J. Gerraty static HashTable cached_realpaths; 1513955d011SMarcel Moolenaar 15251ee2c1cSSimon J. Gerraty /* 15351ee2c1cSSimon J. Gerraty * For compatibility with the POSIX version of MAKEFLAGS that includes 154e2eeea75SSimon J. Gerraty * all the options without '-', convert 'flags' to '-f -l -a -g -s'. 15551ee2c1cSSimon J. Gerraty */ 15651ee2c1cSSimon J. Gerraty static char * 15751ee2c1cSSimon J. Gerraty explode(const char *flags) 15851ee2c1cSSimon J. Gerraty { 15951ee2c1cSSimon J. Gerraty size_t len; 16051ee2c1cSSimon J. Gerraty char *nf, *st; 16151ee2c1cSSimon J. Gerraty const char *f; 16251ee2c1cSSimon J. Gerraty 16351ee2c1cSSimon J. Gerraty if (flags == NULL) 16451ee2c1cSSimon J. Gerraty return NULL; 16551ee2c1cSSimon J. Gerraty 166*06b9b3e0SSimon J. Gerraty for (f = flags; *f != '\0'; f++) 167956e45f6SSimon J. Gerraty if (!ch_isalpha(*f)) 16851ee2c1cSSimon J. Gerraty break; 16951ee2c1cSSimon J. Gerraty 170*06b9b3e0SSimon J. Gerraty if (*f != '\0') 17151ee2c1cSSimon J. Gerraty return bmake_strdup(flags); 17251ee2c1cSSimon J. Gerraty 17351ee2c1cSSimon J. Gerraty len = strlen(flags); 17451ee2c1cSSimon J. Gerraty st = nf = bmake_malloc(len * 3 + 1); 175*06b9b3e0SSimon J. Gerraty while (*flags != '\0') { 17651ee2c1cSSimon J. Gerraty *nf++ = '-'; 17751ee2c1cSSimon J. Gerraty *nf++ = *flags++; 17851ee2c1cSSimon J. Gerraty *nf++ = ' '; 17951ee2c1cSSimon J. Gerraty } 18051ee2c1cSSimon J. Gerraty *nf = '\0'; 18151ee2c1cSSimon J. Gerraty return st; 18251ee2c1cSSimon J. Gerraty } 18351ee2c1cSSimon J. Gerraty 184e2eeea75SSimon J. Gerraty /* 185e2eeea75SSimon J. Gerraty * usage -- 186e2eeea75SSimon J. Gerraty * exit with usage message 187e2eeea75SSimon J. Gerraty */ 188e2eeea75SSimon J. Gerraty MAKE_ATTR_DEAD static void 189e2eeea75SSimon J. Gerraty usage(void) 190e2eeea75SSimon J. Gerraty { 191e2eeea75SSimon J. Gerraty size_t prognameLen = strcspn(progname, "["); 192e2eeea75SSimon J. Gerraty 193e2eeea75SSimon J. Gerraty (void)fprintf(stderr, 194e2eeea75SSimon J. Gerraty "usage: %.*s [-BeikNnqrSstWwX]\n" 195e2eeea75SSimon J. Gerraty " [-C directory] [-D variable] [-d flags] [-f makefile]\n" 196e2eeea75SSimon J. Gerraty " [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 197e2eeea75SSimon J. Gerraty " [-V variable] [-v variable] [variable=value] [target ...]\n", 198e2eeea75SSimon J. Gerraty (int)prognameLen, progname); 199e2eeea75SSimon J. Gerraty exit(2); 200e2eeea75SSimon J. Gerraty } 201e2eeea75SSimon J. Gerraty 2023955d011SMarcel Moolenaar static void 203956e45f6SSimon J. Gerraty parse_debug_option_F(const char *modules) 2043955d011SMarcel Moolenaar { 2053955d011SMarcel Moolenaar const char *mode; 206956e45f6SSimon J. Gerraty size_t len; 2073955d011SMarcel Moolenaar char *fname; 2083955d011SMarcel Moolenaar 209956e45f6SSimon J. Gerraty if (opts.debug_file != stdout && opts.debug_file != stderr) 210956e45f6SSimon J. Gerraty fclose(opts.debug_file); 211956e45f6SSimon J. Gerraty 212956e45f6SSimon J. Gerraty if (*modules == '+') { 2133955d011SMarcel Moolenaar modules++; 2143955d011SMarcel Moolenaar mode = "a"; 2153955d011SMarcel Moolenaar } else 2163955d011SMarcel Moolenaar mode = "w"; 217956e45f6SSimon J. Gerraty 2183955d011SMarcel Moolenaar if (strcmp(modules, "stdout") == 0) { 219956e45f6SSimon J. Gerraty opts.debug_file = stdout; 220956e45f6SSimon J. Gerraty return; 2213955d011SMarcel Moolenaar } 2223955d011SMarcel Moolenaar if (strcmp(modules, "stderr") == 0) { 223956e45f6SSimon J. Gerraty opts.debug_file = stderr; 224956e45f6SSimon J. Gerraty return; 2253955d011SMarcel Moolenaar } 226956e45f6SSimon J. Gerraty 2273955d011SMarcel Moolenaar len = strlen(modules); 228e1cee40dSSimon J. Gerraty fname = bmake_malloc(len + 20); 2293955d011SMarcel Moolenaar memcpy(fname, modules, len + 1); 230956e45f6SSimon J. Gerraty 2313955d011SMarcel Moolenaar /* Let the filename be modified by the pid */ 2323955d011SMarcel Moolenaar if (strcmp(fname + len - 3, ".%d") == 0) 2333955d011SMarcel Moolenaar snprintf(fname + len - 2, 20, "%d", getpid()); 234956e45f6SSimon J. Gerraty 235956e45f6SSimon J. Gerraty opts.debug_file = fopen(fname, mode); 236e2eeea75SSimon J. Gerraty if (opts.debug_file == NULL) { 2373955d011SMarcel Moolenaar fprintf(stderr, "Cannot open debug file %s\n", 2383955d011SMarcel Moolenaar fname); 2393955d011SMarcel Moolenaar usage(); 2403955d011SMarcel Moolenaar } 2413955d011SMarcel Moolenaar free(fname); 242956e45f6SSimon J. Gerraty } 243956e45f6SSimon J. Gerraty 244956e45f6SSimon J. Gerraty static void 245956e45f6SSimon J. Gerraty parse_debug_options(const char *argvalue) 246956e45f6SSimon J. Gerraty { 247956e45f6SSimon J. Gerraty const char *modules; 248e2eeea75SSimon J. Gerraty DebugFlags debug = opts.debug; 249956e45f6SSimon J. Gerraty 250*06b9b3e0SSimon J. Gerraty for (modules = argvalue; *modules != '\0'; ++modules) { 251956e45f6SSimon J. Gerraty switch (*modules) { 252956e45f6SSimon J. Gerraty case '0': /* undocumented, only intended for tests */ 253e2eeea75SSimon J. Gerraty debug = DEBUG_NONE; 254956e45f6SSimon J. Gerraty break; 255956e45f6SSimon J. Gerraty case 'A': 256e2eeea75SSimon J. Gerraty debug = DEBUG_ALL; 257956e45f6SSimon J. Gerraty break; 258956e45f6SSimon J. Gerraty case 'a': 259e2eeea75SSimon J. Gerraty debug |= DEBUG_ARCH; 260956e45f6SSimon J. Gerraty break; 261956e45f6SSimon J. Gerraty case 'C': 262e2eeea75SSimon J. Gerraty debug |= DEBUG_CWD; 263956e45f6SSimon J. Gerraty break; 264956e45f6SSimon J. Gerraty case 'c': 265e2eeea75SSimon J. Gerraty debug |= DEBUG_COND; 266956e45f6SSimon J. Gerraty break; 267956e45f6SSimon J. Gerraty case 'd': 268e2eeea75SSimon J. Gerraty debug |= DEBUG_DIR; 269956e45f6SSimon J. Gerraty break; 270956e45f6SSimon J. Gerraty case 'e': 271e2eeea75SSimon J. Gerraty debug |= DEBUG_ERROR; 272956e45f6SSimon J. Gerraty break; 273956e45f6SSimon J. Gerraty case 'f': 274e2eeea75SSimon J. Gerraty debug |= DEBUG_FOR; 275956e45f6SSimon J. Gerraty break; 276956e45f6SSimon J. Gerraty case 'g': 277956e45f6SSimon J. Gerraty if (modules[1] == '1') { 278e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH1; 279e2eeea75SSimon J. Gerraty modules++; 280e2eeea75SSimon J. Gerraty } else if (modules[1] == '2') { 281e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH2; 282e2eeea75SSimon J. Gerraty modules++; 283e2eeea75SSimon J. Gerraty } else if (modules[1] == '3') { 284e2eeea75SSimon J. Gerraty debug |= DEBUG_GRAPH3; 285e2eeea75SSimon J. Gerraty modules++; 286956e45f6SSimon J. Gerraty } 287956e45f6SSimon J. Gerraty break; 288956e45f6SSimon J. Gerraty case 'h': 289e2eeea75SSimon J. Gerraty debug |= DEBUG_HASH; 290956e45f6SSimon J. Gerraty break; 291956e45f6SSimon J. Gerraty case 'j': 292e2eeea75SSimon J. Gerraty debug |= DEBUG_JOB; 293956e45f6SSimon J. Gerraty break; 294956e45f6SSimon J. Gerraty case 'L': 295*06b9b3e0SSimon J. Gerraty opts.strict = TRUE; 296956e45f6SSimon J. Gerraty break; 297956e45f6SSimon J. Gerraty case 'l': 298e2eeea75SSimon J. Gerraty debug |= DEBUG_LOUD; 299956e45f6SSimon J. Gerraty break; 300956e45f6SSimon J. Gerraty case 'M': 301e2eeea75SSimon J. Gerraty debug |= DEBUG_META; 302956e45f6SSimon J. Gerraty break; 303956e45f6SSimon J. Gerraty case 'm': 304e2eeea75SSimon J. Gerraty debug |= DEBUG_MAKE; 305956e45f6SSimon J. Gerraty break; 306956e45f6SSimon J. Gerraty case 'n': 307e2eeea75SSimon J. Gerraty debug |= DEBUG_SCRIPT; 308956e45f6SSimon J. Gerraty break; 309956e45f6SSimon J. Gerraty case 'p': 310e2eeea75SSimon J. Gerraty debug |= DEBUG_PARSE; 311956e45f6SSimon J. Gerraty break; 312956e45f6SSimon J. Gerraty case 's': 313e2eeea75SSimon J. Gerraty debug |= DEBUG_SUFF; 314956e45f6SSimon J. Gerraty break; 315956e45f6SSimon J. Gerraty case 't': 316e2eeea75SSimon J. Gerraty debug |= DEBUG_TARG; 317956e45f6SSimon J. Gerraty break; 318956e45f6SSimon J. Gerraty case 'V': 319956e45f6SSimon J. Gerraty opts.debugVflag = TRUE; 320956e45f6SSimon J. Gerraty break; 321956e45f6SSimon J. Gerraty case 'v': 322e2eeea75SSimon J. Gerraty debug |= DEBUG_VAR; 323956e45f6SSimon J. Gerraty break; 324956e45f6SSimon J. Gerraty case 'x': 325e2eeea75SSimon J. Gerraty debug |= DEBUG_SHELL; 326956e45f6SSimon J. Gerraty break; 327956e45f6SSimon J. Gerraty case 'F': 328956e45f6SSimon J. Gerraty parse_debug_option_F(modules + 1); 3293955d011SMarcel Moolenaar goto debug_setbuf; 3303955d011SMarcel Moolenaar default: 3313955d011SMarcel Moolenaar (void)fprintf(stderr, 3323955d011SMarcel Moolenaar "%s: illegal argument to d option -- %c\n", 3333955d011SMarcel Moolenaar progname, *modules); 3343955d011SMarcel Moolenaar usage(); 3353955d011SMarcel Moolenaar } 3363955d011SMarcel Moolenaar } 337e2eeea75SSimon J. Gerraty 3383955d011SMarcel Moolenaar debug_setbuf: 339e2eeea75SSimon J. Gerraty opts.debug = debug; 340e2eeea75SSimon J. Gerraty 3413955d011SMarcel Moolenaar /* 3423955d011SMarcel Moolenaar * Make the debug_file unbuffered, and make 3433955d011SMarcel Moolenaar * stdout line buffered (unless debugfile == stdout). 3443955d011SMarcel Moolenaar */ 345956e45f6SSimon J. Gerraty setvbuf(opts.debug_file, NULL, _IONBF, 0); 346956e45f6SSimon J. Gerraty if (opts.debug_file != stdout) { 3473955d011SMarcel Moolenaar setvbuf(stdout, NULL, _IOLBF, 0); 3483955d011SMarcel Moolenaar } 3493955d011SMarcel Moolenaar } 3503955d011SMarcel Moolenaar 351e1cee40dSSimon J. Gerraty /* 352e1cee40dSSimon J. Gerraty * does path contain any relative components 353e1cee40dSSimon J. Gerraty */ 3542c3632d1SSimon J. Gerraty static Boolean 355e1cee40dSSimon J. Gerraty is_relpath(const char *path) 356e1cee40dSSimon J. Gerraty { 357e1cee40dSSimon J. Gerraty const char *cp; 358e1cee40dSSimon J. Gerraty 359e1cee40dSSimon J. Gerraty if (path[0] != '/') 360e1cee40dSSimon J. Gerraty return TRUE; 361e1cee40dSSimon J. Gerraty cp = path; 3622c3632d1SSimon J. Gerraty while ((cp = strstr(cp, "/.")) != NULL) { 363e1cee40dSSimon J. Gerraty cp += 2; 364e2eeea75SSimon J. Gerraty if (*cp == '.') 365e2eeea75SSimon J. Gerraty cp++; 366e1cee40dSSimon J. Gerraty if (cp[0] == '/' || cp[0] == '\0') 367e1cee40dSSimon J. Gerraty return TRUE; 3682c3632d1SSimon J. Gerraty } 369e1cee40dSSimon J. Gerraty return FALSE; 370e1cee40dSSimon J. Gerraty } 371e1cee40dSSimon J. Gerraty 372956e45f6SSimon J. Gerraty static void 373956e45f6SSimon J. Gerraty MainParseArgChdir(const char *argvalue) 374956e45f6SSimon J. Gerraty { 375956e45f6SSimon J. Gerraty struct stat sa, sb; 376956e45f6SSimon J. Gerraty 377956e45f6SSimon J. Gerraty if (chdir(argvalue) == -1) { 378956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: chdir %s: %s\n", 379956e45f6SSimon J. Gerraty progname, argvalue, strerror(errno)); 380*06b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 381956e45f6SSimon J. Gerraty } 382956e45f6SSimon J. Gerraty if (getcwd(curdir, MAXPATHLEN) == NULL) { 383956e45f6SSimon J. Gerraty (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 384956e45f6SSimon J. Gerraty exit(2); 385956e45f6SSimon J. Gerraty } 386956e45f6SSimon J. Gerraty if (!is_relpath(argvalue) && 387956e45f6SSimon J. Gerraty stat(argvalue, &sa) != -1 && 388956e45f6SSimon J. Gerraty stat(curdir, &sb) != -1 && 389956e45f6SSimon J. Gerraty sa.st_ino == sb.st_ino && 390956e45f6SSimon J. Gerraty sa.st_dev == sb.st_dev) 391956e45f6SSimon J. Gerraty strncpy(curdir, argvalue, MAXPATHLEN); 392956e45f6SSimon J. Gerraty ignorePWD = TRUE; 393956e45f6SSimon J. Gerraty } 394956e45f6SSimon J. Gerraty 395956e45f6SSimon J. Gerraty static void 396956e45f6SSimon J. Gerraty MainParseArgJobsInternal(const char *argvalue) 397956e45f6SSimon J. Gerraty { 398e2eeea75SSimon J. Gerraty char end; 399e2eeea75SSimon J. Gerraty if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { 400956e45f6SSimon J. Gerraty (void)fprintf(stderr, 401956e45f6SSimon J. Gerraty "%s: internal error -- J option malformed (%s)\n", 402956e45f6SSimon J. Gerraty progname, argvalue); 403956e45f6SSimon J. Gerraty usage(); 404956e45f6SSimon J. Gerraty } 405956e45f6SSimon J. Gerraty if ((fcntl(jp_0, F_GETFD, 0) < 0) || 406956e45f6SSimon J. Gerraty (fcntl(jp_1, F_GETFD, 0) < 0)) { 407956e45f6SSimon J. Gerraty #if 0 408956e45f6SSimon J. Gerraty (void)fprintf(stderr, 409956e45f6SSimon J. Gerraty "%s: ###### warning -- J descriptors were closed!\n", 410956e45f6SSimon J. Gerraty progname); 411956e45f6SSimon J. Gerraty exit(2); 412956e45f6SSimon J. Gerraty #endif 413956e45f6SSimon J. Gerraty jp_0 = -1; 414956e45f6SSimon J. Gerraty jp_1 = -1; 415956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 416956e45f6SSimon J. Gerraty } else { 417956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 418956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 419956e45f6SSimon J. Gerraty } 420956e45f6SSimon J. Gerraty } 421956e45f6SSimon J. Gerraty 422956e45f6SSimon J. Gerraty static void 423956e45f6SSimon J. Gerraty MainParseArgJobs(const char *argvalue) 424956e45f6SSimon J. Gerraty { 425956e45f6SSimon J. Gerraty char *p; 426956e45f6SSimon J. Gerraty 427956e45f6SSimon J. Gerraty forceJobs = TRUE; 428956e45f6SSimon J. Gerraty opts.maxJobs = (int)strtol(argvalue, &p, 0); 429956e45f6SSimon J. Gerraty if (*p != '\0' || opts.maxJobs < 1) { 430956e45f6SSimon J. Gerraty (void)fprintf(stderr, 431956e45f6SSimon J. Gerraty "%s: illegal argument to -j -- must be positive integer!\n", 432956e45f6SSimon J. Gerraty progname); 433*06b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 434956e45f6SSimon J. Gerraty } 435956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 436956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 437956e45f6SSimon J. Gerraty Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); 438956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 439956e45f6SSimon J. Gerraty } 440956e45f6SSimon J. Gerraty 441956e45f6SSimon J. Gerraty static void 442956e45f6SSimon J. Gerraty MainParseArgSysInc(const char *argvalue) 443956e45f6SSimon J. Gerraty { 444956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 445956e45f6SSimon J. Gerraty if (strncmp(".../", argvalue, 4) == 0) { 446956e45f6SSimon J. Gerraty char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 447956e45f6SSimon J. Gerraty if (found_path == NULL) 448956e45f6SSimon J. Gerraty return; 449956e45f6SSimon J. Gerraty (void)Dir_AddDir(sysIncPath, found_path); 450956e45f6SSimon J. Gerraty free(found_path); 451956e45f6SSimon J. Gerraty } else { 452956e45f6SSimon J. Gerraty (void)Dir_AddDir(sysIncPath, argvalue); 453956e45f6SSimon J. Gerraty } 454956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 455956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 456956e45f6SSimon J. Gerraty } 457956e45f6SSimon J. Gerraty 458956e45f6SSimon J. Gerraty static Boolean 459956e45f6SSimon J. Gerraty MainParseArg(char c, const char *argvalue) 460956e45f6SSimon J. Gerraty { 461956e45f6SSimon J. Gerraty switch (c) { 462956e45f6SSimon J. Gerraty case '\0': 463956e45f6SSimon J. Gerraty break; 464956e45f6SSimon J. Gerraty case 'B': 465956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 466956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 467956e45f6SSimon J. Gerraty Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); 468956e45f6SSimon J. Gerraty break; 469956e45f6SSimon J. Gerraty case 'C': 470956e45f6SSimon J. Gerraty MainParseArgChdir(argvalue); 471956e45f6SSimon J. Gerraty break; 472956e45f6SSimon J. Gerraty case 'D': 473956e45f6SSimon J. Gerraty if (argvalue[0] == '\0') return FALSE; 474956e45f6SSimon J. Gerraty Var_Set(argvalue, "1", VAR_GLOBAL); 475956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 476956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 477956e45f6SSimon J. Gerraty break; 478956e45f6SSimon J. Gerraty case 'I': 479956e45f6SSimon J. Gerraty Parse_AddIncludeDir(argvalue); 480956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 481956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 482956e45f6SSimon J. Gerraty break; 483956e45f6SSimon J. Gerraty case 'J': 484956e45f6SSimon J. Gerraty MainParseArgJobsInternal(argvalue); 485956e45f6SSimon J. Gerraty break; 486956e45f6SSimon J. Gerraty case 'N': 487956e45f6SSimon J. Gerraty opts.noExecute = TRUE; 488956e45f6SSimon J. Gerraty opts.noRecursiveExecute = TRUE; 489956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 490956e45f6SSimon J. Gerraty break; 491956e45f6SSimon J. Gerraty case 'S': 492956e45f6SSimon J. Gerraty opts.keepgoing = FALSE; 493956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 494956e45f6SSimon J. Gerraty break; 495956e45f6SSimon J. Gerraty case 'T': 496956e45f6SSimon J. Gerraty tracefile = bmake_strdup(argvalue); 497956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 498956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 499956e45f6SSimon J. Gerraty break; 500956e45f6SSimon J. Gerraty case 'V': 501956e45f6SSimon J. Gerraty case 'v': 502e2eeea75SSimon J. Gerraty opts.printVars = c == 'v' ? PVM_EXPANDED : PVM_UNEXPANDED; 503*06b9b3e0SSimon J. Gerraty Lst_Append(&opts.variables, bmake_strdup(argvalue)); 504956e45f6SSimon J. Gerraty /* XXX: Why always -V? */ 505956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 506956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 507956e45f6SSimon J. Gerraty break; 508956e45f6SSimon J. Gerraty case 'W': 509956e45f6SSimon J. Gerraty opts.parseWarnFatal = TRUE; 510e2eeea75SSimon J. Gerraty /* XXX: why no Var_Append? */ 511956e45f6SSimon J. Gerraty break; 512956e45f6SSimon J. Gerraty case 'X': 513956e45f6SSimon J. Gerraty opts.varNoExportEnv = TRUE; 514956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 515956e45f6SSimon J. Gerraty break; 516956e45f6SSimon J. Gerraty case 'd': 517956e45f6SSimon J. Gerraty /* If '-d-opts' don't pass to children */ 518956e45f6SSimon J. Gerraty if (argvalue[0] == '-') 519956e45f6SSimon J. Gerraty argvalue++; 520956e45f6SSimon J. Gerraty else { 521956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 522956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 523956e45f6SSimon J. Gerraty } 524956e45f6SSimon J. Gerraty parse_debug_options(argvalue); 525956e45f6SSimon J. Gerraty break; 526956e45f6SSimon J. Gerraty case 'e': 527956e45f6SSimon J. Gerraty opts.checkEnvFirst = TRUE; 528956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 529956e45f6SSimon J. Gerraty break; 530956e45f6SSimon J. Gerraty case 'f': 531*06b9b3e0SSimon J. Gerraty Lst_Append(&opts.makefiles, bmake_strdup(argvalue)); 532956e45f6SSimon J. Gerraty break; 533956e45f6SSimon J. Gerraty case 'i': 534956e45f6SSimon J. Gerraty opts.ignoreErrors = TRUE; 535956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 536956e45f6SSimon J. Gerraty break; 537956e45f6SSimon J. Gerraty case 'j': 538956e45f6SSimon J. Gerraty MainParseArgJobs(argvalue); 539956e45f6SSimon J. Gerraty break; 540956e45f6SSimon J. Gerraty case 'k': 541956e45f6SSimon J. Gerraty opts.keepgoing = TRUE; 542956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 543956e45f6SSimon J. Gerraty break; 544956e45f6SSimon J. Gerraty case 'm': 545956e45f6SSimon J. Gerraty MainParseArgSysInc(argvalue); 546e2eeea75SSimon J. Gerraty /* XXX: why no Var_Append? */ 547956e45f6SSimon J. Gerraty break; 548956e45f6SSimon J. Gerraty case 'n': 549956e45f6SSimon J. Gerraty opts.noExecute = TRUE; 550956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 551956e45f6SSimon J. Gerraty break; 552956e45f6SSimon J. Gerraty case 'q': 553956e45f6SSimon J. Gerraty opts.queryFlag = TRUE; 554956e45f6SSimon J. Gerraty /* Kind of nonsensical, wot? */ 555956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 556956e45f6SSimon J. Gerraty break; 557956e45f6SSimon J. Gerraty case 'r': 558956e45f6SSimon J. Gerraty opts.noBuiltins = TRUE; 559956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 560956e45f6SSimon J. Gerraty break; 561956e45f6SSimon J. Gerraty case 's': 562956e45f6SSimon J. Gerraty opts.beSilent = TRUE; 563956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 564956e45f6SSimon J. Gerraty break; 565956e45f6SSimon J. Gerraty case 't': 566956e45f6SSimon J. Gerraty opts.touchFlag = TRUE; 567956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 568956e45f6SSimon J. Gerraty break; 569956e45f6SSimon J. Gerraty case 'w': 570956e45f6SSimon J. Gerraty opts.enterFlag = TRUE; 571956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 572956e45f6SSimon J. Gerraty break; 573956e45f6SSimon J. Gerraty default: 574956e45f6SSimon J. Gerraty case '?': 575956e45f6SSimon J. Gerraty usage(); 576956e45f6SSimon J. Gerraty } 577956e45f6SSimon J. Gerraty return TRUE; 578956e45f6SSimon J. Gerraty } 579956e45f6SSimon J. Gerraty 580*06b9b3e0SSimon J. Gerraty /* 581*06b9b3e0SSimon J. Gerraty * Parse the given arguments. Called from main() and from 5823955d011SMarcel Moolenaar * Main_ParseArgLine() when the .MAKEFLAGS target is used. 5833955d011SMarcel Moolenaar * 584956e45f6SSimon J. Gerraty * The arguments must be treated as read-only and will be freed after the 585956e45f6SSimon J. Gerraty * call. 5863955d011SMarcel Moolenaar * 587*06b9b3e0SSimon J. Gerraty * XXX: Deal with command line overriding .MAKEFLAGS in makefile 588*06b9b3e0SSimon J. Gerraty */ 5893955d011SMarcel Moolenaar static void 5903955d011SMarcel Moolenaar MainParseArgs(int argc, char **argv) 5913955d011SMarcel Moolenaar { 592956e45f6SSimon J. Gerraty char c; 5933955d011SMarcel Moolenaar int arginc; 5943955d011SMarcel Moolenaar char *argvalue; 5953955d011SMarcel Moolenaar char *optscan; 5963955d011SMarcel Moolenaar Boolean inOption, dashDash = FALSE; 5973955d011SMarcel Moolenaar 598956e45f6SSimon J. Gerraty const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 5993955d011SMarcel Moolenaar /* Can't actually use getopt(3) because rescanning is not portable */ 6003955d011SMarcel Moolenaar 6013955d011SMarcel Moolenaar rearg: 6023955d011SMarcel Moolenaar inOption = FALSE; 6033955d011SMarcel Moolenaar optscan = NULL; 6043955d011SMarcel Moolenaar while (argc > 1) { 605956e45f6SSimon J. Gerraty const char *optspec; 6063955d011SMarcel Moolenaar if (!inOption) 6073955d011SMarcel Moolenaar optscan = argv[1]; 6083955d011SMarcel Moolenaar c = *optscan++; 6093955d011SMarcel Moolenaar arginc = 0; 6103955d011SMarcel Moolenaar if (inOption) { 6113955d011SMarcel Moolenaar if (c == '\0') { 612e2eeea75SSimon J. Gerraty argv++; 613e2eeea75SSimon J. Gerraty argc--; 6143955d011SMarcel Moolenaar inOption = FALSE; 6153955d011SMarcel Moolenaar continue; 6163955d011SMarcel Moolenaar } 6173955d011SMarcel Moolenaar } else { 6183955d011SMarcel Moolenaar if (c != '-' || dashDash) 6193955d011SMarcel Moolenaar break; 6203955d011SMarcel Moolenaar inOption = TRUE; 6213955d011SMarcel Moolenaar c = *optscan++; 6223955d011SMarcel Moolenaar } 6233955d011SMarcel Moolenaar /* '-' found at some earlier point */ 624956e45f6SSimon J. Gerraty optspec = strchr(optspecs, c); 625956e45f6SSimon J. Gerraty if (c != '\0' && optspec != NULL && optspec[1] == ':') { 6263955d011SMarcel Moolenaar /* -<something> found, and <something> should have an arg */ 6273955d011SMarcel Moolenaar inOption = FALSE; 6283955d011SMarcel Moolenaar arginc = 1; 6293955d011SMarcel Moolenaar argvalue = optscan; 6303955d011SMarcel Moolenaar if (*argvalue == '\0') { 6313955d011SMarcel Moolenaar if (argc < 3) 6323955d011SMarcel Moolenaar goto noarg; 6333955d011SMarcel Moolenaar argvalue = argv[2]; 6343955d011SMarcel Moolenaar arginc = 2; 6353955d011SMarcel Moolenaar } 6363955d011SMarcel Moolenaar } else { 6373955d011SMarcel Moolenaar argvalue = NULL; 6383955d011SMarcel Moolenaar } 6393955d011SMarcel Moolenaar switch (c) { 6403955d011SMarcel Moolenaar case '\0': 6413955d011SMarcel Moolenaar arginc = 1; 6423955d011SMarcel Moolenaar inOption = FALSE; 6433955d011SMarcel Moolenaar break; 6443955d011SMarcel Moolenaar case '-': 6453955d011SMarcel Moolenaar dashDash = TRUE; 6463955d011SMarcel Moolenaar break; 6473955d011SMarcel Moolenaar default: 648956e45f6SSimon J. Gerraty if (!MainParseArg(c, argvalue)) 649956e45f6SSimon J. Gerraty goto noarg; 6503955d011SMarcel Moolenaar } 6513955d011SMarcel Moolenaar argv += arginc; 6523955d011SMarcel Moolenaar argc -= arginc; 6533955d011SMarcel Moolenaar } 6543955d011SMarcel Moolenaar 6553955d011SMarcel Moolenaar /* 6563955d011SMarcel Moolenaar * See if the rest of the arguments are variable assignments and 6573955d011SMarcel Moolenaar * perform them if so. Else take them to be targets and stuff them 6583955d011SMarcel Moolenaar * on the end of the "create" list. 6593955d011SMarcel Moolenaar */ 660956e45f6SSimon J. Gerraty for (; argc > 1; ++argv, --argc) { 661956e45f6SSimon J. Gerraty VarAssign var; 662956e45f6SSimon J. Gerraty if (Parse_IsVar(argv[1], &var)) { 663956e45f6SSimon J. Gerraty Parse_DoVar(&var, VAR_CMDLINE); 6643955d011SMarcel Moolenaar } else { 665e2eeea75SSimon J. Gerraty if (argv[1][0] == '\0') 6663955d011SMarcel Moolenaar Punt("illegal (null) argument."); 667e2eeea75SSimon J. Gerraty if (argv[1][0] == '-' && !dashDash) 6683955d011SMarcel Moolenaar goto rearg; 669*06b9b3e0SSimon J. Gerraty Lst_Append(&opts.create, bmake_strdup(argv[1])); 670956e45f6SSimon J. Gerraty } 6713955d011SMarcel Moolenaar } 6723955d011SMarcel Moolenaar 6733955d011SMarcel Moolenaar return; 6743955d011SMarcel Moolenaar noarg: 6753955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 6763955d011SMarcel Moolenaar progname, c); 6773955d011SMarcel Moolenaar usage(); 6783955d011SMarcel Moolenaar } 6793955d011SMarcel Moolenaar 680*06b9b3e0SSimon J. Gerraty /* 681*06b9b3e0SSimon J. Gerraty * Break a line of arguments into words and parse them. 6823955d011SMarcel Moolenaar * 683956e45f6SSimon J. Gerraty * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 684*06b9b3e0SSimon J. Gerraty * by main() when reading the MAKEFLAGS environment variable. 685*06b9b3e0SSimon J. Gerraty */ 6863955d011SMarcel Moolenaar void 6873955d011SMarcel Moolenaar Main_ParseArgLine(const char *line) 6883955d011SMarcel Moolenaar { 6892c3632d1SSimon J. Gerraty Words words; 6902c3632d1SSimon J. Gerraty char *buf; 6913955d011SMarcel Moolenaar 6923955d011SMarcel Moolenaar if (line == NULL) 6933955d011SMarcel Moolenaar return; 694*06b9b3e0SSimon J. Gerraty /* XXX: don't use line as an iterator variable */ 6953955d011SMarcel Moolenaar for (; *line == ' '; ++line) 6963955d011SMarcel Moolenaar continue; 697e2eeea75SSimon J. Gerraty if (line[0] == '\0') 6983955d011SMarcel Moolenaar return; 6993955d011SMarcel Moolenaar 7003955d011SMarcel Moolenaar #ifndef POSIX 7013955d011SMarcel Moolenaar { 7023955d011SMarcel Moolenaar /* 7033955d011SMarcel Moolenaar * $MAKE may simply be naming the make(1) binary 7043955d011SMarcel Moolenaar */ 7053955d011SMarcel Moolenaar char *cp; 7063955d011SMarcel Moolenaar 7073955d011SMarcel Moolenaar if (!(cp = strrchr(line, '/'))) 7083955d011SMarcel Moolenaar cp = line; 7093955d011SMarcel Moolenaar if ((cp = strstr(cp, "make")) && 7103955d011SMarcel Moolenaar strcmp(cp, "make") == 0) 7113955d011SMarcel Moolenaar return; 7123955d011SMarcel Moolenaar } 7133955d011SMarcel Moolenaar #endif 714e2eeea75SSimon J. Gerraty { 715*06b9b3e0SSimon J. Gerraty FStr argv0 = Var_Value(".MAKE", VAR_GLOBAL); 716*06b9b3e0SSimon J. Gerraty buf = str_concat3(argv0.str, " ", line); 717*06b9b3e0SSimon J. Gerraty FStr_Done(&argv0); 718e2eeea75SSimon J. Gerraty } 7193955d011SMarcel Moolenaar 7202c3632d1SSimon J. Gerraty words = Str_Words(buf, TRUE); 7212c3632d1SSimon J. Gerraty if (words.words == NULL) { 7223955d011SMarcel Moolenaar Error("Unterminated quoted string [%s]", buf); 7233955d011SMarcel Moolenaar free(buf); 7243955d011SMarcel Moolenaar return; 7253955d011SMarcel Moolenaar } 7263955d011SMarcel Moolenaar free(buf); 7272c3632d1SSimon J. Gerraty MainParseArgs((int)words.len, words.words); 7283955d011SMarcel Moolenaar 7292c3632d1SSimon J. Gerraty Words_Free(words); 7303955d011SMarcel Moolenaar } 7313955d011SMarcel Moolenaar 7323955d011SMarcel Moolenaar Boolean 733e2eeea75SSimon J. Gerraty Main_SetObjdir(Boolean writable, const char *fmt, ...) 7343955d011SMarcel Moolenaar { 7353955d011SMarcel Moolenaar struct stat sb; 736b46b9039SSimon J. Gerraty char *path; 737b46b9039SSimon J. Gerraty char buf[MAXPATHLEN + 1]; 738e23f3f6eSSimon J. Gerraty char buf2[MAXPATHLEN + 1]; 7393955d011SMarcel Moolenaar Boolean rc = FALSE; 74045447996SSimon J. Gerraty va_list ap; 74145447996SSimon J. Gerraty 74245447996SSimon J. Gerraty va_start(ap, fmt); 743b46b9039SSimon J. Gerraty vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 74445447996SSimon J. Gerraty va_end(ap); 7453955d011SMarcel Moolenaar 7463955d011SMarcel Moolenaar if (path[0] != '/') { 747e1cee40dSSimon J. Gerraty snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 748e1cee40dSSimon J. Gerraty path = buf2; 7493955d011SMarcel Moolenaar } 7503955d011SMarcel Moolenaar 7513955d011SMarcel Moolenaar /* look for the directory and try to chdir there */ 7523955d011SMarcel Moolenaar if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 753e2eeea75SSimon J. Gerraty if ((writable && access(path, W_OK) != 0) || 754e2eeea75SSimon J. Gerraty (chdir(path) != 0)) { 755e2eeea75SSimon J. Gerraty (void)fprintf(stderr, "%s warning: %s: %s.\n", 756e2eeea75SSimon J. Gerraty progname, path, strerror(errno)); 7573955d011SMarcel Moolenaar } else { 7582c3632d1SSimon J. Gerraty snprintf(objdir, sizeof objdir, "%s", path); 7593841c287SSimon J. Gerraty Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 7603955d011SMarcel Moolenaar setenv("PWD", objdir, 1); 7613955d011SMarcel Moolenaar Dir_InitDot(); 762e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(); 7633955d011SMarcel Moolenaar rc = TRUE; 764956e45f6SSimon J. Gerraty if (opts.enterFlag && strcmp(objdir, curdir) != 0) 7654c620fe5SSimon J. Gerraty enterFlagObj = TRUE; 7663955d011SMarcel Moolenaar } 7673955d011SMarcel Moolenaar } 7683955d011SMarcel Moolenaar 7693955d011SMarcel Moolenaar return rc; 7703955d011SMarcel Moolenaar } 7713955d011SMarcel Moolenaar 77245447996SSimon J. Gerraty static Boolean 773e2eeea75SSimon J. Gerraty SetVarObjdir(Boolean writable, const char *var, const char *suffix) 77445447996SSimon J. Gerraty { 775*06b9b3e0SSimon J. Gerraty FStr path = Var_Value(var, VAR_CMDLINE); 776*06b9b3e0SSimon J. Gerraty FStr xpath; 777b46b9039SSimon J. Gerraty 778*06b9b3e0SSimon J. Gerraty if (path.str == NULL || path.str[0] == '\0') { 779*06b9b3e0SSimon J. Gerraty FStr_Done(&path); 78045447996SSimon J. Gerraty return FALSE; 7812c3632d1SSimon J. Gerraty } 78245447996SSimon J. Gerraty 783b46b9039SSimon J. Gerraty /* expand variable substitutions */ 784*06b9b3e0SSimon J. Gerraty xpath = FStr_InitRefer(path.str); 785*06b9b3e0SSimon J. Gerraty if (strchr(path.str, '$') != 0) { 786*06b9b3e0SSimon J. Gerraty char *expanded; 787*06b9b3e0SSimon J. Gerraty (void)Var_Subst(path.str, VAR_GLOBAL, VARE_WANTRES, &expanded); 788956e45f6SSimon J. Gerraty /* TODO: handle errors */ 789*06b9b3e0SSimon J. Gerraty xpath = FStr_InitOwn(expanded); 790956e45f6SSimon J. Gerraty } 791b46b9039SSimon J. Gerraty 792*06b9b3e0SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", xpath.str, suffix); 793b46b9039SSimon J. Gerraty 794*06b9b3e0SSimon J. Gerraty FStr_Done(&xpath); 795*06b9b3e0SSimon J. Gerraty FStr_Done(&path); 79645447996SSimon J. Gerraty return TRUE; 79745447996SSimon J. Gerraty } 79845447996SSimon J. Gerraty 799*06b9b3e0SSimon J. Gerraty /* 800*06b9b3e0SSimon J. Gerraty * Splits str into words, adding them to the list. 801*06b9b3e0SSimon J. Gerraty * The string must be kept alive as long as the list. 802*06b9b3e0SSimon J. Gerraty */ 8033955d011SMarcel Moolenaar int 804e2eeea75SSimon J. Gerraty str2Lst_Append(StringList *lp, char *str) 8053955d011SMarcel Moolenaar { 8063955d011SMarcel Moolenaar char *cp; 8073955d011SMarcel Moolenaar int n; 8083955d011SMarcel Moolenaar 809e2eeea75SSimon J. Gerraty const char *sep = " \t"; 8103955d011SMarcel Moolenaar 811*06b9b3e0SSimon J. Gerraty for (n = 0, cp = strtok(str, sep); cp != NULL; cp = strtok(NULL, sep)) { 8122c3632d1SSimon J. Gerraty Lst_Append(lp, cp); 8133955d011SMarcel Moolenaar n++; 8143955d011SMarcel Moolenaar } 8153841c287SSimon J. Gerraty return n; 8163955d011SMarcel Moolenaar } 8173955d011SMarcel Moolenaar 8183955d011SMarcel Moolenaar #ifdef SIGINFO 8193955d011SMarcel Moolenaar /*ARGSUSED*/ 8203955d011SMarcel Moolenaar static void 8213955d011SMarcel Moolenaar siginfo(int signo MAKE_ATTR_UNUSED) 8223955d011SMarcel Moolenaar { 8233955d011SMarcel Moolenaar char dir[MAXPATHLEN]; 8243955d011SMarcel Moolenaar char str[2 * MAXPATHLEN]; 8253955d011SMarcel Moolenaar int len; 826e2eeea75SSimon J. Gerraty if (getcwd(dir, sizeof dir) == NULL) 8273955d011SMarcel Moolenaar return; 828e2eeea75SSimon J. Gerraty len = snprintf(str, sizeof str, "%s: Working in: %s\n", progname, dir); 8293955d011SMarcel Moolenaar if (len > 0) 8303955d011SMarcel Moolenaar (void)write(STDERR_FILENO, str, (size_t)len); 8313955d011SMarcel Moolenaar } 8323955d011SMarcel Moolenaar #endif 8333955d011SMarcel Moolenaar 834*06b9b3e0SSimon J. Gerraty /* Allow makefiles some control over the mode we run in. */ 835*06b9b3e0SSimon J. Gerraty static void 836*06b9b3e0SSimon J. Gerraty MakeMode(void) 8373955d011SMarcel Moolenaar { 838*06b9b3e0SSimon J. Gerraty FStr mode = FStr_InitRefer(NULL); 8393955d011SMarcel Moolenaar 840*06b9b3e0SSimon J. Gerraty if (mode.str == NULL) { 841*06b9b3e0SSimon J. Gerraty char *expanded; 842956e45f6SSimon J. Gerraty (void)Var_Subst("${" MAKE_MODE ":tl}", 843*06b9b3e0SSimon J. Gerraty VAR_GLOBAL, VARE_WANTRES, &expanded); 844956e45f6SSimon J. Gerraty /* TODO: handle errors */ 845*06b9b3e0SSimon J. Gerraty mode = FStr_InitOwn(expanded); 846956e45f6SSimon J. Gerraty } 8473955d011SMarcel Moolenaar 848*06b9b3e0SSimon J. Gerraty if (mode.str[0] != '\0') { 849*06b9b3e0SSimon J. Gerraty if (strstr(mode.str, "compat") != NULL) { 850956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 8513955d011SMarcel Moolenaar forceJobs = FALSE; 8523955d011SMarcel Moolenaar } 8533955d011SMarcel Moolenaar #if USE_META 854*06b9b3e0SSimon J. Gerraty if (strstr(mode.str, "meta") != NULL) 855*06b9b3e0SSimon J. Gerraty meta_mode_init(mode.str); 8563955d011SMarcel Moolenaar #endif 8573955d011SMarcel Moolenaar } 858be19d90bSSimon J. Gerraty 859*06b9b3e0SSimon J. Gerraty FStr_Done(&mode); 8603955d011SMarcel Moolenaar } 8613955d011SMarcel Moolenaar 8628695518cSSimon J. Gerraty static void 863956e45f6SSimon J. Gerraty PrintVar(const char *varname, Boolean expandVars) 864956e45f6SSimon J. Gerraty { 865*06b9b3e0SSimon J. Gerraty if (strchr(varname, '$') != NULL) { 866956e45f6SSimon J. Gerraty char *evalue; 867956e45f6SSimon J. Gerraty (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue); 868956e45f6SSimon J. Gerraty /* TODO: handle errors */ 869956e45f6SSimon J. Gerraty printf("%s\n", evalue); 870956e45f6SSimon J. Gerraty bmake_free(evalue); 871956e45f6SSimon J. Gerraty 872956e45f6SSimon J. Gerraty } else if (expandVars) { 873956e45f6SSimon J. Gerraty char *expr = str_concat3("${", varname, "}"); 874956e45f6SSimon J. Gerraty char *evalue; 875956e45f6SSimon J. Gerraty (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue); 876956e45f6SSimon J. Gerraty /* TODO: handle errors */ 877956e45f6SSimon J. Gerraty free(expr); 878956e45f6SSimon J. Gerraty printf("%s\n", evalue); 879956e45f6SSimon J. Gerraty bmake_free(evalue); 880956e45f6SSimon J. Gerraty 881956e45f6SSimon J. Gerraty } else { 882*06b9b3e0SSimon J. Gerraty FStr value = Var_Value(varname, VAR_GLOBAL); 883*06b9b3e0SSimon J. Gerraty printf("%s\n", value.str != NULL ? value.str : ""); 884*06b9b3e0SSimon J. Gerraty FStr_Done(&value); 885956e45f6SSimon J. Gerraty } 886956e45f6SSimon J. Gerraty } 887956e45f6SSimon J. Gerraty 888e2eeea75SSimon J. Gerraty /* 889e2eeea75SSimon J. Gerraty * Return a Boolean based on a variable. 890e2eeea75SSimon J. Gerraty * 891e2eeea75SSimon J. Gerraty * If the knob is not set, return the fallback. 892e2eeea75SSimon J. Gerraty * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 893e2eeea75SSimon J. Gerraty * is FALSE, otherwise TRUE. 894e2eeea75SSimon J. Gerraty */ 895e2eeea75SSimon J. Gerraty Boolean 896e2eeea75SSimon J. Gerraty GetBooleanVar(const char *varname, Boolean fallback) 897e2eeea75SSimon J. Gerraty { 898e2eeea75SSimon J. Gerraty char *expr = str_concat3("${", varname, ":U}"); 899e2eeea75SSimon J. Gerraty char *value; 900e2eeea75SSimon J. Gerraty Boolean res; 901e2eeea75SSimon J. Gerraty 902e2eeea75SSimon J. Gerraty (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); 903e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 904e2eeea75SSimon J. Gerraty res = ParseBoolean(value, fallback); 905e2eeea75SSimon J. Gerraty free(value); 906e2eeea75SSimon J. Gerraty free(expr); 907e2eeea75SSimon J. Gerraty return res; 908e2eeea75SSimon J. Gerraty } 909e2eeea75SSimon J. Gerraty 910956e45f6SSimon J. Gerraty static void 9118695518cSSimon J. Gerraty doPrintVars(void) 9128695518cSSimon J. Gerraty { 913956e45f6SSimon J. Gerraty StringListNode *ln; 9148695518cSSimon J. Gerraty Boolean expandVars; 9158695518cSSimon J. Gerraty 916e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_EXPANDED) 9178695518cSSimon J. Gerraty expandVars = TRUE; 918956e45f6SSimon J. Gerraty else if (opts.debugVflag) 9198695518cSSimon J. Gerraty expandVars = FALSE; 9208695518cSSimon J. Gerraty else 921e2eeea75SSimon J. Gerraty expandVars = GetBooleanVar(".MAKE.EXPAND_VARIABLES", FALSE); 9228695518cSSimon J. Gerraty 923*06b9b3e0SSimon J. Gerraty for (ln = opts.variables.first; ln != NULL; ln = ln->next) { 924956e45f6SSimon J. Gerraty const char *varname = ln->datum; 925956e45f6SSimon J. Gerraty PrintVar(varname, expandVars); 9268695518cSSimon J. Gerraty } 9278695518cSSimon J. Gerraty } 9288695518cSSimon J. Gerraty 9298695518cSSimon J. Gerraty static Boolean 9308695518cSSimon J. Gerraty runTargets(void) 9318695518cSSimon J. Gerraty { 932*06b9b3e0SSimon J. Gerraty GNodeList targs = LST_INIT; /* target nodes to create */ 9338695518cSSimon J. Gerraty Boolean outOfDate; /* FALSE if all targets up to date */ 9348695518cSSimon J. Gerraty 9358695518cSSimon J. Gerraty /* 9368695518cSSimon J. Gerraty * Have now read the entire graph and need to make a list of 9378695518cSSimon J. Gerraty * targets to create. If none was given on the command line, 9388695518cSSimon J. Gerraty * we consult the parsing module to find the main target(s) 9398695518cSSimon J. Gerraty * to create. 9408695518cSSimon J. Gerraty */ 941*06b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) 942*06b9b3e0SSimon J. Gerraty Parse_MainName(&targs); 9438695518cSSimon J. Gerraty else 944*06b9b3e0SSimon J. Gerraty Targ_FindList(&targs, &opts.create); 9458695518cSSimon J. Gerraty 946956e45f6SSimon J. Gerraty if (!opts.compatMake) { 9478695518cSSimon J. Gerraty /* 9488695518cSSimon J. Gerraty * Initialize job module before traversing the graph 9498695518cSSimon J. Gerraty * now that any .BEGIN and .END targets have been read. 9508695518cSSimon J. Gerraty * This is done only if the -q flag wasn't given 9518695518cSSimon J. Gerraty * (to prevent the .BEGIN from being executed should 9528695518cSSimon J. Gerraty * it exist). 9538695518cSSimon J. Gerraty */ 954956e45f6SSimon J. Gerraty if (!opts.queryFlag) { 9558695518cSSimon J. Gerraty Job_Init(); 9568695518cSSimon J. Gerraty jobsRunning = TRUE; 9578695518cSSimon J. Gerraty } 9588695518cSSimon J. Gerraty 9598695518cSSimon J. Gerraty /* Traverse the graph, checking on all the targets */ 960*06b9b3e0SSimon J. Gerraty outOfDate = Make_Run(&targs); 9618695518cSSimon J. Gerraty } else { 9628695518cSSimon J. Gerraty /* 9638695518cSSimon J. Gerraty * Compat_Init will take care of creating all the 9648695518cSSimon J. Gerraty * targets as well as initializing the module. 9658695518cSSimon J. Gerraty */ 966*06b9b3e0SSimon J. Gerraty Compat_Run(&targs); 9678695518cSSimon J. Gerraty outOfDate = FALSE; 9688695518cSSimon J. Gerraty } 969*06b9b3e0SSimon J. Gerraty Lst_Done(&targs); /* Don't free the nodes. */ 9708695518cSSimon J. Gerraty return outOfDate; 9718695518cSSimon J. Gerraty } 9728695518cSSimon J. Gerraty 973956e45f6SSimon J. Gerraty /* 974956e45f6SSimon J. Gerraty * Set up the .TARGETS variable to contain the list of targets to be 975956e45f6SSimon J. Gerraty * created. If none specified, make the variable empty -- the parser 976956e45f6SSimon J. Gerraty * will fill the thing in with the default or .MAIN target. 977956e45f6SSimon J. Gerraty */ 978956e45f6SSimon J. Gerraty static void 979956e45f6SSimon J. Gerraty InitVarTargets(void) 980956e45f6SSimon J. Gerraty { 981956e45f6SSimon J. Gerraty StringListNode *ln; 982956e45f6SSimon J. Gerraty 983*06b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&opts.create)) { 984956e45f6SSimon J. Gerraty Var_Set(".TARGETS", "", VAR_GLOBAL); 985956e45f6SSimon J. Gerraty return; 986956e45f6SSimon J. Gerraty } 987956e45f6SSimon J. Gerraty 988*06b9b3e0SSimon J. Gerraty for (ln = opts.create.first; ln != NULL; ln = ln->next) { 989956e45f6SSimon J. Gerraty char *name = ln->datum; 990956e45f6SSimon J. Gerraty Var_Append(".TARGETS", name, VAR_GLOBAL); 991956e45f6SSimon J. Gerraty } 992956e45f6SSimon J. Gerraty } 993956e45f6SSimon J. Gerraty 994956e45f6SSimon J. Gerraty static void 995956e45f6SSimon J. Gerraty InitRandom(void) 996956e45f6SSimon J. Gerraty { 997956e45f6SSimon J. Gerraty struct timeval tv; 998956e45f6SSimon J. Gerraty 999956e45f6SSimon J. Gerraty gettimeofday(&tv, NULL); 1000956e45f6SSimon J. Gerraty srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 1001956e45f6SSimon J. Gerraty } 1002956e45f6SSimon J. Gerraty 1003956e45f6SSimon J. Gerraty static const char * 1004e2eeea75SSimon J. Gerraty InitVarMachine(const struct utsname *utsname) 1005956e45f6SSimon J. Gerraty { 1006956e45f6SSimon J. Gerraty #ifdef FORCE_MACHINE 1007e2eeea75SSimon J. Gerraty return FORCE_MACHINE; 1008956e45f6SSimon J. Gerraty #else 1009956e45f6SSimon J. Gerraty const char *machine = getenv("MACHINE"); 1010e2eeea75SSimon J. Gerraty 1011956e45f6SSimon J. Gerraty if (machine != NULL) 1012956e45f6SSimon J. Gerraty return machine; 1013956e45f6SSimon J. Gerraty 1014e2eeea75SSimon J. Gerraty #if defined(MAKE_NATIVE) 1015956e45f6SSimon J. Gerraty return utsname->machine; 1016e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE) 1017956e45f6SSimon J. Gerraty return MAKE_MACHINE; 1018956e45f6SSimon J. Gerraty #else 1019956e45f6SSimon J. Gerraty return "unknown"; 1020956e45f6SSimon J. Gerraty #endif 1021956e45f6SSimon J. Gerraty #endif 1022956e45f6SSimon J. Gerraty } 1023956e45f6SSimon J. Gerraty 1024956e45f6SSimon J. Gerraty static const char * 1025e2eeea75SSimon J. Gerraty InitVarMachineArch(void) 1026956e45f6SSimon J. Gerraty { 1027e2eeea75SSimon J. Gerraty #ifdef FORCE_MACHINE_ARCH 1028e2eeea75SSimon J. Gerraty return FORCE_MACHINE_ARCH; 1029e2eeea75SSimon J. Gerraty #else 1030956e45f6SSimon J. Gerraty const char *env = getenv("MACHINE_ARCH"); 1031956e45f6SSimon J. Gerraty if (env != NULL) 1032956e45f6SSimon J. Gerraty return env; 1033956e45f6SSimon J. Gerraty 1034956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) && defined(CTL_HW) 1035956e45f6SSimon J. Gerraty { 1036956e45f6SSimon J. Gerraty struct utsname utsname; 1037e2eeea75SSimon J. Gerraty static char machine_arch_buf[sizeof utsname.machine]; 1038956e45f6SSimon J. Gerraty const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1039e2eeea75SSimon J. Gerraty size_t len = sizeof machine_arch_buf; 1040956e45f6SSimon J. Gerraty 1041*06b9b3e0SSimon J. Gerraty if (sysctl(mib, (unsigned int)__arraycount(mib), 1042*06b9b3e0SSimon J. Gerraty machine_arch_buf, &len, NULL, 0) < 0) { 1043*06b9b3e0SSimon J. Gerraty (void)fprintf(stderr, "%s: sysctl failed (%s).\n", 1044*06b9b3e0SSimon J. Gerraty progname, strerror(errno)); 1045956e45f6SSimon J. Gerraty exit(2); 1046956e45f6SSimon J. Gerraty } 1047956e45f6SSimon J. Gerraty 1048956e45f6SSimon J. Gerraty return machine_arch_buf; 1049956e45f6SSimon J. Gerraty } 1050e2eeea75SSimon J. Gerraty #elif defined(MACHINE_ARCH) 1051e2eeea75SSimon J. Gerraty return MACHINE_ARCH; 1052e2eeea75SSimon J. Gerraty #elif defined(MAKE_MACHINE_ARCH) 1053956e45f6SSimon J. Gerraty return MAKE_MACHINE_ARCH; 1054956e45f6SSimon J. Gerraty #else 1055956e45f6SSimon J. Gerraty return "unknown"; 1056956e45f6SSimon J. Gerraty #endif 1057956e45f6SSimon J. Gerraty #endif 1058956e45f6SSimon J. Gerraty } 1059956e45f6SSimon J. Gerraty 1060956e45f6SSimon J. Gerraty #ifndef NO_PWD_OVERRIDE 1061956e45f6SSimon J. Gerraty /* 1062956e45f6SSimon J. Gerraty * All this code is so that we know where we are when we start up 1063956e45f6SSimon J. Gerraty * on a different machine with pmake. 1064956e45f6SSimon J. Gerraty * 1065956e45f6SSimon J. Gerraty * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1066956e45f6SSimon J. Gerraty * since the value of curdir can vary depending on how we got 1067956e45f6SSimon J. Gerraty * here. Ie sitting at a shell prompt (shell that provides $PWD) 1068956e45f6SSimon J. Gerraty * or via subdir.mk in which case its likely a shell which does 1069956e45f6SSimon J. Gerraty * not provide it. 1070956e45f6SSimon J. Gerraty * 1071956e45f6SSimon J. Gerraty * So, to stop it breaking this case only, we ignore PWD if 1072956e45f6SSimon J. Gerraty * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1073956e45f6SSimon J. Gerraty */ 1074956e45f6SSimon J. Gerraty static void 1075956e45f6SSimon J. Gerraty HandlePWD(const struct stat *curdir_st) 1076956e45f6SSimon J. Gerraty { 1077956e45f6SSimon J. Gerraty char *pwd; 1078*06b9b3e0SSimon J. Gerraty FStr prefix, makeobjdir; 1079956e45f6SSimon J. Gerraty struct stat pwd_st; 1080956e45f6SSimon J. Gerraty 1081956e45f6SSimon J. Gerraty if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1082956e45f6SSimon J. Gerraty return; 1083956e45f6SSimon J. Gerraty 1084*06b9b3e0SSimon J. Gerraty prefix = Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE); 1085*06b9b3e0SSimon J. Gerraty if (prefix.str != NULL) { 1086*06b9b3e0SSimon J. Gerraty FStr_Done(&prefix); 1087956e45f6SSimon J. Gerraty return; 1088956e45f6SSimon J. Gerraty } 1089956e45f6SSimon J. Gerraty 1090*06b9b3e0SSimon J. Gerraty makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE); 1091*06b9b3e0SSimon J. Gerraty if (makeobjdir.str != NULL && strchr(makeobjdir.str, '$') != NULL) 1092956e45f6SSimon J. Gerraty goto ignore_pwd; 1093956e45f6SSimon J. Gerraty 1094956e45f6SSimon J. Gerraty if (stat(pwd, &pwd_st) == 0 && 1095956e45f6SSimon J. Gerraty curdir_st->st_ino == pwd_st.st_ino && 1096956e45f6SSimon J. Gerraty curdir_st->st_dev == pwd_st.st_dev) 1097956e45f6SSimon J. Gerraty (void)strncpy(curdir, pwd, MAXPATHLEN); 1098956e45f6SSimon J. Gerraty 1099956e45f6SSimon J. Gerraty ignore_pwd: 1100*06b9b3e0SSimon J. Gerraty FStr_Done(&makeobjdir); 1101956e45f6SSimon J. Gerraty } 1102956e45f6SSimon J. Gerraty #endif 1103956e45f6SSimon J. Gerraty 1104956e45f6SSimon J. Gerraty /* 1105956e45f6SSimon J. Gerraty * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1106956e45f6SSimon J. Gerraty * MAKEOBJDIR is set in the environment, try only that value 1107956e45f6SSimon J. Gerraty * and fall back to .CURDIR if it does not exist. 1108956e45f6SSimon J. Gerraty * 1109956e45f6SSimon J. Gerraty * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1110956e45f6SSimon J. Gerraty * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1111956e45f6SSimon J. Gerraty * of these paths exist, just use .CURDIR. 1112956e45f6SSimon J. Gerraty */ 1113956e45f6SSimon J. Gerraty static void 1114956e45f6SSimon J. Gerraty InitObjdir(const char *machine, const char *machine_arch) 1115956e45f6SSimon J. Gerraty { 1116e2eeea75SSimon J. Gerraty Boolean writable; 1117956e45f6SSimon J. Gerraty 1118*06b9b3e0SSimon J. Gerraty Dir_InitCur(curdir); 1119e2eeea75SSimon J. Gerraty writable = GetBooleanVar("MAKE_OBJDIR_CHECK_WRITABLE", TRUE); 1120e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(FALSE, "%s", curdir); 1121e2eeea75SSimon J. Gerraty 1122e2eeea75SSimon J. Gerraty if (!SetVarObjdir(writable, "MAKEOBJDIRPREFIX", curdir) && 1123e2eeea75SSimon J. Gerraty !SetVarObjdir(writable, "MAKEOBJDIR", "") && 1124e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1125e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s.%s", _PATH_OBJDIR, machine) && 1126e2eeea75SSimon J. Gerraty !Main_SetObjdir(writable, "%s", _PATH_OBJDIR)) 1127e2eeea75SSimon J. Gerraty (void)Main_SetObjdir(writable, "%s%s", _PATH_OBJDIRPREFIX, curdir); 1128956e45f6SSimon J. Gerraty } 1129956e45f6SSimon J. Gerraty 1130956e45f6SSimon J. Gerraty /* get rid of resource limit on file descriptors */ 1131956e45f6SSimon J. Gerraty static void 1132956e45f6SSimon J. Gerraty UnlimitFiles(void) 1133956e45f6SSimon J. Gerraty { 1134956e45f6SSimon J. Gerraty #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1135956e45f6SSimon J. Gerraty struct rlimit rl; 1136956e45f6SSimon J. Gerraty if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1137956e45f6SSimon J. Gerraty rl.rlim_cur != rl.rlim_max) { 1138956e45f6SSimon J. Gerraty rl.rlim_cur = rl.rlim_max; 1139956e45f6SSimon J. Gerraty (void)setrlimit(RLIMIT_NOFILE, &rl); 1140956e45f6SSimon J. Gerraty } 1141956e45f6SSimon J. Gerraty #endif 1142956e45f6SSimon J. Gerraty } 1143956e45f6SSimon J. Gerraty 1144956e45f6SSimon J. Gerraty static void 1145956e45f6SSimon J. Gerraty CmdOpts_Init(void) 1146956e45f6SSimon J. Gerraty { 1147*06b9b3e0SSimon J. Gerraty opts.compatMake = FALSE; 1148*06b9b3e0SSimon J. Gerraty opts.debug = DEBUG_NONE; 1149956e45f6SSimon J. Gerraty /* opts.debug_file has been initialized earlier */ 1150*06b9b3e0SSimon J. Gerraty opts.strict = FALSE; 1151956e45f6SSimon J. Gerraty opts.debugVflag = FALSE; 1152956e45f6SSimon J. Gerraty opts.checkEnvFirst = FALSE; 1153*06b9b3e0SSimon J. Gerraty Lst_Init(&opts.makefiles); 1154956e45f6SSimon J. Gerraty opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1155*06b9b3e0SSimon J. Gerraty opts.maxJobs = 1; 1156956e45f6SSimon J. Gerraty opts.keepgoing = FALSE; /* Stop on error */ 1157956e45f6SSimon J. Gerraty opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1158956e45f6SSimon J. Gerraty opts.noExecute = FALSE; /* Execute all commands */ 1159*06b9b3e0SSimon J. Gerraty opts.queryFlag = FALSE; 1160956e45f6SSimon J. Gerraty opts.noBuiltins = FALSE; /* Read the built-in rules */ 1161956e45f6SSimon J. Gerraty opts.beSilent = FALSE; /* Print commands as executed */ 1162*06b9b3e0SSimon J. Gerraty opts.touchFlag = FALSE; 1163e2eeea75SSimon J. Gerraty opts.printVars = PVM_NONE; 1164*06b9b3e0SSimon J. Gerraty Lst_Init(&opts.variables); 1165956e45f6SSimon J. Gerraty opts.parseWarnFatal = FALSE; 1166956e45f6SSimon J. Gerraty opts.enterFlag = FALSE; 1167956e45f6SSimon J. Gerraty opts.varNoExportEnv = FALSE; 1168*06b9b3e0SSimon J. Gerraty Lst_Init(&opts.create); 1169956e45f6SSimon J. Gerraty } 1170956e45f6SSimon J. Gerraty 1171*06b9b3e0SSimon J. Gerraty /* 1172*06b9b3e0SSimon J. Gerraty * Initialize MAKE and .MAKE to the path of the executable, so that it can be 1173956e45f6SSimon J. Gerraty * found by execvp(3) and the shells, even after a chdir. 1174956e45f6SSimon J. Gerraty * 1175956e45f6SSimon J. Gerraty * If it's a relative path and contains a '/', resolve it to an absolute path. 1176*06b9b3e0SSimon J. Gerraty * Otherwise keep it as is, assuming it will be found in the PATH. 1177*06b9b3e0SSimon J. Gerraty */ 1178956e45f6SSimon J. Gerraty static void 1179956e45f6SSimon J. Gerraty InitVarMake(const char *argv0) 1180956e45f6SSimon J. Gerraty { 1181956e45f6SSimon J. Gerraty const char *make = argv0; 1182956e45f6SSimon J. Gerraty 1183956e45f6SSimon J. Gerraty if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1184956e45f6SSimon J. Gerraty char pathbuf[MAXPATHLEN]; 1185*06b9b3e0SSimon J. Gerraty const char *abspath = cached_realpath(argv0, pathbuf); 1186956e45f6SSimon J. Gerraty struct stat st; 1187*06b9b3e0SSimon J. Gerraty if (abspath != NULL && abspath[0] == '/' && 1188*06b9b3e0SSimon J. Gerraty stat(make, &st) == 0) 1189*06b9b3e0SSimon J. Gerraty make = abspath; 1190956e45f6SSimon J. Gerraty } 1191956e45f6SSimon J. Gerraty 1192956e45f6SSimon J. Gerraty Var_Set("MAKE", make, VAR_GLOBAL); 1193956e45f6SSimon J. Gerraty Var_Set(".MAKE", make, VAR_GLOBAL); 1194956e45f6SSimon J. Gerraty } 1195956e45f6SSimon J. Gerraty 1196*06b9b3e0SSimon J. Gerraty /* 1197*06b9b3e0SSimon J. Gerraty * Add the directories from the colon-separated syspath to defSysIncPath. 1198*06b9b3e0SSimon J. Gerraty * After returning, the contents of syspath is unspecified. 1199*06b9b3e0SSimon J. Gerraty */ 1200956e45f6SSimon J. Gerraty static void 1201956e45f6SSimon J. Gerraty InitDefSysIncPath(char *syspath) 1202956e45f6SSimon J. Gerraty { 1203956e45f6SSimon J. Gerraty static char defsyspath[] = _PATH_DEFSYSPATH; 1204956e45f6SSimon J. Gerraty char *start, *cp; 1205956e45f6SSimon J. Gerraty 1206956e45f6SSimon J. Gerraty /* 1207956e45f6SSimon J. Gerraty * If no user-supplied system path was given (through the -m option) 1208956e45f6SSimon J. Gerraty * add the directories from the DEFSYSPATH (more than one may be given 1209956e45f6SSimon J. Gerraty * as dir1:...:dirn) to the system include path. 1210956e45f6SSimon J. Gerraty */ 1211956e45f6SSimon J. Gerraty if (syspath == NULL || syspath[0] == '\0') 1212956e45f6SSimon J. Gerraty syspath = defsyspath; 1213956e45f6SSimon J. Gerraty else 1214956e45f6SSimon J. Gerraty syspath = bmake_strdup(syspath); 1215956e45f6SSimon J. Gerraty 1216956e45f6SSimon J. Gerraty for (start = syspath; *start != '\0'; start = cp) { 1217956e45f6SSimon J. Gerraty for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1218956e45f6SSimon J. Gerraty continue; 1219e2eeea75SSimon J. Gerraty if (*cp == ':') 1220956e45f6SSimon J. Gerraty *cp++ = '\0'; 1221e2eeea75SSimon J. Gerraty 1222956e45f6SSimon J. Gerraty /* look for magic parent directory search string */ 1223e2eeea75SSimon J. Gerraty if (strncmp(start, ".../", 4) == 0) { 1224956e45f6SSimon J. Gerraty char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1225956e45f6SSimon J. Gerraty if (dir != NULL) { 1226956e45f6SSimon J. Gerraty (void)Dir_AddDir(defSysIncPath, dir); 1227956e45f6SSimon J. Gerraty free(dir); 1228956e45f6SSimon J. Gerraty } 1229e2eeea75SSimon J. Gerraty } else { 1230e2eeea75SSimon J. Gerraty (void)Dir_AddDir(defSysIncPath, start); 1231956e45f6SSimon J. Gerraty } 1232956e45f6SSimon J. Gerraty } 1233956e45f6SSimon J. Gerraty 1234956e45f6SSimon J. Gerraty if (syspath != defsyspath) 1235956e45f6SSimon J. Gerraty free(syspath); 1236956e45f6SSimon J. Gerraty } 1237956e45f6SSimon J. Gerraty 1238956e45f6SSimon J. Gerraty static void 1239956e45f6SSimon J. Gerraty ReadBuiltinRules(void) 1240956e45f6SSimon J. Gerraty { 1241e2eeea75SSimon J. Gerraty StringListNode *ln; 1242*06b9b3e0SSimon J. Gerraty StringList sysMkPath = LST_INIT; 1243e2eeea75SSimon J. Gerraty 1244956e45f6SSimon J. Gerraty Dir_Expand(_PATH_DEFSYSMK, 1245956e45f6SSimon J. Gerraty Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, 1246*06b9b3e0SSimon J. Gerraty &sysMkPath); 1247*06b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&sysMkPath)) 1248956e45f6SSimon J. Gerraty Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1249e2eeea75SSimon J. Gerraty 1250*06b9b3e0SSimon J. Gerraty for (ln = sysMkPath.first; ln != NULL; ln = ln->next) 1251e2eeea75SSimon J. Gerraty if (ReadMakefile(ln->datum) == 0) 1252e2eeea75SSimon J. Gerraty break; 1253e2eeea75SSimon J. Gerraty 1254e2eeea75SSimon J. Gerraty if (ln == NULL) 1255e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", 1256*06b9b3e0SSimon J. Gerraty progname, (const char *)sysMkPath.first->datum); 1257e2eeea75SSimon J. Gerraty 1258e2eeea75SSimon J. Gerraty /* Free the list but not the actual filenames since these may still 1259e2eeea75SSimon J. Gerraty * be used in GNodes. */ 1260*06b9b3e0SSimon J. Gerraty Lst_Done(&sysMkPath); 1261956e45f6SSimon J. Gerraty } 1262956e45f6SSimon J. Gerraty 1263956e45f6SSimon J. Gerraty static void 1264956e45f6SSimon J. Gerraty InitMaxJobs(void) 1265956e45f6SSimon J. Gerraty { 1266956e45f6SSimon J. Gerraty char *value; 1267956e45f6SSimon J. Gerraty int n; 1268956e45f6SSimon J. Gerraty 1269956e45f6SSimon J. Gerraty if (forceJobs || opts.compatMake || 1270956e45f6SSimon J. Gerraty !Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) 1271956e45f6SSimon J. Gerraty return; 1272956e45f6SSimon J. Gerraty 1273956e45f6SSimon J. Gerraty (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); 1274956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1275956e45f6SSimon J. Gerraty n = (int)strtol(value, NULL, 0); 1276956e45f6SSimon J. Gerraty if (n < 1) { 1277956e45f6SSimon J. Gerraty (void)fprintf(stderr, 1278956e45f6SSimon J. Gerraty "%s: illegal value for .MAKE.JOBS " 1279956e45f6SSimon J. Gerraty "-- must be positive integer!\n", 1280956e45f6SSimon J. Gerraty progname); 1281*06b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 1282956e45f6SSimon J. Gerraty } 1283956e45f6SSimon J. Gerraty 1284956e45f6SSimon J. Gerraty if (n != opts.maxJobs) { 1285956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1286956e45f6SSimon J. Gerraty Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1287956e45f6SSimon J. Gerraty } 1288956e45f6SSimon J. Gerraty 1289956e45f6SSimon J. Gerraty opts.maxJobs = n; 1290956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 1291956e45f6SSimon J. Gerraty forceJobs = TRUE; 1292956e45f6SSimon J. Gerraty free(value); 1293956e45f6SSimon J. Gerraty } 1294956e45f6SSimon J. Gerraty 1295956e45f6SSimon J. Gerraty /* 1296956e45f6SSimon J. Gerraty * For compatibility, look at the directories in the VPATH variable 1297956e45f6SSimon J. Gerraty * and add them to the search path, if the variable is defined. The 1298956e45f6SSimon J. Gerraty * variable's value is in the same format as the PATH environment 1299956e45f6SSimon J. Gerraty * variable, i.e. <directory>:<directory>:<directory>... 1300956e45f6SSimon J. Gerraty */ 1301956e45f6SSimon J. Gerraty static void 1302956e45f6SSimon J. Gerraty InitVpath(void) 1303956e45f6SSimon J. Gerraty { 1304956e45f6SSimon J. Gerraty char *vpath, savec, *path; 1305956e45f6SSimon J. Gerraty if (!Var_Exists("VPATH", VAR_CMDLINE)) 1306956e45f6SSimon J. Gerraty return; 1307956e45f6SSimon J. Gerraty 1308956e45f6SSimon J. Gerraty (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath); 1309956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1310956e45f6SSimon J. Gerraty path = vpath; 1311956e45f6SSimon J. Gerraty do { 1312956e45f6SSimon J. Gerraty char *cp; 1313956e45f6SSimon J. Gerraty /* skip to end of directory */ 1314956e45f6SSimon J. Gerraty for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1315956e45f6SSimon J. Gerraty continue; 1316956e45f6SSimon J. Gerraty /* Save terminator character so know when to stop */ 1317956e45f6SSimon J. Gerraty savec = *cp; 1318956e45f6SSimon J. Gerraty *cp = '\0'; 1319956e45f6SSimon J. Gerraty /* Add directory to search path */ 1320*06b9b3e0SSimon J. Gerraty (void)Dir_AddDir(&dirSearchPath, path); 1321956e45f6SSimon J. Gerraty *cp = savec; 1322956e45f6SSimon J. Gerraty path = cp + 1; 1323956e45f6SSimon J. Gerraty } while (savec == ':'); 1324956e45f6SSimon J. Gerraty free(vpath); 1325956e45f6SSimon J. Gerraty } 1326956e45f6SSimon J. Gerraty 1327956e45f6SSimon J. Gerraty static void 1328e2eeea75SSimon J. Gerraty ReadAllMakefiles(StringList *makefiles) 1329956e45f6SSimon J. Gerraty { 1330956e45f6SSimon J. Gerraty StringListNode *ln; 1331956e45f6SSimon J. Gerraty 1332e2eeea75SSimon J. Gerraty for (ln = makefiles->first; ln != NULL; ln = ln->next) { 1333e2eeea75SSimon J. Gerraty const char *fname = ln->datum; 1334e2eeea75SSimon J. Gerraty if (ReadMakefile(fname) != 0) 1335e2eeea75SSimon J. Gerraty Fatal("%s: cannot open %s.", progname, fname); 1336956e45f6SSimon J. Gerraty } 1337956e45f6SSimon J. Gerraty } 1338956e45f6SSimon J. Gerraty 1339956e45f6SSimon J. Gerraty static void 1340e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(void) 1341956e45f6SSimon J. Gerraty { 1342e2eeea75SSimon J. Gerraty StringListNode *ln; 1343e2eeea75SSimon J. Gerraty char *prefs; 1344956e45f6SSimon J. Gerraty 1345e2eeea75SSimon J. Gerraty (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", 1346e2eeea75SSimon J. Gerraty VAR_CMDLINE, VARE_WANTRES, &prefs); 1347e2eeea75SSimon J. Gerraty /* TODO: handle errors */ 1348956e45f6SSimon J. Gerraty 1349e2eeea75SSimon J. Gerraty /* XXX: This should use a local list instead of opts.makefiles 1350e2eeea75SSimon J. Gerraty * since these makefiles do not come from the command line. They 1351e2eeea75SSimon J. Gerraty * also have different semantics in that only the first file that 1352e2eeea75SSimon J. Gerraty * is found is processed. See ReadAllMakefiles. */ 1353*06b9b3e0SSimon J. Gerraty (void)str2Lst_Append(&opts.makefiles, prefs); 1354956e45f6SSimon J. Gerraty 1355*06b9b3e0SSimon J. Gerraty for (ln = opts.makefiles.first; ln != NULL; ln = ln->next) 1356e2eeea75SSimon J. Gerraty if (ReadMakefile(ln->datum) == 0) 1357e2eeea75SSimon J. Gerraty break; 1358956e45f6SSimon J. Gerraty 1359e2eeea75SSimon J. Gerraty free(prefs); 1360956e45f6SSimon J. Gerraty } 1361956e45f6SSimon J. Gerraty 1362*06b9b3e0SSimon J. Gerraty /* 1363*06b9b3e0SSimon J. Gerraty * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. 1364e2eeea75SSimon J. Gerraty * Initialize a few modules. 1365*06b9b3e0SSimon J. Gerraty * Parse the arguments from MAKEFLAGS and the command line. 1366*06b9b3e0SSimon J. Gerraty */ 1367e2eeea75SSimon J. Gerraty static void 1368e2eeea75SSimon J. Gerraty main_Init(int argc, char **argv) 13693955d011SMarcel Moolenaar { 1370956e45f6SSimon J. Gerraty struct stat sa; 1371956e45f6SSimon J. Gerraty const char *machine; 1372956e45f6SSimon J. Gerraty const char *machine_arch; 13733955d011SMarcel Moolenaar char *syspath = getenv("MAKESYSPATH"); 13743955d011SMarcel Moolenaar struct utsname utsname; 13753955d011SMarcel Moolenaar 13763955d011SMarcel Moolenaar /* default to writing debug to stderr */ 1377956e45f6SSimon J. Gerraty opts.debug_file = stderr; 13783955d011SMarcel Moolenaar 1379e2eeea75SSimon J. Gerraty HashTable_Init(&cached_realpaths); 1380e2eeea75SSimon J. Gerraty 13813955d011SMarcel Moolenaar #ifdef SIGINFO 13823955d011SMarcel Moolenaar (void)bmake_signal(SIGINFO, siginfo); 13833955d011SMarcel Moolenaar #endif 1384956e45f6SSimon J. Gerraty 1385956e45f6SSimon J. Gerraty InitRandom(); 13863955d011SMarcel Moolenaar 1387*06b9b3e0SSimon J. Gerraty progname = str_basename(argv[0]); 1388956e45f6SSimon J. Gerraty 1389956e45f6SSimon J. Gerraty UnlimitFiles(); 13903955d011SMarcel Moolenaar 13911748de26SSimon J. Gerraty if (uname(&utsname) == -1) { 13921748de26SSimon J. Gerraty (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 13931748de26SSimon J. Gerraty strerror(errno)); 13941748de26SSimon J. Gerraty exit(2); 13951748de26SSimon J. Gerraty } 13961748de26SSimon J. Gerraty 13973955d011SMarcel Moolenaar /* 13983955d011SMarcel Moolenaar * Get the name of this type of MACHINE from utsname 13993955d011SMarcel Moolenaar * so we can share an executable for similar machines. 14003955d011SMarcel Moolenaar * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 14013955d011SMarcel Moolenaar * 14023955d011SMarcel Moolenaar * Note that both MACHINE and MACHINE_ARCH are decided at 14033955d011SMarcel Moolenaar * run-time. 14043955d011SMarcel Moolenaar */ 1405e2eeea75SSimon J. Gerraty machine = InitVarMachine(&utsname); 1406e2eeea75SSimon J. Gerraty machine_arch = InitVarMachineArch(); 14073955d011SMarcel Moolenaar 14083955d011SMarcel Moolenaar myPid = getpid(); /* remember this for vFork() */ 14093955d011SMarcel Moolenaar 14103955d011SMarcel Moolenaar /* 14113955d011SMarcel Moolenaar * Just in case MAKEOBJDIR wants us to do something tricky. 14123955d011SMarcel Moolenaar */ 1413e2eeea75SSimon J. Gerraty Targ_Init(); 1414e2eeea75SSimon J. Gerraty Var_Init(); 14153841c287SSimon J. Gerraty Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL); 14163841c287SSimon J. Gerraty Var_Set("MACHINE", machine, VAR_GLOBAL); 14173841c287SSimon J. Gerraty Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 14183955d011SMarcel Moolenaar #ifdef MAKE_VERSION 14193841c287SSimon J. Gerraty Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL); 14203955d011SMarcel Moolenaar #endif 14213841c287SSimon J. Gerraty Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */ 14223955d011SMarcel Moolenaar /* 14233955d011SMarcel Moolenaar * This is the traditional preference for makefiles. 14243955d011SMarcel Moolenaar */ 14253955d011SMarcel Moolenaar #ifndef MAKEFILE_PREFERENCE_LIST 14263955d011SMarcel Moolenaar # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 14273955d011SMarcel Moolenaar #endif 1428e2eeea75SSimon J. Gerraty Var_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, VAR_GLOBAL); 14293841c287SSimon J. Gerraty Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); 14303955d011SMarcel Moolenaar 1431956e45f6SSimon J. Gerraty CmdOpts_Init(); 14323955d011SMarcel Moolenaar allPrecious = FALSE; /* Remove targets when interrupted */ 143345447996SSimon J. Gerraty deleteOnError = FALSE; /* Historical default behavior */ 14343955d011SMarcel Moolenaar jobsRunning = FALSE; 14353955d011SMarcel Moolenaar 1436956e45f6SSimon J. Gerraty maxJobTokens = opts.maxJobs; 14373955d011SMarcel Moolenaar ignorePWD = FALSE; 14383955d011SMarcel Moolenaar 14393955d011SMarcel Moolenaar /* 14403955d011SMarcel Moolenaar * Initialize the parsing, directory and variable modules to prepare 14413955d011SMarcel Moolenaar * for the reading of inclusion paths and variable settings on the 14423955d011SMarcel Moolenaar * command line 14433955d011SMarcel Moolenaar */ 14443955d011SMarcel Moolenaar 14453955d011SMarcel Moolenaar /* 14463955d011SMarcel Moolenaar * Initialize various variables. 14473955d011SMarcel Moolenaar * MAKE also gets this name, for compatibility 14483955d011SMarcel Moolenaar * .MAKEFLAGS gets set to the empty string just in case. 14493955d011SMarcel Moolenaar * MFLAGS also gets initialized empty, for compatibility. 14503955d011SMarcel Moolenaar */ 14513955d011SMarcel Moolenaar Parse_Init(); 1452956e45f6SSimon J. Gerraty InitVarMake(argv[0]); 14533841c287SSimon J. Gerraty Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 14543841c287SSimon J. Gerraty Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); 14553841c287SSimon J. Gerraty Var_Set("MFLAGS", "", VAR_GLOBAL); 14563841c287SSimon J. Gerraty Var_Set(".ALLTARGETS", "", VAR_GLOBAL); 145751ee2c1cSSimon J. Gerraty /* some makefiles need to know this */ 1458956e45f6SSimon J. Gerraty Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE); 14593955d011SMarcel Moolenaar 1460e2eeea75SSimon J. Gerraty /* Set some other useful variables. */ 14613955d011SMarcel Moolenaar { 1462e2eeea75SSimon J. Gerraty char tmp[64], *ep = getenv(MAKE_LEVEL_ENV); 14633955d011SMarcel Moolenaar 1464e2eeea75SSimon J. Gerraty makelevel = ep != NULL && ep[0] != '\0' ? atoi(ep) : 0; 146551ee2c1cSSimon J. Gerraty if (makelevel < 0) 146651ee2c1cSSimon J. Gerraty makelevel = 0; 1467e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%d", makelevel); 14683841c287SSimon J. Gerraty Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL); 1469e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", myPid); 14703841c287SSimon J. Gerraty Var_Set(".MAKE.PID", tmp, VAR_GLOBAL); 1471e2eeea75SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getppid()); 14723841c287SSimon J. Gerraty Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL); 1473*06b9b3e0SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getuid()); 1474*06b9b3e0SSimon J. Gerraty Var_Set(".MAKE.UID", tmp, VAR_GLOBAL); 1475*06b9b3e0SSimon J. Gerraty snprintf(tmp, sizeof tmp, "%u", getgid()); 1476*06b9b3e0SSimon J. Gerraty Var_Set(".MAKE.GID", tmp, VAR_GLOBAL); 14773955d011SMarcel Moolenaar } 147851ee2c1cSSimon J. Gerraty if (makelevel > 0) { 147951ee2c1cSSimon J. Gerraty char pn[1024]; 1480e2eeea75SSimon J. Gerraty snprintf(pn, sizeof pn, "%s[%d]", progname, makelevel); 148151ee2c1cSSimon J. Gerraty progname = bmake_strdup(pn); 148251ee2c1cSSimon J. Gerraty } 14833955d011SMarcel Moolenaar 14841748de26SSimon J. Gerraty #ifdef USE_META 14851748de26SSimon J. Gerraty meta_init(); 14861748de26SSimon J. Gerraty #endif 14872c3632d1SSimon J. Gerraty Dir_Init(); 14881ce939a7SSimon J. Gerraty 14893955d011SMarcel Moolenaar /* 14903955d011SMarcel Moolenaar * First snag any flags out of the MAKE environment variable. 14913955d011SMarcel Moolenaar * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 14923955d011SMarcel Moolenaar * in a different format). 14933955d011SMarcel Moolenaar */ 14943955d011SMarcel Moolenaar #ifdef POSIX 1495956e45f6SSimon J. Gerraty { 1496956e45f6SSimon J. Gerraty char *p1 = explode(getenv("MAKEFLAGS")); 149751ee2c1cSSimon J. Gerraty Main_ParseArgLine(p1); 149851ee2c1cSSimon J. Gerraty free(p1); 1499956e45f6SSimon J. Gerraty } 15003955d011SMarcel Moolenaar #else 15013955d011SMarcel Moolenaar Main_ParseArgLine(getenv("MAKE")); 15023955d011SMarcel Moolenaar #endif 15033955d011SMarcel Moolenaar 15043955d011SMarcel Moolenaar /* 15053955d011SMarcel Moolenaar * Find where we are (now). 15063955d011SMarcel Moolenaar * We take care of PWD for the automounter below... 15073955d011SMarcel Moolenaar */ 15083955d011SMarcel Moolenaar if (getcwd(curdir, MAXPATHLEN) == NULL) { 15093955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: getcwd: %s.\n", 15103955d011SMarcel Moolenaar progname, strerror(errno)); 15113955d011SMarcel Moolenaar exit(2); 15123955d011SMarcel Moolenaar } 15133955d011SMarcel Moolenaar 15143955d011SMarcel Moolenaar MainParseArgs(argc, argv); 15153955d011SMarcel Moolenaar 1516956e45f6SSimon J. Gerraty if (opts.enterFlag) 151751ee2c1cSSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, curdir); 151851ee2c1cSSimon J. Gerraty 15193955d011SMarcel Moolenaar /* 15203955d011SMarcel Moolenaar * Verify that cwd is sane. 15213955d011SMarcel Moolenaar */ 15223955d011SMarcel Moolenaar if (stat(curdir, &sa) == -1) { 15233955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: %s: %s.\n", 15243955d011SMarcel Moolenaar progname, curdir, strerror(errno)); 15253955d011SMarcel Moolenaar exit(2); 15263955d011SMarcel Moolenaar } 15273955d011SMarcel Moolenaar 15283955d011SMarcel Moolenaar #ifndef NO_PWD_OVERRIDE 1529956e45f6SSimon J. Gerraty HandlePWD(&sa); 15303955d011SMarcel Moolenaar #endif 15313841c287SSimon J. Gerraty Var_Set(".CURDIR", curdir, VAR_GLOBAL); 15323955d011SMarcel Moolenaar 1533956e45f6SSimon J. Gerraty InitObjdir(machine, machine_arch); 15343955d011SMarcel Moolenaar 15353955d011SMarcel Moolenaar /* 15363955d011SMarcel Moolenaar * Initialize archive, target and suffix modules in preparation for 15373955d011SMarcel Moolenaar * parsing the makefile(s) 15383955d011SMarcel Moolenaar */ 15393955d011SMarcel Moolenaar Arch_Init(); 15403955d011SMarcel Moolenaar Suff_Init(); 15413955d011SMarcel Moolenaar Trace_Init(tracefile); 15423955d011SMarcel Moolenaar 1543e2eeea75SSimon J. Gerraty defaultNode = NULL; 15443955d011SMarcel Moolenaar (void)time(&now); 15453955d011SMarcel Moolenaar 15463955d011SMarcel Moolenaar Trace_Log(MAKESTART, NULL); 15473955d011SMarcel Moolenaar 1548956e45f6SSimon J. Gerraty InitVarTargets(); 15493955d011SMarcel Moolenaar 1550956e45f6SSimon J. Gerraty InitDefSysIncPath(syspath); 1551e2eeea75SSimon J. Gerraty } 15523955d011SMarcel Moolenaar 1553*06b9b3e0SSimon J. Gerraty /* 1554*06b9b3e0SSimon J. Gerraty * Read the system makefile followed by either makefile, Makefile or the 1555*06b9b3e0SSimon J. Gerraty * files given by the -f option. Exit on parse errors. 1556*06b9b3e0SSimon J. Gerraty */ 1557e2eeea75SSimon J. Gerraty static void 1558e2eeea75SSimon J. Gerraty main_ReadFiles(void) 1559e2eeea75SSimon J. Gerraty { 1560e2eeea75SSimon J. Gerraty 1561956e45f6SSimon J. Gerraty if (!opts.noBuiltins) 1562956e45f6SSimon J. Gerraty ReadBuiltinRules(); 15633955d011SMarcel Moolenaar 1564*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&opts.makefiles)) 1565*06b9b3e0SSimon J. Gerraty ReadAllMakefiles(&opts.makefiles); 1566e2eeea75SSimon J. Gerraty else 1567e2eeea75SSimon J. Gerraty ReadFirstDefaultMakefile(); 1568e2eeea75SSimon J. Gerraty } 1569e2eeea75SSimon J. Gerraty 1570e2eeea75SSimon J. Gerraty /* Compute the dependency graph. */ 1571e2eeea75SSimon J. Gerraty static void 1572e2eeea75SSimon J. Gerraty main_PrepareMaking(void) 1573e2eeea75SSimon J. Gerraty { 15743955d011SMarcel Moolenaar /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1575e2eeea75SSimon J. Gerraty if (!opts.noBuiltins || opts.printVars == PVM_NONE) { 1576*06b9b3e0SSimon J. Gerraty (void)Var_Subst("${.MAKE.DEPENDFILE}", 1577956e45f6SSimon J. Gerraty VAR_CMDLINE, VARE_WANTRES, &makeDependfile); 1578956e45f6SSimon J. Gerraty if (makeDependfile[0] != '\0') { 1579956e45f6SSimon J. Gerraty /* TODO: handle errors */ 15803955d011SMarcel Moolenaar doing_depend = TRUE; 15812c3632d1SSimon J. Gerraty (void)ReadMakefile(makeDependfile); 15823955d011SMarcel Moolenaar doing_depend = FALSE; 15833955d011SMarcel Moolenaar } 1584956e45f6SSimon J. Gerraty } 15853955d011SMarcel Moolenaar 15864c620fe5SSimon J. Gerraty if (enterFlagObj) 15874c620fe5SSimon J. Gerraty printf("%s: Entering directory `%s'\n", progname, objdir); 15884c620fe5SSimon J. Gerraty 1589*06b9b3e0SSimon J. Gerraty MakeMode(); 15903955d011SMarcel Moolenaar 1591956e45f6SSimon J. Gerraty { 1592*06b9b3e0SSimon J. Gerraty FStr makeflags = Var_Value(MAKEFLAGS, VAR_GLOBAL); 1593*06b9b3e0SSimon J. Gerraty Var_Append("MFLAGS", makeflags.str, VAR_GLOBAL); 1594*06b9b3e0SSimon J. Gerraty FStr_Done(&makeflags); 1595956e45f6SSimon J. Gerraty } 1596e48f47ddSSimon J. Gerraty 1597956e45f6SSimon J. Gerraty InitMaxJobs(); 1598e48f47ddSSimon J. Gerraty 1599e48f47ddSSimon J. Gerraty /* 1600e2eeea75SSimon J. Gerraty * Be compatible if the user did not specify -j and did not explicitly 1601e2eeea75SSimon J. Gerraty * turn compatibility on. 1602e48f47ddSSimon J. Gerraty */ 1603e2eeea75SSimon J. Gerraty if (!opts.compatMake && !forceJobs) 1604956e45f6SSimon J. Gerraty opts.compatMake = TRUE; 1605e48f47ddSSimon J. Gerraty 1606956e45f6SSimon J. Gerraty if (!opts.compatMake) 16073955d011SMarcel Moolenaar Job_ServerStart(maxJobTokens, jp_0, jp_1); 1608956e45f6SSimon J. Gerraty DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1609956e45f6SSimon J. Gerraty jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 16103955d011SMarcel Moolenaar 1611e2eeea75SSimon J. Gerraty if (opts.printVars == PVM_NONE) 16123955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(TRUE); /* initial export */ 16133955d011SMarcel Moolenaar 1614956e45f6SSimon J. Gerraty InitVpath(); 16153955d011SMarcel Moolenaar 16163955d011SMarcel Moolenaar /* 16173955d011SMarcel Moolenaar * Now that all search paths have been read for suffixes et al, it's 16183955d011SMarcel Moolenaar * time to add the default search path to their lists... 16193955d011SMarcel Moolenaar */ 16203955d011SMarcel Moolenaar Suff_DoPaths(); 16213955d011SMarcel Moolenaar 16223955d011SMarcel Moolenaar /* 16233955d011SMarcel Moolenaar * Propagate attributes through :: dependency lists. 16243955d011SMarcel Moolenaar */ 16253955d011SMarcel Moolenaar Targ_Propagate(); 16263955d011SMarcel Moolenaar 16273955d011SMarcel Moolenaar /* print the initial graph, if the user requested it */ 16283955d011SMarcel Moolenaar if (DEBUG(GRAPH1)) 16293955d011SMarcel Moolenaar Targ_PrintGraph(1); 16303955d011SMarcel Moolenaar } 16313955d011SMarcel Moolenaar 1632*06b9b3e0SSimon J. Gerraty /* 1633*06b9b3e0SSimon J. Gerraty * Make the targets. 1634e2eeea75SSimon J. Gerraty * If the -v or -V options are given, print variables instead. 1635*06b9b3e0SSimon J. Gerraty * Return whether any of the targets is out-of-date. 1636*06b9b3e0SSimon J. Gerraty */ 1637e2eeea75SSimon J. Gerraty static Boolean 1638e2eeea75SSimon J. Gerraty main_Run(void) 1639e2eeea75SSimon J. Gerraty { 1640e2eeea75SSimon J. Gerraty if (opts.printVars != PVM_NONE) { 1641e2eeea75SSimon J. Gerraty /* print the values of any variables requested by the user */ 1642e2eeea75SSimon J. Gerraty doPrintVars(); 1643e2eeea75SSimon J. Gerraty return FALSE; 1644e2eeea75SSimon J. Gerraty } else { 1645e2eeea75SSimon J. Gerraty return runTargets(); 1646e2eeea75SSimon J. Gerraty } 1647e2eeea75SSimon J. Gerraty } 16483955d011SMarcel Moolenaar 1649e2eeea75SSimon J. Gerraty /* Clean up after making the targets. */ 1650e2eeea75SSimon J. Gerraty static void 1651e2eeea75SSimon J. Gerraty main_CleanUp(void) 1652e2eeea75SSimon J. Gerraty { 1653e2eeea75SSimon J. Gerraty #ifdef CLEANUP 1654*06b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.variables, free); 1655*06b9b3e0SSimon J. Gerraty /* 1656*06b9b3e0SSimon J. Gerraty * Don't free the actual strings from opts.makefiles, they may be 1657*06b9b3e0SSimon J. Gerraty * used in GNodes. 1658*06b9b3e0SSimon J. Gerraty */ 1659*06b9b3e0SSimon J. Gerraty Lst_Done(&opts.makefiles); 1660*06b9b3e0SSimon J. Gerraty Lst_DoneCall(&opts.create, free); 1661e2eeea75SSimon J. Gerraty #endif 1662e2eeea75SSimon J. Gerraty 1663e2eeea75SSimon J. Gerraty /* print the graph now it's been processed if the user requested it */ 1664e2eeea75SSimon J. Gerraty if (DEBUG(GRAPH2)) 1665e2eeea75SSimon J. Gerraty Targ_PrintGraph(2); 1666e2eeea75SSimon J. Gerraty 1667e2eeea75SSimon J. Gerraty Trace_Log(MAKEEND, NULL); 1668e2eeea75SSimon J. Gerraty 1669e2eeea75SSimon J. Gerraty if (enterFlagObj) 1670e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, objdir); 1671e2eeea75SSimon J. Gerraty if (opts.enterFlag) 1672e2eeea75SSimon J. Gerraty printf("%s: Leaving directory `%s'\n", progname, curdir); 1673e2eeea75SSimon J. Gerraty 1674e2eeea75SSimon J. Gerraty #ifdef USE_META 1675e2eeea75SSimon J. Gerraty meta_finish(); 1676e2eeea75SSimon J. Gerraty #endif 1677e2eeea75SSimon J. Gerraty Suff_End(); 1678e2eeea75SSimon J. Gerraty Targ_End(); 1679e2eeea75SSimon J. Gerraty Arch_End(); 1680e2eeea75SSimon J. Gerraty Var_End(); 1681e2eeea75SSimon J. Gerraty Parse_End(); 1682e2eeea75SSimon J. Gerraty Dir_End(); 1683e2eeea75SSimon J. Gerraty Job_End(); 1684e2eeea75SSimon J. Gerraty Trace_End(); 1685e2eeea75SSimon J. Gerraty } 1686e2eeea75SSimon J. Gerraty 1687e2eeea75SSimon J. Gerraty /* Determine the exit code. */ 1688e2eeea75SSimon J. Gerraty static int 1689e2eeea75SSimon J. Gerraty main_Exit(Boolean outOfDate) 1690e2eeea75SSimon J. Gerraty { 1691*06b9b3e0SSimon J. Gerraty if (opts.strict && (main_errors > 0 || Parse_GetFatals() > 0)) 1692956e45f6SSimon J. Gerraty return 2; /* Not 1 so -q can distinguish error */ 16933955d011SMarcel Moolenaar return outOfDate ? 1 : 0; 16943955d011SMarcel Moolenaar } 16953955d011SMarcel Moolenaar 1696e2eeea75SSimon J. Gerraty int 1697e2eeea75SSimon J. Gerraty main(int argc, char **argv) 1698e2eeea75SSimon J. Gerraty { 1699e2eeea75SSimon J. Gerraty Boolean outOfDate; 1700e2eeea75SSimon J. Gerraty 1701e2eeea75SSimon J. Gerraty main_Init(argc, argv); 1702e2eeea75SSimon J. Gerraty main_ReadFiles(); 1703e2eeea75SSimon J. Gerraty main_PrepareMaking(); 1704e2eeea75SSimon J. Gerraty outOfDate = main_Run(); 1705e2eeea75SSimon J. Gerraty main_CleanUp(); 1706e2eeea75SSimon J. Gerraty return main_Exit(outOfDate); 1707e2eeea75SSimon J. Gerraty } 1708e2eeea75SSimon J. Gerraty 1709*06b9b3e0SSimon J. Gerraty /* 1710*06b9b3e0SSimon J. Gerraty * Open and parse the given makefile, with all its side effects. 17113955d011SMarcel Moolenaar * 17123955d011SMarcel Moolenaar * Results: 17133955d011SMarcel Moolenaar * 0 if ok. -1 if couldn't open file. 17143955d011SMarcel Moolenaar */ 17153955d011SMarcel Moolenaar static int 17162c3632d1SSimon J. Gerraty ReadMakefile(const char *fname) 17173955d011SMarcel Moolenaar { 17183955d011SMarcel Moolenaar int fd; 17192c3632d1SSimon J. Gerraty char *name, *path = NULL; 17203955d011SMarcel Moolenaar 1721e2eeea75SSimon J. Gerraty if (strcmp(fname, "-") == 0) { 17223955d011SMarcel Moolenaar Parse_File(NULL /*stdin*/, -1); 17233841c287SSimon J. Gerraty Var_Set("MAKEFILE", "", VAR_INTERNAL); 17243955d011SMarcel Moolenaar } else { 17253955d011SMarcel Moolenaar /* if we've chdir'd, rebuild the path name */ 1726e2eeea75SSimon J. Gerraty if (strcmp(curdir, objdir) != 0 && *fname != '/') { 17272c3632d1SSimon J. Gerraty path = str_concat3(curdir, "/", fname); 17283955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 17293955d011SMarcel Moolenaar if (fd != -1) { 17303955d011SMarcel Moolenaar fname = path; 17313955d011SMarcel Moolenaar goto found; 17323955d011SMarcel Moolenaar } 17332c3632d1SSimon J. Gerraty free(path); 17343955d011SMarcel Moolenaar 17353955d011SMarcel Moolenaar /* If curdir failed, try objdir (ala .depend) */ 17362c3632d1SSimon J. Gerraty path = str_concat3(objdir, "/", fname); 17373955d011SMarcel Moolenaar fd = open(path, O_RDONLY); 17383955d011SMarcel Moolenaar if (fd != -1) { 17393955d011SMarcel Moolenaar fname = path; 17403955d011SMarcel Moolenaar goto found; 17413955d011SMarcel Moolenaar } 17423955d011SMarcel Moolenaar } else { 17433955d011SMarcel Moolenaar fd = open(fname, O_RDONLY); 17443955d011SMarcel Moolenaar if (fd != -1) 17453955d011SMarcel Moolenaar goto found; 17463955d011SMarcel Moolenaar } 17473955d011SMarcel Moolenaar /* look in -I and system include directories. */ 17483955d011SMarcel Moolenaar name = Dir_FindFile(fname, parseIncPath); 1749e2eeea75SSimon J. Gerraty if (name == NULL) { 1750956e45f6SSimon J. Gerraty SearchPath *sysInc = Lst_IsEmpty(sysIncPath) 1751956e45f6SSimon J. Gerraty ? defSysIncPath : sysIncPath; 1752956e45f6SSimon J. Gerraty name = Dir_FindFile(fname, sysInc); 1753956e45f6SSimon J. Gerraty } 1754e2eeea75SSimon J. Gerraty if (name == NULL || (fd = open(name, O_RDONLY)) == -1) { 17553955d011SMarcel Moolenaar free(name); 17563955d011SMarcel Moolenaar free(path); 17573841c287SSimon J. Gerraty return -1; 17583955d011SMarcel Moolenaar } 17593955d011SMarcel Moolenaar fname = name; 17603955d011SMarcel Moolenaar /* 17613955d011SMarcel Moolenaar * set the MAKEFILE variable desired by System V fans -- the 17623955d011SMarcel Moolenaar * placement of the setting here means it gets set to the last 17633955d011SMarcel Moolenaar * makefile specified, as it is set by SysV make. 17643955d011SMarcel Moolenaar */ 17653955d011SMarcel Moolenaar found: 17663955d011SMarcel Moolenaar if (!doing_depend) 17673841c287SSimon J. Gerraty Var_Set("MAKEFILE", fname, VAR_INTERNAL); 17683955d011SMarcel Moolenaar Parse_File(fname, fd); 17693955d011SMarcel Moolenaar } 17703955d011SMarcel Moolenaar free(path); 17713841c287SSimon J. Gerraty return 0; 17723955d011SMarcel Moolenaar } 17733955d011SMarcel Moolenaar 17743955d011SMarcel Moolenaar /*- 17753955d011SMarcel Moolenaar * Cmd_Exec -- 17763955d011SMarcel Moolenaar * Execute the command in cmd, and return the output of that command 17772c3632d1SSimon J. Gerraty * in a string. In the output, newlines are replaced with spaces. 17783955d011SMarcel Moolenaar * 17793955d011SMarcel Moolenaar * Results: 17802c3632d1SSimon J. Gerraty * A string containing the output of the command, or the empty string. 17812c3632d1SSimon J. Gerraty * *errfmt returns a format string describing the command failure, 17822c3632d1SSimon J. Gerraty * if any, using a single %s conversion specification. 17833955d011SMarcel Moolenaar * 17843955d011SMarcel Moolenaar * Side Effects: 17853955d011SMarcel Moolenaar * The string must be freed by the caller. 17863955d011SMarcel Moolenaar */ 17873955d011SMarcel Moolenaar char * 17882c3632d1SSimon J. Gerraty Cmd_Exec(const char *cmd, const char **errfmt) 17893955d011SMarcel Moolenaar { 17903955d011SMarcel Moolenaar const char *args[4]; /* Args for invoking the shell */ 1791*06b9b3e0SSimon J. Gerraty int pipefds[2]; 17923955d011SMarcel Moolenaar int cpid; /* Child PID */ 17933955d011SMarcel Moolenaar int pid; /* PID from wait() */ 1794e2eeea75SSimon J. Gerraty int status; /* command exit status */ 17953955d011SMarcel Moolenaar Buffer buf; /* buffer to store the result */ 17962c3632d1SSimon J. Gerraty ssize_t bytes_read; 17972c3632d1SSimon J. Gerraty char *res; /* result */ 17982c3632d1SSimon J. Gerraty size_t res_len; 17993955d011SMarcel Moolenaar char *cp; 1800db29cad8SSimon J. Gerraty int savederr; /* saved errno */ 18013955d011SMarcel Moolenaar 18022c3632d1SSimon J. Gerraty *errfmt = NULL; 18033955d011SMarcel Moolenaar 1804*06b9b3e0SSimon J. Gerraty if (shellName == NULL) 18053955d011SMarcel Moolenaar Shell_Init(); 18063955d011SMarcel Moolenaar /* 18073955d011SMarcel Moolenaar * Set up arguments for shell 18083955d011SMarcel Moolenaar */ 18093955d011SMarcel Moolenaar args[0] = shellName; 18103955d011SMarcel Moolenaar args[1] = "-c"; 18113955d011SMarcel Moolenaar args[2] = cmd; 18123955d011SMarcel Moolenaar args[3] = NULL; 18133955d011SMarcel Moolenaar 18143955d011SMarcel Moolenaar /* 18153955d011SMarcel Moolenaar * Open a pipe for fetching its output 18163955d011SMarcel Moolenaar */ 1817*06b9b3e0SSimon J. Gerraty if (pipe(pipefds) == -1) { 18182c3632d1SSimon J. Gerraty *errfmt = "Couldn't create pipe for \"%s\""; 18193955d011SMarcel Moolenaar goto bad; 18203955d011SMarcel Moolenaar } 18213955d011SMarcel Moolenaar 1822*06b9b3e0SSimon J. Gerraty Var_ReexportVars(); 1823*06b9b3e0SSimon J. Gerraty 18243955d011SMarcel Moolenaar /* 18253955d011SMarcel Moolenaar * Fork 18263955d011SMarcel Moolenaar */ 18273955d011SMarcel Moolenaar switch (cpid = vFork()) { 18283955d011SMarcel Moolenaar case 0: 1829*06b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close input side of pipe */ 18303955d011SMarcel Moolenaar 18313955d011SMarcel Moolenaar /* 18323955d011SMarcel Moolenaar * Duplicate the output stream to the shell's output, then 18333955d011SMarcel Moolenaar * shut the extra thing down. Note we don't fetch the error 18343955d011SMarcel Moolenaar * stream...why not? Why? 18353955d011SMarcel Moolenaar */ 1836*06b9b3e0SSimon J. Gerraty (void)dup2(pipefds[1], 1); 1837*06b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); 18383955d011SMarcel Moolenaar 18393955d011SMarcel Moolenaar (void)execv(shellPath, UNCONST(args)); 18403955d011SMarcel Moolenaar _exit(1); 18413955d011SMarcel Moolenaar /*NOTREACHED*/ 18423955d011SMarcel Moolenaar 18433955d011SMarcel Moolenaar case -1: 18442c3632d1SSimon J. Gerraty *errfmt = "Couldn't exec \"%s\""; 18453955d011SMarcel Moolenaar goto bad; 18463955d011SMarcel Moolenaar 18473955d011SMarcel Moolenaar default: 1848*06b9b3e0SSimon J. Gerraty (void)close(pipefds[1]); /* No need for the writing half */ 18493955d011SMarcel Moolenaar 1850db29cad8SSimon J. Gerraty savederr = 0; 1851e2eeea75SSimon J. Gerraty Buf_Init(&buf); 18523955d011SMarcel Moolenaar 18533955d011SMarcel Moolenaar do { 18543955d011SMarcel Moolenaar char result[BUFSIZ]; 1855*06b9b3e0SSimon J. Gerraty bytes_read = read(pipefds[0], result, sizeof result); 18562c3632d1SSimon J. Gerraty if (bytes_read > 0) 18572c3632d1SSimon J. Gerraty Buf_AddBytes(&buf, result, (size_t)bytes_read); 1858e2eeea75SSimon J. Gerraty } while (bytes_read > 0 || 1859e2eeea75SSimon J. Gerraty (bytes_read == -1 && errno == EINTR)); 18602c3632d1SSimon J. Gerraty if (bytes_read == -1) 1861db29cad8SSimon J. Gerraty savederr = errno; 18623955d011SMarcel Moolenaar 1863*06b9b3e0SSimon J. Gerraty (void)close(pipefds[0]); /* Close the input side of the pipe. */ 18643955d011SMarcel Moolenaar 1865e2eeea75SSimon J. Gerraty /* Wait for the process to exit. */ 1866e2eeea75SSimon J. Gerraty while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) 18673955d011SMarcel Moolenaar JobReapChild(pid, status, FALSE); 1868e2eeea75SSimon J. Gerraty 1869956e45f6SSimon J. Gerraty res_len = Buf_Len(&buf); 18703955d011SMarcel Moolenaar res = Buf_Destroy(&buf, FALSE); 18713955d011SMarcel Moolenaar 1872db29cad8SSimon J. Gerraty if (savederr != 0) 18732c3632d1SSimon J. Gerraty *errfmt = "Couldn't read shell's output for \"%s\""; 18743955d011SMarcel Moolenaar 18753955d011SMarcel Moolenaar if (WIFSIGNALED(status)) 18762c3632d1SSimon J. Gerraty *errfmt = "\"%s\" exited on a signal"; 18773955d011SMarcel Moolenaar else if (WEXITSTATUS(status) != 0) 18782c3632d1SSimon J. Gerraty *errfmt = "\"%s\" returned non-zero status"; 18793955d011SMarcel Moolenaar 18802c3632d1SSimon J. Gerraty /* Convert newlines to spaces. A final newline is just stripped */ 18812c3632d1SSimon J. Gerraty if (res_len > 0 && res[res_len - 1] == '\n') 18822c3632d1SSimon J. Gerraty res[res_len - 1] = '\0'; 18832c3632d1SSimon J. Gerraty for (cp = res; *cp != '\0'; cp++) 18842c3632d1SSimon J. Gerraty if (*cp == '\n') 18853955d011SMarcel Moolenaar *cp = ' '; 18863955d011SMarcel Moolenaar break; 18873955d011SMarcel Moolenaar } 18883955d011SMarcel Moolenaar return res; 18893955d011SMarcel Moolenaar bad: 18902c3632d1SSimon J. Gerraty return bmake_strdup(""); 18913955d011SMarcel Moolenaar } 18923955d011SMarcel Moolenaar 1893*06b9b3e0SSimon J. Gerraty /* 1894*06b9b3e0SSimon J. Gerraty * Print a printf-style error message. 18953955d011SMarcel Moolenaar * 1896e2eeea75SSimon J. Gerraty * In default mode, this error message has no consequences, in particular it 1897*06b9b3e0SSimon J. Gerraty * does not affect the exit status. Only in lint mode (-dL) it does. 1898*06b9b3e0SSimon J. Gerraty */ 18993955d011SMarcel Moolenaar void 19003955d011SMarcel Moolenaar Error(const char *fmt, ...) 19013955d011SMarcel Moolenaar { 19023955d011SMarcel Moolenaar va_list ap; 19033955d011SMarcel Moolenaar FILE *err_file; 19043955d011SMarcel Moolenaar 1905956e45f6SSimon J. Gerraty err_file = opts.debug_file; 19063955d011SMarcel Moolenaar if (err_file == stdout) 19073955d011SMarcel Moolenaar err_file = stderr; 19083955d011SMarcel Moolenaar (void)fflush(stdout); 19093955d011SMarcel Moolenaar for (;;) { 19103955d011SMarcel Moolenaar va_start(ap, fmt); 19113955d011SMarcel Moolenaar fprintf(err_file, "%s: ", progname); 19123955d011SMarcel Moolenaar (void)vfprintf(err_file, fmt, ap); 19133955d011SMarcel Moolenaar va_end(ap); 19143955d011SMarcel Moolenaar (void)fprintf(err_file, "\n"); 19153955d011SMarcel Moolenaar (void)fflush(err_file); 19163955d011SMarcel Moolenaar if (err_file == stderr) 19173955d011SMarcel Moolenaar break; 19183955d011SMarcel Moolenaar err_file = stderr; 19193955d011SMarcel Moolenaar } 1920*06b9b3e0SSimon J. Gerraty main_errors++; 19213955d011SMarcel Moolenaar } 19223955d011SMarcel Moolenaar 1923*06b9b3e0SSimon J. Gerraty /* 1924*06b9b3e0SSimon J. Gerraty * Wait for any running jobs to finish, then produce an error message, 1925e2eeea75SSimon J. Gerraty * finally exit immediately. 19263955d011SMarcel Moolenaar * 1927e2eeea75SSimon J. Gerraty * Exiting immediately differs from Parse_Error, which exits only after the 1928*06b9b3e0SSimon J. Gerraty * current top-level makefile has been parsed completely. 1929*06b9b3e0SSimon J. Gerraty */ 19303955d011SMarcel Moolenaar void 19313955d011SMarcel Moolenaar Fatal(const char *fmt, ...) 19323955d011SMarcel Moolenaar { 19333955d011SMarcel Moolenaar va_list ap; 19343955d011SMarcel Moolenaar 19353955d011SMarcel Moolenaar if (jobsRunning) 19363955d011SMarcel Moolenaar Job_Wait(); 19373955d011SMarcel Moolenaar 19383955d011SMarcel Moolenaar (void)fflush(stdout); 1939e2eeea75SSimon J. Gerraty va_start(ap, fmt); 19403955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 19413955d011SMarcel Moolenaar va_end(ap); 19423955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 19433955d011SMarcel Moolenaar (void)fflush(stderr); 19443955d011SMarcel Moolenaar 19453955d011SMarcel Moolenaar PrintOnError(NULL, NULL); 19463955d011SMarcel Moolenaar 19473955d011SMarcel Moolenaar if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 19483955d011SMarcel Moolenaar Targ_PrintGraph(2); 1949e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 19503955d011SMarcel Moolenaar exit(2); /* Not 1 so -q can distinguish error */ 19513955d011SMarcel Moolenaar } 19523955d011SMarcel Moolenaar 1953*06b9b3e0SSimon J. Gerraty /* 1954*06b9b3e0SSimon J. Gerraty * Major exception once jobs are being created. 1955*06b9b3e0SSimon J. Gerraty * Kills all jobs, prints a message and exits. 1956*06b9b3e0SSimon J. Gerraty */ 19573955d011SMarcel Moolenaar void 19583955d011SMarcel Moolenaar Punt(const char *fmt, ...) 19593955d011SMarcel Moolenaar { 19603955d011SMarcel Moolenaar va_list ap; 19613955d011SMarcel Moolenaar 19623955d011SMarcel Moolenaar va_start(ap, fmt); 19633955d011SMarcel Moolenaar (void)fflush(stdout); 19643955d011SMarcel Moolenaar (void)fprintf(stderr, "%s: ", progname); 19653955d011SMarcel Moolenaar (void)vfprintf(stderr, fmt, ap); 19663955d011SMarcel Moolenaar va_end(ap); 19673955d011SMarcel Moolenaar (void)fprintf(stderr, "\n"); 19683955d011SMarcel Moolenaar (void)fflush(stderr); 19693955d011SMarcel Moolenaar 19703955d011SMarcel Moolenaar PrintOnError(NULL, NULL); 19713955d011SMarcel Moolenaar 19723955d011SMarcel Moolenaar DieHorribly(); 19733955d011SMarcel Moolenaar } 19743955d011SMarcel Moolenaar 1975956e45f6SSimon J. Gerraty /* Exit without giving a message. */ 19763955d011SMarcel Moolenaar void 19773955d011SMarcel Moolenaar DieHorribly(void) 19783955d011SMarcel Moolenaar { 19793955d011SMarcel Moolenaar if (jobsRunning) 19803955d011SMarcel Moolenaar Job_AbortAll(); 19813955d011SMarcel Moolenaar if (DEBUG(GRAPH2)) 19823955d011SMarcel Moolenaar Targ_PrintGraph(2); 1983e2eeea75SSimon J. Gerraty Trace_Log(MAKEERROR, NULL); 1984*06b9b3e0SSimon J. Gerraty exit(2); /* Not 1 so -q can distinguish error */ 19853955d011SMarcel Moolenaar } 19863955d011SMarcel Moolenaar 1987*06b9b3e0SSimon J. Gerraty /* 1988*06b9b3e0SSimon J. Gerraty * Called when aborting due to errors in child shell to signal abnormal exit. 1989956e45f6SSimon J. Gerraty * The program exits. 1990*06b9b3e0SSimon J. Gerraty * Errors is the number of errors encountered in Make_Make. 1991*06b9b3e0SSimon J. Gerraty */ 19923955d011SMarcel Moolenaar void 1993956e45f6SSimon J. Gerraty Finish(int errs) 19943955d011SMarcel Moolenaar { 1995e2eeea75SSimon J. Gerraty if (shouldDieQuietly(NULL, -1)) 19963841c287SSimon J. Gerraty exit(2); 1997956e45f6SSimon J. Gerraty Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 19983955d011SMarcel Moolenaar } 19993955d011SMarcel Moolenaar 20003955d011SMarcel Moolenaar /* 20011748de26SSimon J. Gerraty * eunlink -- 20023955d011SMarcel Moolenaar * Remove a file carefully, avoiding directories. 20033955d011SMarcel Moolenaar */ 20043955d011SMarcel Moolenaar int 20053955d011SMarcel Moolenaar eunlink(const char *file) 20063955d011SMarcel Moolenaar { 20073955d011SMarcel Moolenaar struct stat st; 20083955d011SMarcel Moolenaar 20093955d011SMarcel Moolenaar if (lstat(file, &st) == -1) 20103955d011SMarcel Moolenaar return -1; 20113955d011SMarcel Moolenaar 20123955d011SMarcel Moolenaar if (S_ISDIR(st.st_mode)) { 20133955d011SMarcel Moolenaar errno = EISDIR; 20143955d011SMarcel Moolenaar return -1; 20153955d011SMarcel Moolenaar } 20163955d011SMarcel Moolenaar return unlink(file); 20173955d011SMarcel Moolenaar } 20183955d011SMarcel Moolenaar 2019956e45f6SSimon J. Gerraty static void 2020956e45f6SSimon J. Gerraty write_all(int fd, const void *data, size_t n) 2021956e45f6SSimon J. Gerraty { 2022956e45f6SSimon J. Gerraty const char *mem = data; 2023956e45f6SSimon J. Gerraty 2024956e45f6SSimon J. Gerraty while (n > 0) { 2025956e45f6SSimon J. Gerraty ssize_t written = write(fd, mem, n); 2026956e45f6SSimon J. Gerraty if (written == -1 && errno == EAGAIN) 2027956e45f6SSimon J. Gerraty continue; 2028956e45f6SSimon J. Gerraty if (written == -1) 2029956e45f6SSimon J. Gerraty break; 2030956e45f6SSimon J. Gerraty mem += written; 2031956e45f6SSimon J. Gerraty n -= (size_t)written; 2032956e45f6SSimon J. Gerraty } 2033956e45f6SSimon J. Gerraty } 2034956e45f6SSimon J. Gerraty 20353955d011SMarcel Moolenaar /* 2036956e45f6SSimon J. Gerraty * execDie -- 20373955d011SMarcel Moolenaar * Print why exec failed, avoiding stdio. 20383955d011SMarcel Moolenaar */ 2039956e45f6SSimon J. Gerraty void MAKE_ATTR_DEAD 2040956e45f6SSimon J. Gerraty execDie(const char *af, const char *av) 20413955d011SMarcel Moolenaar { 2042956e45f6SSimon J. Gerraty Buffer buf; 20433955d011SMarcel Moolenaar 2044e2eeea75SSimon J. Gerraty Buf_Init(&buf); 2045956e45f6SSimon J. Gerraty Buf_AddStr(&buf, progname); 2046956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ": "); 2047956e45f6SSimon J. Gerraty Buf_AddStr(&buf, af); 2048956e45f6SSimon J. Gerraty Buf_AddStr(&buf, "("); 2049956e45f6SSimon J. Gerraty Buf_AddStr(&buf, av); 2050956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ") failed ("); 2051956e45f6SSimon J. Gerraty Buf_AddStr(&buf, strerror(errno)); 2052956e45f6SSimon J. Gerraty Buf_AddStr(&buf, ")\n"); 20533955d011SMarcel Moolenaar 2054956e45f6SSimon J. Gerraty write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf)); 2055956e45f6SSimon J. Gerraty 2056956e45f6SSimon J. Gerraty Buf_Destroy(&buf, TRUE); 2057956e45f6SSimon J. Gerraty _exit(1); 20583955d011SMarcel Moolenaar } 20593955d011SMarcel Moolenaar 2060b46b9039SSimon J. Gerraty /* purge any relative paths */ 2061e1cee40dSSimon J. Gerraty static void 2062e2eeea75SSimon J. Gerraty purge_relative_cached_realpaths(void) 2063e1cee40dSSimon J. Gerraty { 2064956e45f6SSimon J. Gerraty HashEntry *he, *nhe; 2065956e45f6SSimon J. Gerraty HashIter hi; 2066b778b302SSimon J. Gerraty 2067e2eeea75SSimon J. Gerraty HashIter_Init(&hi, &cached_realpaths); 2068956e45f6SSimon J. Gerraty he = HashIter_Next(&hi); 2069956e45f6SSimon J. Gerraty while (he != NULL) { 2070956e45f6SSimon J. Gerraty nhe = HashIter_Next(&hi); 2071956e45f6SSimon J. Gerraty if (he->key[0] != '/') { 2072e2eeea75SSimon J. Gerraty DEBUG1(DIR, "cached_realpath: purging %s\n", he->key); 2073e2eeea75SSimon J. Gerraty HashTable_DeleteEntry(&cached_realpaths, he); 2074e2eeea75SSimon J. Gerraty /* XXX: What about the allocated he->value? Either 2075e2eeea75SSimon J. Gerraty * free them or document why they cannot be freed. */ 2076b46b9039SSimon J. Gerraty } 2077b46b9039SSimon J. Gerraty he = nhe; 2078b46b9039SSimon J. Gerraty } 2079b46b9039SSimon J. Gerraty } 2080e1cee40dSSimon J. Gerraty 2081e1cee40dSSimon J. Gerraty char * 2082e1cee40dSSimon J. Gerraty cached_realpath(const char *pathname, char *resolved) 2083e1cee40dSSimon J. Gerraty { 20842c3632d1SSimon J. Gerraty const char *rp; 2085e1cee40dSSimon J. Gerraty 2086e2eeea75SSimon J. Gerraty if (pathname == NULL || pathname[0] == '\0') 2087e1cee40dSSimon J. Gerraty return NULL; 2088e1cee40dSSimon J. Gerraty 2089e2eeea75SSimon J. Gerraty rp = HashTable_FindValue(&cached_realpaths, pathname); 2090e2eeea75SSimon J. Gerraty if (rp != NULL) { 2091b778b302SSimon J. Gerraty /* a hit */ 2092e2eeea75SSimon J. Gerraty strncpy(resolved, rp, MAXPATHLEN); 2093e2eeea75SSimon J. Gerraty resolved[MAXPATHLEN - 1] = '\0'; 2094e2eeea75SSimon J. Gerraty return resolved; 2095e2eeea75SSimon J. Gerraty } 20963841c287SSimon J. Gerraty 2097e2eeea75SSimon J. Gerraty rp = realpath(pathname, resolved); 2098e2eeea75SSimon J. Gerraty if (rp != NULL) { 2099e2eeea75SSimon J. Gerraty HashTable_Set(&cached_realpaths, pathname, bmake_strdup(rp)); 2100e2eeea75SSimon J. Gerraty DEBUG2(DIR, "cached_realpath: %s -> %s\n", pathname, rp); 2101e2eeea75SSimon J. Gerraty return resolved; 2102e2eeea75SSimon J. Gerraty } 2103e2eeea75SSimon J. Gerraty 2104e2eeea75SSimon J. Gerraty /* should we negative-cache? */ 2105e2eeea75SSimon J. Gerraty return NULL; 2106b778b302SSimon J. Gerraty } 2107b778b302SSimon J. Gerraty 21083841c287SSimon J. Gerraty /* 21093841c287SSimon J. Gerraty * Return true if we should die without noise. 2110e2eeea75SSimon J. Gerraty * For example our failing child was a sub-make or failure happened elsewhere. 21113841c287SSimon J. Gerraty */ 2112e2eeea75SSimon J. Gerraty Boolean 2113e2eeea75SSimon J. Gerraty shouldDieQuietly(GNode *gn, int bf) 21143841c287SSimon J. Gerraty { 21153841c287SSimon J. Gerraty static int quietly = -1; 21163841c287SSimon J. Gerraty 21173841c287SSimon J. Gerraty if (quietly < 0) { 2118e2eeea75SSimon J. Gerraty if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE)) 21193841c287SSimon J. Gerraty quietly = 0; 21203841c287SSimon J. Gerraty else if (bf >= 0) 21213841c287SSimon J. Gerraty quietly = bf; 21223841c287SSimon J. Gerraty else 2123*06b9b3e0SSimon J. Gerraty quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0; 21243841c287SSimon J. Gerraty } 21253841c287SSimon J. Gerraty return quietly; 21263841c287SSimon J. Gerraty } 21273841c287SSimon J. Gerraty 2128956e45f6SSimon J. Gerraty static void 2129956e45f6SSimon J. Gerraty SetErrorVars(GNode *gn) 2130956e45f6SSimon J. Gerraty { 2131956e45f6SSimon J. Gerraty StringListNode *ln; 2132956e45f6SSimon J. Gerraty 2133956e45f6SSimon J. Gerraty /* 2134956e45f6SSimon J. Gerraty * We can print this even if there is no .ERROR target. 2135956e45f6SSimon J. Gerraty */ 2136956e45f6SSimon J. Gerraty Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); 2137956e45f6SSimon J. Gerraty Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2138956e45f6SSimon J. Gerraty 2139*06b9b3e0SSimon J. Gerraty for (ln = gn->commands.first; ln != NULL; ln = ln->next) { 2140956e45f6SSimon J. Gerraty const char *cmd = ln->datum; 2141956e45f6SSimon J. Gerraty 2142956e45f6SSimon J. Gerraty if (cmd == NULL) 2143956e45f6SSimon J. Gerraty break; 2144956e45f6SSimon J. Gerraty Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); 2145956e45f6SSimon J. Gerraty } 2146956e45f6SSimon J. Gerraty } 2147956e45f6SSimon J. Gerraty 2148*06b9b3e0SSimon J. Gerraty /* 2149*06b9b3e0SSimon J. Gerraty * Print some helpful information in case of an error. 2150*06b9b3e0SSimon J. Gerraty * The caller should exit soon after calling this function. 2151*06b9b3e0SSimon J. Gerraty */ 21523955d011SMarcel Moolenaar void 2153e2eeea75SSimon J. Gerraty PrintOnError(GNode *gn, const char *msg) 21543955d011SMarcel Moolenaar { 2155e2eeea75SSimon J. Gerraty static GNode *errorNode = NULL; 21563955d011SMarcel Moolenaar 21572c3632d1SSimon J. Gerraty if (DEBUG(HASH)) { 21582c3632d1SSimon J. Gerraty Targ_Stats(); 21592c3632d1SSimon J. Gerraty Var_Stats(); 21602c3632d1SSimon J. Gerraty } 21612c3632d1SSimon J. Gerraty 2162*06b9b3e0SSimon J. Gerraty if (errorNode != NULL) 2163*06b9b3e0SSimon J. Gerraty return; /* we've been here! */ 21643841c287SSimon J. Gerraty 2165e2eeea75SSimon J. Gerraty if (msg != NULL) 2166e2eeea75SSimon J. Gerraty printf("%s", msg); 21673955d011SMarcel Moolenaar printf("\n%s: stopped in %s\n", progname, curdir); 21683955d011SMarcel Moolenaar 2169*06b9b3e0SSimon J. Gerraty /* we generally want to keep quiet if a sub-make died */ 2170*06b9b3e0SSimon J. Gerraty if (shouldDieQuietly(gn, -1)) 2171*06b9b3e0SSimon J. Gerraty return; 2172e2eeea75SSimon J. Gerraty 2173e2eeea75SSimon J. Gerraty if (gn != NULL) 2174956e45f6SSimon J. Gerraty SetErrorVars(gn); 2175e2eeea75SSimon J. Gerraty 2176e2eeea75SSimon J. Gerraty { 2177e2eeea75SSimon J. Gerraty char *errorVarsValues; 2178e2eeea75SSimon J. Gerraty (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 2179e2eeea75SSimon J. Gerraty VAR_GLOBAL, VARE_WANTRES, &errorVarsValues); 2180956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2181e2eeea75SSimon J. Gerraty printf("%s", errorVarsValues); 2182e2eeea75SSimon J. Gerraty free(errorVarsValues); 2183e2eeea75SSimon J. Gerraty } 2184e2eeea75SSimon J. Gerraty 2185ac3446e9SSimon J. Gerraty fflush(stdout); 2186ac3446e9SSimon J. Gerraty 21873955d011SMarcel Moolenaar /* 21883955d011SMarcel Moolenaar * Finally, see if there is a .ERROR target, and run it if so. 21893955d011SMarcel Moolenaar */ 2190e2eeea75SSimon J. Gerraty errorNode = Targ_FindNode(".ERROR"); 2191e2eeea75SSimon J. Gerraty if (errorNode != NULL) { 2192e2eeea75SSimon J. Gerraty errorNode->type |= OP_SPECIAL; 2193e2eeea75SSimon J. Gerraty Compat_Make(errorNode, errorNode); 21943955d011SMarcel Moolenaar } 21953955d011SMarcel Moolenaar } 21963955d011SMarcel Moolenaar 21973955d011SMarcel Moolenaar void 21983955d011SMarcel Moolenaar Main_ExportMAKEFLAGS(Boolean first) 21993955d011SMarcel Moolenaar { 22002c3632d1SSimon J. Gerraty static Boolean once = TRUE; 22012c3632d1SSimon J. Gerraty const char *expr; 22023955d011SMarcel Moolenaar char *s; 22033955d011SMarcel Moolenaar 22043955d011SMarcel Moolenaar if (once != first) 22053955d011SMarcel Moolenaar return; 22062c3632d1SSimon J. Gerraty once = FALSE; 22073955d011SMarcel Moolenaar 22082c3632d1SSimon J. Gerraty expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2209956e45f6SSimon J. Gerraty (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); 2210956e45f6SSimon J. Gerraty /* TODO: handle errors */ 22112c3632d1SSimon J. Gerraty if (s[0] != '\0') { 22123955d011SMarcel Moolenaar #ifdef POSIX 22133955d011SMarcel Moolenaar setenv("MAKEFLAGS", s, 1); 22143955d011SMarcel Moolenaar #else 22153955d011SMarcel Moolenaar setenv("MAKE", s, 1); 22163955d011SMarcel Moolenaar #endif 22173955d011SMarcel Moolenaar } 22183955d011SMarcel Moolenaar } 22193955d011SMarcel Moolenaar 22203955d011SMarcel Moolenaar char * 22213955d011SMarcel Moolenaar getTmpdir(void) 22223955d011SMarcel Moolenaar { 22233955d011SMarcel Moolenaar static char *tmpdir = NULL; 22243955d011SMarcel Moolenaar struct stat st; 22253955d011SMarcel Moolenaar 2226e2eeea75SSimon J. Gerraty if (tmpdir != NULL) 2227e2eeea75SSimon J. Gerraty return tmpdir; 2228e2eeea75SSimon J. Gerraty 2229e2eeea75SSimon J. Gerraty /* Honor $TMPDIR but only if it is valid. Ensure it ends with '/'. */ 2230e2eeea75SSimon J. Gerraty (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", 2231e2eeea75SSimon J. Gerraty VAR_GLOBAL, VARE_WANTRES, &tmpdir); 2232956e45f6SSimon J. Gerraty /* TODO: handle errors */ 2233e2eeea75SSimon J. Gerraty 22343955d011SMarcel Moolenaar if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 22353955d011SMarcel Moolenaar free(tmpdir); 22363955d011SMarcel Moolenaar tmpdir = bmake_strdup(_PATH_TMP); 22373955d011SMarcel Moolenaar } 22383955d011SMarcel Moolenaar return tmpdir; 22393955d011SMarcel Moolenaar } 22403955d011SMarcel Moolenaar 22413955d011SMarcel Moolenaar /* 22423955d011SMarcel Moolenaar * Create and open a temp file using "pattern". 2243956e45f6SSimon J. Gerraty * If out_fname is provided, set it to a copy of the filename created. 22443955d011SMarcel Moolenaar * Otherwise unlink the file once open. 22453955d011SMarcel Moolenaar */ 22463955d011SMarcel Moolenaar int 2247956e45f6SSimon J. Gerraty mkTempFile(const char *pattern, char **out_fname) 22483955d011SMarcel Moolenaar { 22493955d011SMarcel Moolenaar static char *tmpdir = NULL; 22503955d011SMarcel Moolenaar char tfile[MAXPATHLEN]; 22513955d011SMarcel Moolenaar int fd; 22523955d011SMarcel Moolenaar 2253e2eeea75SSimon J. Gerraty if (pattern == NULL) 22543955d011SMarcel Moolenaar pattern = TMPPAT; 2255956e45f6SSimon J. Gerraty if (tmpdir == NULL) 22563955d011SMarcel Moolenaar tmpdir = getTmpdir(); 22573955d011SMarcel Moolenaar if (pattern[0] == '/') { 2258e2eeea75SSimon J. Gerraty snprintf(tfile, sizeof tfile, "%s", pattern); 22593955d011SMarcel Moolenaar } else { 2260e2eeea75SSimon J. Gerraty snprintf(tfile, sizeof tfile, "%s%s", tmpdir, pattern); 22613955d011SMarcel Moolenaar } 22623955d011SMarcel Moolenaar if ((fd = mkstemp(tfile)) < 0) 2263e2eeea75SSimon J. Gerraty Punt("Could not create temporary file %s: %s", tfile, 2264e2eeea75SSimon J. Gerraty strerror(errno)); 2265*06b9b3e0SSimon J. Gerraty if (out_fname != NULL) { 2266956e45f6SSimon J. Gerraty *out_fname = bmake_strdup(tfile); 22673955d011SMarcel Moolenaar } else { 2268*06b9b3e0SSimon 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