1321964Ssjg/* $NetBSD: main.c,v 1.272 2017/06/19 19:58:24 christos Exp $ */ 2236769Sobrien 3236769Sobrien/* 4236769Sobrien * Copyright (c) 1988, 1989, 1990, 1993 5236769Sobrien * The Regents of the University of California. All rights reserved. 6236769Sobrien * 7236769Sobrien * This code is derived from software contributed to Berkeley by 8236769Sobrien * Adam de Boor. 9236769Sobrien * 10236769Sobrien * Redistribution and use in source and binary forms, with or without 11236769Sobrien * modification, are permitted provided that the following conditions 12236769Sobrien * are met: 13236769Sobrien * 1. Redistributions of source code must retain the above copyright 14236769Sobrien * notice, this list of conditions and the following disclaimer. 15236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 16236769Sobrien * notice, this list of conditions and the following disclaimer in the 17236769Sobrien * documentation and/or other materials provided with the distribution. 18236769Sobrien * 3. Neither the name of the University nor the names of its contributors 19236769Sobrien * may be used to endorse or promote products derived from this software 20236769Sobrien * without specific prior written permission. 21236769Sobrien * 22236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32236769Sobrien * SUCH DAMAGE. 33236769Sobrien */ 34236769Sobrien 35236769Sobrien/* 36236769Sobrien * Copyright (c) 1989 by Berkeley Softworks 37236769Sobrien * All rights reserved. 38236769Sobrien * 39236769Sobrien * This code is derived from software contributed to Berkeley by 40236769Sobrien * Adam de Boor. 41236769Sobrien * 42236769Sobrien * Redistribution and use in source and binary forms, with or without 43236769Sobrien * modification, are permitted provided that the following conditions 44236769Sobrien * are met: 45236769Sobrien * 1. Redistributions of source code must retain the above copyright 46236769Sobrien * notice, this list of conditions and the following disclaimer. 47236769Sobrien * 2. Redistributions in binary form must reproduce the above copyright 48236769Sobrien * notice, this list of conditions and the following disclaimer in the 49236769Sobrien * documentation and/or other materials provided with the distribution. 50236769Sobrien * 3. All advertising materials mentioning features or use of this software 51236769Sobrien * must display the following acknowledgement: 52236769Sobrien * This product includes software developed by the University of 53236769Sobrien * California, Berkeley and its contributors. 54236769Sobrien * 4. Neither the name of the University nor the names of its contributors 55236769Sobrien * may be used to endorse or promote products derived from this software 56236769Sobrien * without specific prior written permission. 57236769Sobrien * 58236769Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59236769Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60236769Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61236769Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62236769Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63236769Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64236769Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65236769Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66236769Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67236769Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68236769Sobrien * SUCH DAMAGE. 69236769Sobrien */ 70236769Sobrien 71236769Sobrien#ifndef MAKE_NATIVE 72321964Ssjgstatic char rcsid[] = "$NetBSD: main.c,v 1.272 2017/06/19 19:58:24 christos Exp $"; 73236769Sobrien#else 74236769Sobrien#include <sys/cdefs.h> 75236769Sobrien#ifndef lint 76236769Sobrien__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\ 77236769Sobrien The Regents of the University of California. All rights reserved."); 78236769Sobrien#endif /* not lint */ 79236769Sobrien 80236769Sobrien#ifndef lint 81236769Sobrien#if 0 82236769Sobrienstatic char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 83236769Sobrien#else 84321964Ssjg__RCSID("$NetBSD: main.c,v 1.272 2017/06/19 19:58:24 christos Exp $"); 85236769Sobrien#endif 86236769Sobrien#endif /* not lint */ 87236769Sobrien#endif 88236769Sobrien 89236769Sobrien/*- 90236769Sobrien * main.c -- 91236769Sobrien * The main file for this entire program. Exit routines etc 92236769Sobrien * reside here. 93236769Sobrien * 94236769Sobrien * Utility functions defined in this file: 95236769Sobrien * Main_ParseArgLine Takes a line of arguments, breaks them and 96236769Sobrien * treats them as if they were given when first 97236769Sobrien * invoked. Used by the parse module to implement 98236769Sobrien * the .MFLAGS target. 99236769Sobrien * 100236769Sobrien * Error Print a tagged error message. The global 101236769Sobrien * MAKE variable must have been defined. This 102292068Ssjg * takes a format string and optional arguments 103292068Ssjg * for it. 104236769Sobrien * 105236769Sobrien * Fatal Print an error message and exit. Also takes 106292068Ssjg * a format string and arguments for it. 107236769Sobrien * 108236769Sobrien * Punt Aborts all jobs and exits with a message. Also 109292068Ssjg * takes a format string and arguments for it. 110236769Sobrien * 111236769Sobrien * Finish Finish things up by printing the number of 112236769Sobrien * errors which occurred, as passed to it, and 113236769Sobrien * exiting. 114236769Sobrien */ 115236769Sobrien 116236769Sobrien#include <sys/types.h> 117236769Sobrien#include <sys/time.h> 118236769Sobrien#include <sys/param.h> 119236769Sobrien#include <sys/resource.h> 120236769Sobrien#include <sys/stat.h> 121276305Sngie#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 122276305Sngie#include <sys/sysctl.h> 123276305Sngie#endif 124236769Sobrien#include <sys/utsname.h> 125236769Sobrien#include "wait.h" 126236769Sobrien 127236769Sobrien#include <errno.h> 128253883Ssjg#include <signal.h> 129236769Sobrien#include <stdarg.h> 130236769Sobrien#include <stdio.h> 131236769Sobrien#include <stdlib.h> 132236769Sobrien#include <time.h> 133253883Ssjg#include <ctype.h> 134236769Sobrien 135236769Sobrien#include "make.h" 136236769Sobrien#include "hash.h" 137236769Sobrien#include "dir.h" 138236769Sobrien#include "job.h" 139236769Sobrien#include "pathnames.h" 140236769Sobrien#include "trace.h" 141236769Sobrien 142236769Sobrien#ifdef USE_IOVEC 143236769Sobrien#include <sys/uio.h> 144236769Sobrien#endif 145236769Sobrien 146236769Sobrien#ifndef DEFMAXLOCAL 147236769Sobrien#define DEFMAXLOCAL DEFMAXJOBS 148236769Sobrien#endif /* DEFMAXLOCAL */ 149236769Sobrien 150276305Sngie#ifndef __arraycount 151276305Sngie# define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 152276305Sngie#endif 153276305Sngie 154236769SobrienLst create; /* Targets to be made */ 155236769Sobrientime_t now; /* Time at start of make */ 156236769SobrienGNode *DEFAULT; /* .DEFAULT node */ 157236769SobrienBoolean allPrecious; /* .PRECIOUS given on line by itself */ 158321964SsjgBoolean deleteOnError; /* .DELETE_ON_ERROR: set */ 159236769Sobrien 160236769Sobrienstatic Boolean noBuiltins; /* -r flag */ 161236769Sobrienstatic Lst makefiles; /* ordered list of makefiles to read */ 162321964Ssjgstatic int printVars; /* -[vV] argument */ 163321964Ssjg#define COMPAT_VARS 1 164321964Ssjg#define EXPAND_VARS 2 165236769Sobrienstatic Lst variables; /* list of variables to print */ 166236769Sobrienint maxJobs; /* -j argument */ 167236769Sobrienstatic int maxJobTokens; /* -j argument */ 168236769SobrienBoolean compatMake; /* -B argument */ 169236769Sobrienint debug; /* -d argument */ 170240330SmarcelBoolean debugVflag; /* -dV */ 171236769SobrienBoolean noExecute; /* -n flag */ 172236769SobrienBoolean noRecursiveExecute; /* -N flag */ 173236769SobrienBoolean keepgoing; /* -k flag */ 174236769SobrienBoolean queryFlag; /* -q flag */ 175236769SobrienBoolean touchFlag; /* -t flag */ 176253883SsjgBoolean enterFlag; /* -w flag */ 177292068SsjgBoolean enterFlagObj; /* -w and objdir != srcdir */ 178236769SobrienBoolean ignoreErrors; /* -i flag */ 179236769SobrienBoolean beSilent; /* -s flag */ 180236769SobrienBoolean oldVars; /* variable substitution style */ 181236769SobrienBoolean checkEnvFirst; /* -e flag */ 182236769SobrienBoolean parseWarnFatal; /* -W flag */ 183236769SobrienBoolean jobServer; /* -J flag */ 184236769Sobrienstatic int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 185236769SobrienBoolean varNoExportEnv; /* -X flag */ 186236769SobrienBoolean doing_depend; /* Set while reading .depend */ 187236769Sobrienstatic Boolean jobsRunning; /* TRUE if the jobs might be running */ 188236769Sobrienstatic const char * tracefile; 189236769Sobrienstatic void MainParseArgs(int, char **); 190236769Sobrienstatic int ReadMakefile(const void *, const void *); 191237578Sobrienstatic void usage(void) MAKE_ATTR_DEAD; 192321964Ssjgstatic void purge_cached_realpaths(void); 193236769Sobrien 194236769Sobrienstatic Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 195236769Sobrienstatic char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 196236769Sobrienchar curdir[MAXPATHLEN + 1]; /* Startup directory */ 197236769Sobrienchar *progname; /* the program name */ 198236769Sobrienchar *makeDependfile; 199236769Sobrienpid_t myPid; 200253883Ssjgint makelevel; 201236769Sobrien 202236769SobrienBoolean forceJobs = FALSE; 203236769Sobrien 204236769Sobrien/* 205236769Sobrien * On some systems MACHINE is defined as something other than 206236769Sobrien * what we want. 207236769Sobrien */ 208236769Sobrien#ifdef FORCE_MACHINE 209236769Sobrien# undef MACHINE 210236769Sobrien# define MACHINE FORCE_MACHINE 211236769Sobrien#endif 212236769Sobrien 213236769Sobrienextern Lst parseIncPath; 214236769Sobrien 215253883Ssjg/* 216253883Ssjg * For compatibility with the POSIX version of MAKEFLAGS that includes 217253883Ssjg * all the options with out -, convert flags to -f -l -a -g -s. 218253883Ssjg */ 219253883Ssjgstatic char * 220253883Ssjgexplode(const char *flags) 221253883Ssjg{ 222253883Ssjg size_t len; 223253883Ssjg char *nf, *st; 224253883Ssjg const char *f; 225253883Ssjg 226253883Ssjg if (flags == NULL) 227253883Ssjg return NULL; 228253883Ssjg 229253883Ssjg for (f = flags; *f; f++) 230253883Ssjg if (!isalpha((unsigned char)*f)) 231253883Ssjg break; 232253883Ssjg 233253883Ssjg if (*f) 234253883Ssjg return bmake_strdup(flags); 235253883Ssjg 236253883Ssjg len = strlen(flags); 237253883Ssjg st = nf = bmake_malloc(len * 3 + 1); 238253883Ssjg while (*flags) { 239253883Ssjg *nf++ = '-'; 240253883Ssjg *nf++ = *flags++; 241253883Ssjg *nf++ = ' '; 242253883Ssjg } 243253883Ssjg *nf = '\0'; 244253883Ssjg return st; 245253883Ssjg} 246253883Ssjg 247236769Sobrienstatic void 248236769Sobrienparse_debug_options(const char *argvalue) 249236769Sobrien{ 250236769Sobrien const char *modules; 251236769Sobrien const char *mode; 252236769Sobrien char *fname; 253236769Sobrien int len; 254236769Sobrien 255236769Sobrien for (modules = argvalue; *modules; ++modules) { 256236769Sobrien switch (*modules) { 257236769Sobrien case 'A': 258236769Sobrien debug = ~0; 259236769Sobrien break; 260236769Sobrien case 'a': 261236769Sobrien debug |= DEBUG_ARCH; 262236769Sobrien break; 263236769Sobrien case 'C': 264236769Sobrien debug |= DEBUG_CWD; 265236769Sobrien break; 266236769Sobrien case 'c': 267236769Sobrien debug |= DEBUG_COND; 268236769Sobrien break; 269236769Sobrien case 'd': 270236769Sobrien debug |= DEBUG_DIR; 271236769Sobrien break; 272236769Sobrien case 'e': 273236769Sobrien debug |= DEBUG_ERROR; 274236769Sobrien break; 275236769Sobrien case 'f': 276236769Sobrien debug |= DEBUG_FOR; 277236769Sobrien break; 278236769Sobrien case 'g': 279236769Sobrien if (modules[1] == '1') { 280236769Sobrien debug |= DEBUG_GRAPH1; 281236769Sobrien ++modules; 282236769Sobrien } 283236769Sobrien else if (modules[1] == '2') { 284236769Sobrien debug |= DEBUG_GRAPH2; 285236769Sobrien ++modules; 286236769Sobrien } 287236769Sobrien else if (modules[1] == '3') { 288236769Sobrien debug |= DEBUG_GRAPH3; 289236769Sobrien ++modules; 290236769Sobrien } 291236769Sobrien break; 292236769Sobrien case 'j': 293236769Sobrien debug |= DEBUG_JOB; 294236769Sobrien break; 295236769Sobrien case 'l': 296236769Sobrien debug |= DEBUG_LOUD; 297236769Sobrien break; 298236769Sobrien case 'M': 299236769Sobrien debug |= DEBUG_META; 300236769Sobrien break; 301236769Sobrien case 'm': 302236769Sobrien debug |= DEBUG_MAKE; 303236769Sobrien break; 304236769Sobrien case 'n': 305236769Sobrien debug |= DEBUG_SCRIPT; 306236769Sobrien break; 307236769Sobrien case 'p': 308236769Sobrien debug |= DEBUG_PARSE; 309236769Sobrien break; 310236769Sobrien case 's': 311236769Sobrien debug |= DEBUG_SUFF; 312236769Sobrien break; 313236769Sobrien case 't': 314236769Sobrien debug |= DEBUG_TARG; 315236769Sobrien break; 316240330Smarcel case 'V': 317240330Smarcel debugVflag = TRUE; 318240330Smarcel break; 319236769Sobrien case 'v': 320236769Sobrien debug |= DEBUG_VAR; 321236769Sobrien break; 322236769Sobrien case 'x': 323236769Sobrien debug |= DEBUG_SHELL; 324236769Sobrien break; 325236769Sobrien case 'F': 326236769Sobrien if (debug_file != stdout && debug_file != stderr) 327236769Sobrien fclose(debug_file); 328236769Sobrien if (*++modules == '+') { 329236769Sobrien modules++; 330236769Sobrien mode = "a"; 331236769Sobrien } else 332236769Sobrien mode = "w"; 333236769Sobrien if (strcmp(modules, "stdout") == 0) { 334236769Sobrien debug_file = stdout; 335236769Sobrien goto debug_setbuf; 336236769Sobrien } 337236769Sobrien if (strcmp(modules, "stderr") == 0) { 338236769Sobrien debug_file = stderr; 339236769Sobrien goto debug_setbuf; 340236769Sobrien } 341236769Sobrien len = strlen(modules); 342321964Ssjg fname = bmake_malloc(len + 20); 343236769Sobrien memcpy(fname, modules, len + 1); 344236769Sobrien /* Let the filename be modified by the pid */ 345236769Sobrien if (strcmp(fname + len - 3, ".%d") == 0) 346236769Sobrien snprintf(fname + len - 2, 20, "%d", getpid()); 347236769Sobrien debug_file = fopen(fname, mode); 348236769Sobrien if (!debug_file) { 349236769Sobrien fprintf(stderr, "Cannot open debug file %s\n", 350236769Sobrien fname); 351236769Sobrien usage(); 352236769Sobrien } 353236769Sobrien free(fname); 354236769Sobrien goto debug_setbuf; 355236769Sobrien default: 356236769Sobrien (void)fprintf(stderr, 357236769Sobrien "%s: illegal argument to d option -- %c\n", 358236769Sobrien progname, *modules); 359236769Sobrien usage(); 360236769Sobrien } 361236769Sobrien } 362236769Sobriendebug_setbuf: 363236769Sobrien /* 364236769Sobrien * Make the debug_file unbuffered, and make 365236769Sobrien * stdout line buffered (unless debugfile == stdout). 366236769Sobrien */ 367236769Sobrien setvbuf(debug_file, NULL, _IONBF, 0); 368236769Sobrien if (debug_file != stdout) { 369236769Sobrien setvbuf(stdout, NULL, _IOLBF, 0); 370236769Sobrien } 371236769Sobrien} 372236769Sobrien 373321964Ssjg/* 374321964Ssjg * does path contain any relative components 375321964Ssjg */ 376321964Ssjgstatic int 377321964Ssjgis_relpath(const char *path) 378321964Ssjg{ 379321964Ssjg const char *cp; 380321964Ssjg 381321964Ssjg if (path[0] != '/') 382321964Ssjg return TRUE; 383321964Ssjg cp = path; 384321964Ssjg do { 385321964Ssjg cp = strstr(cp, "/."); 386321964Ssjg if (!cp) 387321964Ssjg break; 388321964Ssjg cp += 2; 389321964Ssjg if (cp[0] == '/' || cp[0] == '\0') 390321964Ssjg return TRUE; 391321964Ssjg else if (cp[0] == '.') { 392321964Ssjg if (cp[1] == '/' || cp[1] == '\0') 393321964Ssjg return TRUE; 394321964Ssjg } 395321964Ssjg } while (cp); 396321964Ssjg return FALSE; 397321964Ssjg} 398321964Ssjg 399236769Sobrien/*- 400236769Sobrien * MainParseArgs -- 401236769Sobrien * Parse a given argument vector. Called from main() and from 402236769Sobrien * Main_ParseArgLine() when the .MAKEFLAGS target is used. 403236769Sobrien * 404236769Sobrien * XXX: Deal with command line overriding .MAKEFLAGS in makefile 405236769Sobrien * 406236769Sobrien * Results: 407236769Sobrien * None 408236769Sobrien * 409236769Sobrien * Side Effects: 410236769Sobrien * Various global and local flags will be set depending on the flags 411236769Sobrien * given 412236769Sobrien */ 413236769Sobrienstatic void 414236769SobrienMainParseArgs(int argc, char **argv) 415236769Sobrien{ 416236769Sobrien char *p; 417236769Sobrien int c = '?'; 418236769Sobrien int arginc; 419236769Sobrien char *argvalue; 420236769Sobrien const char *getopt_def; 421321964Ssjg struct stat sa, sb; 422236769Sobrien char *optscan; 423236769Sobrien Boolean inOption, dashDash = FALSE; 424236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 425236769Sobrien 426321964Ssjg#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w" 427236769Sobrien/* Can't actually use getopt(3) because rescanning is not portable */ 428236769Sobrien 429236769Sobrien getopt_def = OPTFLAGS; 430236769Sobrienrearg: 431236769Sobrien inOption = FALSE; 432236769Sobrien optscan = NULL; 433236769Sobrien while(argc > 1) { 434236769Sobrien char *getopt_spec; 435236769Sobrien if(!inOption) 436236769Sobrien optscan = argv[1]; 437236769Sobrien c = *optscan++; 438236769Sobrien arginc = 0; 439236769Sobrien if(inOption) { 440236769Sobrien if(c == '\0') { 441236769Sobrien ++argv; 442236769Sobrien --argc; 443236769Sobrien inOption = FALSE; 444236769Sobrien continue; 445236769Sobrien } 446236769Sobrien } else { 447236769Sobrien if (c != '-' || dashDash) 448236769Sobrien break; 449236769Sobrien inOption = TRUE; 450236769Sobrien c = *optscan++; 451236769Sobrien } 452236769Sobrien /* '-' found at some earlier point */ 453236769Sobrien getopt_spec = strchr(getopt_def, c); 454236769Sobrien if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 455236769Sobrien /* -<something> found, and <something> should have an arg */ 456236769Sobrien inOption = FALSE; 457236769Sobrien arginc = 1; 458236769Sobrien argvalue = optscan; 459236769Sobrien if(*argvalue == '\0') { 460236769Sobrien if (argc < 3) 461236769Sobrien goto noarg; 462236769Sobrien argvalue = argv[2]; 463236769Sobrien arginc = 2; 464236769Sobrien } 465236769Sobrien } else { 466236769Sobrien argvalue = NULL; 467236769Sobrien } 468236769Sobrien switch(c) { 469236769Sobrien case '\0': 470236769Sobrien arginc = 1; 471236769Sobrien inOption = FALSE; 472236769Sobrien break; 473236769Sobrien case 'B': 474236769Sobrien compatMake = TRUE; 475236769Sobrien Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 476236769Sobrien Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 477236769Sobrien break; 478236769Sobrien case 'C': 479236769Sobrien if (chdir(argvalue) == -1) { 480236769Sobrien (void)fprintf(stderr, 481236769Sobrien "%s: chdir %s: %s\n", 482236769Sobrien progname, argvalue, 483236769Sobrien strerror(errno)); 484236769Sobrien exit(1); 485236769Sobrien } 486236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 487236769Sobrien (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 488236769Sobrien exit(2); 489236769Sobrien } 490321964Ssjg if (!is_relpath(argvalue) && 491321964Ssjg stat(argvalue, &sa) != -1 && 492321964Ssjg stat(curdir, &sb) != -1 && 493321964Ssjg sa.st_ino == sb.st_ino && 494321964Ssjg sa.st_dev == sb.st_dev) 495321964Ssjg strncpy(curdir, argvalue, MAXPATHLEN); 496236769Sobrien ignorePWD = TRUE; 497236769Sobrien break; 498236769Sobrien case 'D': 499236769Sobrien if (argvalue == NULL || argvalue[0] == 0) goto noarg; 500236769Sobrien Var_Set(argvalue, "1", VAR_GLOBAL, 0); 501236769Sobrien Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 502236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 503236769Sobrien break; 504236769Sobrien case 'I': 505236769Sobrien if (argvalue == NULL) goto noarg; 506236769Sobrien Parse_AddIncludeDir(argvalue); 507236769Sobrien Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 508236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 509236769Sobrien break; 510236769Sobrien case 'J': 511236769Sobrien if (argvalue == NULL) goto noarg; 512236769Sobrien if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 513236769Sobrien (void)fprintf(stderr, 514236769Sobrien "%s: internal error -- J option malformed (%s)\n", 515236769Sobrien progname, argvalue); 516236769Sobrien usage(); 517236769Sobrien } 518236769Sobrien if ((fcntl(jp_0, F_GETFD, 0) < 0) || 519236769Sobrien (fcntl(jp_1, F_GETFD, 0) < 0)) { 520236769Sobrien#if 0 521236769Sobrien (void)fprintf(stderr, 522236769Sobrien "%s: ###### warning -- J descriptors were closed!\n", 523236769Sobrien progname); 524236769Sobrien exit(2); 525236769Sobrien#endif 526236769Sobrien jp_0 = -1; 527236769Sobrien jp_1 = -1; 528236769Sobrien compatMake = TRUE; 529236769Sobrien } else { 530236769Sobrien Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 531236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 532236769Sobrien jobServer = TRUE; 533236769Sobrien } 534236769Sobrien break; 535236769Sobrien case 'N': 536236769Sobrien noExecute = TRUE; 537236769Sobrien noRecursiveExecute = TRUE; 538236769Sobrien Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 539236769Sobrien break; 540236769Sobrien case 'S': 541236769Sobrien keepgoing = FALSE; 542236769Sobrien Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 543236769Sobrien break; 544236769Sobrien case 'T': 545236769Sobrien if (argvalue == NULL) goto noarg; 546236769Sobrien tracefile = bmake_strdup(argvalue); 547236769Sobrien Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 548236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 549236769Sobrien break; 550236769Sobrien case 'V': 551321964Ssjg case 'v': 552236769Sobrien if (argvalue == NULL) goto noarg; 553321964Ssjg printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; 554236769Sobrien (void)Lst_AtEnd(variables, argvalue); 555236769Sobrien Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 556236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 557236769Sobrien break; 558236769Sobrien case 'W': 559236769Sobrien parseWarnFatal = TRUE; 560236769Sobrien break; 561236769Sobrien case 'X': 562236769Sobrien varNoExportEnv = TRUE; 563236769Sobrien Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 564236769Sobrien break; 565236769Sobrien case 'd': 566236769Sobrien if (argvalue == NULL) goto noarg; 567236769Sobrien /* If '-d-opts' don't pass to children */ 568236769Sobrien if (argvalue[0] == '-') 569236769Sobrien argvalue++; 570236769Sobrien else { 571236769Sobrien Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 572236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 573236769Sobrien } 574236769Sobrien parse_debug_options(argvalue); 575236769Sobrien break; 576236769Sobrien case 'e': 577236769Sobrien checkEnvFirst = TRUE; 578236769Sobrien Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 579236769Sobrien break; 580236769Sobrien case 'f': 581236769Sobrien if (argvalue == NULL) goto noarg; 582236769Sobrien (void)Lst_AtEnd(makefiles, argvalue); 583236769Sobrien break; 584236769Sobrien case 'i': 585236769Sobrien ignoreErrors = TRUE; 586236769Sobrien Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 587236769Sobrien break; 588236769Sobrien case 'j': 589236769Sobrien if (argvalue == NULL) goto noarg; 590236769Sobrien forceJobs = TRUE; 591236769Sobrien maxJobs = strtol(argvalue, &p, 0); 592236769Sobrien if (*p != '\0' || maxJobs < 1) { 593236769Sobrien (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 594236769Sobrien progname); 595236769Sobrien exit(1); 596236769Sobrien } 597236769Sobrien Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 598236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 599236769Sobrien Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 600236769Sobrien maxJobTokens = maxJobs; 601236769Sobrien break; 602236769Sobrien case 'k': 603236769Sobrien keepgoing = TRUE; 604236769Sobrien Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 605236769Sobrien break; 606236769Sobrien case 'm': 607236769Sobrien if (argvalue == NULL) goto noarg; 608236769Sobrien /* look for magic parent directory search string */ 609236769Sobrien if (strncmp(".../", argvalue, 4) == 0) { 610236769Sobrien if (!Dir_FindHereOrAbove(curdir, argvalue+4, 611236769Sobrien found_path, sizeof(found_path))) 612236769Sobrien break; /* nothing doing */ 613236769Sobrien (void)Dir_AddDir(sysIncPath, found_path); 614236769Sobrien } else { 615236769Sobrien (void)Dir_AddDir(sysIncPath, argvalue); 616236769Sobrien } 617236769Sobrien Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 618236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 619236769Sobrien break; 620236769Sobrien case 'n': 621236769Sobrien noExecute = TRUE; 622236769Sobrien Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 623236769Sobrien break; 624236769Sobrien case 'q': 625236769Sobrien queryFlag = TRUE; 626236769Sobrien /* Kind of nonsensical, wot? */ 627236769Sobrien Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 628236769Sobrien break; 629236769Sobrien case 'r': 630236769Sobrien noBuiltins = TRUE; 631236769Sobrien Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 632236769Sobrien break; 633236769Sobrien case 's': 634236769Sobrien beSilent = TRUE; 635236769Sobrien Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 636236769Sobrien break; 637236769Sobrien case 't': 638236769Sobrien touchFlag = TRUE; 639236769Sobrien Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 640236769Sobrien break; 641253883Ssjg case 'w': 642253883Ssjg enterFlag = TRUE; 643253883Ssjg Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 644253883Ssjg break; 645236769Sobrien case '-': 646236769Sobrien dashDash = TRUE; 647236769Sobrien break; 648236769Sobrien default: 649236769Sobrien case '?': 650236769Sobrien#ifndef MAKE_NATIVE 651236769Sobrien fprintf(stderr, "getopt(%s) -> %d (%c)\n", 652236769Sobrien OPTFLAGS, c, c); 653236769Sobrien#endif 654236769Sobrien usage(); 655236769Sobrien } 656236769Sobrien argv += arginc; 657236769Sobrien argc -= arginc; 658236769Sobrien } 659236769Sobrien 660236769Sobrien oldVars = TRUE; 661236769Sobrien 662236769Sobrien /* 663236769Sobrien * See if the rest of the arguments are variable assignments and 664236769Sobrien * perform them if so. Else take them to be targets and stuff them 665236769Sobrien * on the end of the "create" list. 666236769Sobrien */ 667236769Sobrien for (; argc > 1; ++argv, --argc) 668236769Sobrien if (Parse_IsVar(argv[1])) { 669236769Sobrien Parse_DoVar(argv[1], VAR_CMD); 670236769Sobrien } else { 671236769Sobrien if (!*argv[1]) 672236769Sobrien Punt("illegal (null) argument."); 673236769Sobrien if (*argv[1] == '-' && !dashDash) 674236769Sobrien goto rearg; 675236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 676236769Sobrien } 677236769Sobrien 678236769Sobrien return; 679236769Sobriennoarg: 680236769Sobrien (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 681236769Sobrien progname, c); 682236769Sobrien usage(); 683236769Sobrien} 684236769Sobrien 685236769Sobrien/*- 686236769Sobrien * Main_ParseArgLine -- 687236769Sobrien * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 688236769Sobrien * is encountered and by main() when reading the .MAKEFLAGS envariable. 689236769Sobrien * Takes a line of arguments and breaks it into its 690236769Sobrien * component words and passes those words and the number of them to the 691236769Sobrien * MainParseArgs function. 692236769Sobrien * The line should have all its leading whitespace removed. 693236769Sobrien * 694236769Sobrien * Input: 695236769Sobrien * line Line to fracture 696236769Sobrien * 697236769Sobrien * Results: 698236769Sobrien * None 699236769Sobrien * 700236769Sobrien * Side Effects: 701236769Sobrien * Only those that come from the various arguments. 702236769Sobrien */ 703236769Sobrienvoid 704236769SobrienMain_ParseArgLine(const char *line) 705236769Sobrien{ 706236769Sobrien char **argv; /* Manufactured argument vector */ 707236769Sobrien int argc; /* Number of arguments in argv */ 708236769Sobrien char *args; /* Space used by the args */ 709236769Sobrien char *buf, *p1; 710236769Sobrien char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 711236769Sobrien size_t len; 712236769Sobrien 713236769Sobrien if (line == NULL) 714236769Sobrien return; 715236769Sobrien for (; *line == ' '; ++line) 716236769Sobrien continue; 717236769Sobrien if (!*line) 718236769Sobrien return; 719236769Sobrien 720236769Sobrien#ifndef POSIX 721236769Sobrien { 722236769Sobrien /* 723236769Sobrien * $MAKE may simply be naming the make(1) binary 724236769Sobrien */ 725236769Sobrien char *cp; 726236769Sobrien 727236769Sobrien if (!(cp = strrchr(line, '/'))) 728236769Sobrien cp = line; 729236769Sobrien if ((cp = strstr(cp, "make")) && 730236769Sobrien strcmp(cp, "make") == 0) 731236769Sobrien return; 732236769Sobrien } 733236769Sobrien#endif 734236769Sobrien buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 735236769Sobrien (void)snprintf(buf, len, "%s %s", argv0, line); 736321964Ssjg free(p1); 737236769Sobrien 738236769Sobrien argv = brk_string(buf, &argc, TRUE, &args); 739236769Sobrien if (argv == NULL) { 740236769Sobrien Error("Unterminated quoted string [%s]", buf); 741236769Sobrien free(buf); 742236769Sobrien return; 743236769Sobrien } 744236769Sobrien free(buf); 745236769Sobrien MainParseArgs(argc, argv); 746236769Sobrien 747236769Sobrien free(args); 748236769Sobrien free(argv); 749236769Sobrien} 750236769Sobrien 751236769SobrienBoolean 752321964SsjgMain_SetObjdir(const char *fmt, ...) 753236769Sobrien{ 754236769Sobrien struct stat sb; 755321964Ssjg char *path; 756236769Sobrien char buf[MAXPATHLEN + 1]; 757321964Ssjg char buf2[MAXPATHLEN + 1]; 758236769Sobrien Boolean rc = FALSE; 759321964Ssjg va_list ap; 760236769Sobrien 761321964Ssjg va_start(ap, fmt); 762321964Ssjg vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 763321964Ssjg va_end(ap); 764236769Sobrien 765236769Sobrien if (path[0] != '/') { 766321964Ssjg snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 767321964Ssjg path = buf2; 768236769Sobrien } 769236769Sobrien 770236769Sobrien /* look for the directory and try to chdir there */ 771236769Sobrien if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 772236769Sobrien if (chdir(path)) { 773236769Sobrien (void)fprintf(stderr, "make warning: %s: %s.\n", 774236769Sobrien path, strerror(errno)); 775236769Sobrien } else { 776236769Sobrien strncpy(objdir, path, MAXPATHLEN); 777236769Sobrien Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 778236769Sobrien setenv("PWD", objdir, 1); 779236769Sobrien Dir_InitDot(); 780321964Ssjg purge_cached_realpaths(); 781236769Sobrien rc = TRUE; 782292068Ssjg if (enterFlag && strcmp(objdir, curdir) != 0) 783292068Ssjg enterFlagObj = TRUE; 784236769Sobrien } 785236769Sobrien } 786236769Sobrien 787236769Sobrien return rc; 788236769Sobrien} 789236769Sobrien 790321964Ssjgstatic Boolean 791321964SsjgMain_SetVarObjdir(const char *var, const char *suffix) 792321964Ssjg{ 793321964Ssjg char *p, *path, *xpath; 794321964Ssjg 795321964Ssjg if ((path = Var_Value(var, VAR_CMD, &p)) == NULL) 796321964Ssjg return FALSE; 797321964Ssjg 798321964Ssjg /* expand variable substitutions */ 799321964Ssjg if (strchr(path, '$') != 0) 800321964Ssjg xpath = Var_Subst(NULL, path, VAR_GLOBAL, VARF_WANTRES); 801321964Ssjg else 802321964Ssjg xpath = path; 803321964Ssjg 804321964Ssjg (void)Main_SetObjdir("%s%s", xpath, suffix); 805321964Ssjg 806321964Ssjg if (xpath != path) 807321964Ssjg free(xpath); 808321964Ssjg free(p); 809321964Ssjg return TRUE; 810321964Ssjg} 811321964Ssjg 812236769Sobrien/*- 813236769Sobrien * ReadAllMakefiles -- 814236769Sobrien * wrapper around ReadMakefile() to read all. 815236769Sobrien * 816236769Sobrien * Results: 817236769Sobrien * TRUE if ok, FALSE on error 818236769Sobrien */ 819236769Sobrienstatic int 820236769SobrienReadAllMakefiles(const void *p, const void *q) 821236769Sobrien{ 822236769Sobrien return (ReadMakefile(p, q) == 0); 823236769Sobrien} 824236769Sobrien 825236769Sobrienint 826236769Sobrienstr2Lst_Append(Lst lp, char *str, const char *sep) 827236769Sobrien{ 828236769Sobrien char *cp; 829236769Sobrien int n; 830236769Sobrien 831236769Sobrien if (!sep) 832236769Sobrien sep = " \t"; 833236769Sobrien 834236769Sobrien for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 835236769Sobrien (void)Lst_AtEnd(lp, cp); 836236769Sobrien n++; 837236769Sobrien } 838236769Sobrien return (n); 839236769Sobrien} 840236769Sobrien 841236769Sobrien#ifdef SIGINFO 842236769Sobrien/*ARGSUSED*/ 843236769Sobrienstatic void 844237578Sobriensiginfo(int signo MAKE_ATTR_UNUSED) 845236769Sobrien{ 846236769Sobrien char dir[MAXPATHLEN]; 847236769Sobrien char str[2 * MAXPATHLEN]; 848236769Sobrien int len; 849236769Sobrien if (getcwd(dir, sizeof(dir)) == NULL) 850236769Sobrien return; 851236769Sobrien len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 852236769Sobrien if (len > 0) 853236769Sobrien (void)write(STDERR_FILENO, str, (size_t)len); 854236769Sobrien} 855236769Sobrien#endif 856236769Sobrien 857236769Sobrien/* 858236769Sobrien * Allow makefiles some control over the mode we run in. 859236769Sobrien */ 860236769Sobrienvoid 861236769SobrienMakeMode(const char *mode) 862236769Sobrien{ 863236769Sobrien char *mp = NULL; 864236769Sobrien 865236769Sobrien if (!mode) 866292068Ssjg mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", 867321964Ssjg VAR_GLOBAL, VARF_WANTRES); 868236769Sobrien 869236769Sobrien if (mode && *mode) { 870236769Sobrien if (strstr(mode, "compat")) { 871236769Sobrien compatMake = TRUE; 872236769Sobrien forceJobs = FALSE; 873236769Sobrien } 874236769Sobrien#if USE_META 875236769Sobrien if (strstr(mode, "meta")) 876249033Ssjg meta_mode_init(mode); 877236769Sobrien#endif 878236769Sobrien } 879321964Ssjg 880321964Ssjg free(mp); 881236769Sobrien} 882236769Sobrien 883321964Ssjgstatic void 884321964SsjgdoPrintVars(void) 885321964Ssjg{ 886321964Ssjg LstNode ln; 887321964Ssjg Boolean expandVars; 888321964Ssjg 889321964Ssjg if (printVars == EXPAND_VARS) 890321964Ssjg expandVars = TRUE; 891321964Ssjg else if (debugVflag) 892321964Ssjg expandVars = FALSE; 893321964Ssjg else 894321964Ssjg expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 895321964Ssjg 896321964Ssjg for (ln = Lst_First(variables); ln != NULL; 897321964Ssjg ln = Lst_Succ(ln)) { 898321964Ssjg char *var = (char *)Lst_Datum(ln); 899321964Ssjg char *value; 900321964Ssjg char *p1; 901321964Ssjg 902321964Ssjg if (strchr(var, '$')) { 903321964Ssjg value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 904321964Ssjg VARF_WANTRES); 905321964Ssjg } else if (expandVars) { 906321964Ssjg char tmp[128]; 907321964Ssjg int len = snprintf(tmp, sizeof(tmp), "${%s}", var); 908321964Ssjg 909321964Ssjg if (len >= (int)sizeof(tmp)) 910321964Ssjg Fatal("%s: variable name too big: %s", 911321964Ssjg progname, var); 912321964Ssjg value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, 913321964Ssjg VARF_WANTRES); 914321964Ssjg } else { 915321964Ssjg value = Var_Value(var, VAR_GLOBAL, &p1); 916321964Ssjg } 917321964Ssjg printf("%s\n", value ? value : ""); 918321964Ssjg free(p1); 919321964Ssjg } 920321964Ssjg} 921321964Ssjg 922321964Ssjgstatic Boolean 923321964SsjgrunTargets(void) 924321964Ssjg{ 925321964Ssjg Lst targs; /* target nodes to create -- passed to Make_Init */ 926321964Ssjg Boolean outOfDate; /* FALSE if all targets up to date */ 927321964Ssjg 928321964Ssjg /* 929321964Ssjg * Have now read the entire graph and need to make a list of 930321964Ssjg * targets to create. If none was given on the command line, 931321964Ssjg * we consult the parsing module to find the main target(s) 932321964Ssjg * to create. 933321964Ssjg */ 934321964Ssjg if (Lst_IsEmpty(create)) 935321964Ssjg targs = Parse_MainName(); 936321964Ssjg else 937321964Ssjg targs = Targ_FindList(create, TARG_CREATE); 938321964Ssjg 939321964Ssjg if (!compatMake) { 940321964Ssjg /* 941321964Ssjg * Initialize job module before traversing the graph 942321964Ssjg * now that any .BEGIN and .END targets have been read. 943321964Ssjg * This is done only if the -q flag wasn't given 944321964Ssjg * (to prevent the .BEGIN from being executed should 945321964Ssjg * it exist). 946321964Ssjg */ 947321964Ssjg if (!queryFlag) { 948321964Ssjg Job_Init(); 949321964Ssjg jobsRunning = TRUE; 950321964Ssjg } 951321964Ssjg 952321964Ssjg /* Traverse the graph, checking on all the targets */ 953321964Ssjg outOfDate = Make_Run(targs); 954321964Ssjg } else { 955321964Ssjg /* 956321964Ssjg * Compat_Init will take care of creating all the 957321964Ssjg * targets as well as initializing the module. 958321964Ssjg */ 959321964Ssjg Compat_Run(targs); 960321964Ssjg outOfDate = FALSE; 961321964Ssjg } 962321964Ssjg Lst_Destroy(targs, NULL); 963321964Ssjg return outOfDate; 964321964Ssjg} 965321964Ssjg 966236769Sobrien/*- 967236769Sobrien * main -- 968236769Sobrien * The main function, for obvious reasons. Initializes variables 969236769Sobrien * and a few modules, then parses the arguments give it in the 970236769Sobrien * environment and on the command line. Reads the system makefile 971236769Sobrien * followed by either Makefile, makefile or the file given by the 972236769Sobrien * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 973236769Sobrien * flags it has received by then uses either the Make or the Compat 974236769Sobrien * module to create the initial list of targets. 975236769Sobrien * 976236769Sobrien * Results: 977236769Sobrien * If -q was given, exits -1 if anything was out-of-date. Else it exits 978236769Sobrien * 0. 979236769Sobrien * 980236769Sobrien * Side Effects: 981236769Sobrien * The program exits when done. Targets are created. etc. etc. etc. 982236769Sobrien */ 983236769Sobrienint 984236769Sobrienmain(int argc, char **argv) 985236769Sobrien{ 986321964Ssjg Boolean outOfDate; /* FALSE if all targets up to date */ 987236769Sobrien struct stat sb, sa; 988250750Ssjg char *p1, *path; 989236769Sobrien char mdpath[MAXPATHLEN]; 990236769Sobrien#ifdef FORCE_MACHINE 991236769Sobrien const char *machine = FORCE_MACHINE; 992236769Sobrien#else 993236769Sobrien const char *machine = getenv("MACHINE"); 994236769Sobrien#endif 995236769Sobrien const char *machine_arch = getenv("MACHINE_ARCH"); 996236769Sobrien char *syspath = getenv("MAKESYSPATH"); 997236769Sobrien Lst sysMkPath; /* Path of sys.mk */ 998236769Sobrien char *cp = NULL, *start; 999236769Sobrien /* avoid faults on read-only strings */ 1000236769Sobrien static char defsyspath[] = _PATH_DEFSYSPATH; 1001236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 1002236769Sobrien struct timeval rightnow; /* to initialize random seed */ 1003236769Sobrien struct utsname utsname; 1004236769Sobrien 1005236769Sobrien /* default to writing debug to stderr */ 1006236769Sobrien debug_file = stderr; 1007236769Sobrien 1008236769Sobrien#ifdef SIGINFO 1009236769Sobrien (void)bmake_signal(SIGINFO, siginfo); 1010236769Sobrien#endif 1011236769Sobrien /* 1012236769Sobrien * Set the seed to produce a different random sequence 1013236769Sobrien * on each program execution. 1014236769Sobrien */ 1015236769Sobrien gettimeofday(&rightnow, NULL); 1016236769Sobrien srandom(rightnow.tv_sec + rightnow.tv_usec); 1017236769Sobrien 1018236769Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 1019236769Sobrien progname++; 1020236769Sobrien else 1021236769Sobrien progname = argv[0]; 1022249033Ssjg#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1023236769Sobrien /* 1024236769Sobrien * get rid of resource limit on file descriptors 1025236769Sobrien */ 1026236769Sobrien { 1027236769Sobrien struct rlimit rl; 1028236769Sobrien if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1029236769Sobrien rl.rlim_cur != rl.rlim_max) { 1030236769Sobrien rl.rlim_cur = rl.rlim_max; 1031236769Sobrien (void)setrlimit(RLIMIT_NOFILE, &rl); 1032236769Sobrien } 1033236769Sobrien } 1034236769Sobrien#endif 1035236769Sobrien 1036249033Ssjg if (uname(&utsname) == -1) { 1037249033Ssjg (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1038249033Ssjg strerror(errno)); 1039249033Ssjg exit(2); 1040249033Ssjg } 1041249033Ssjg 1042236769Sobrien /* 1043236769Sobrien * Get the name of this type of MACHINE from utsname 1044236769Sobrien * so we can share an executable for similar machines. 1045236769Sobrien * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1046236769Sobrien * 1047236769Sobrien * Note that both MACHINE and MACHINE_ARCH are decided at 1048236769Sobrien * run-time. 1049236769Sobrien */ 1050236769Sobrien if (!machine) { 1051236769Sobrien#ifdef MAKE_NATIVE 1052236769Sobrien machine = utsname.machine; 1053236769Sobrien#else 1054236769Sobrien#ifdef MAKE_MACHINE 1055236769Sobrien machine = MAKE_MACHINE; 1056236769Sobrien#else 1057236769Sobrien machine = "unknown"; 1058236769Sobrien#endif 1059236769Sobrien#endif 1060236769Sobrien } 1061236769Sobrien 1062236769Sobrien if (!machine_arch) { 1063276305Sngie#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_MACHINE_ARCH) 1064276305Sngie static char machine_arch_buf[sizeof(utsname.machine)]; 1065276305Sngie int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1066276305Sngie size_t len = sizeof(machine_arch_buf); 1067276305Sngie 1068276305Sngie if (sysctl(mib, __arraycount(mib), machine_arch_buf, 1069276305Sngie &len, NULL, 0) < 0) { 1070276305Sngie (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 1071276305Sngie strerror(errno)); 1072276305Sngie exit(2); 1073276305Sngie } 1074276305Sngie 1075276305Sngie machine_arch = machine_arch_buf; 1076276305Sngie#else 1077236769Sobrien#ifndef MACHINE_ARCH 1078236769Sobrien#ifdef MAKE_MACHINE_ARCH 1079236769Sobrien machine_arch = MAKE_MACHINE_ARCH; 1080236769Sobrien#else 1081236769Sobrien machine_arch = "unknown"; 1082236769Sobrien#endif 1083236769Sobrien#else 1084236769Sobrien machine_arch = MACHINE_ARCH; 1085236769Sobrien#endif 1086276305Sngie#endif 1087236769Sobrien } 1088236769Sobrien 1089236769Sobrien myPid = getpid(); /* remember this for vFork() */ 1090236769Sobrien 1091236769Sobrien /* 1092236769Sobrien * Just in case MAKEOBJDIR wants us to do something tricky. 1093236769Sobrien */ 1094236769Sobrien Var_Init(); /* Initialize the lists of variables for 1095236769Sobrien * parsing arguments */ 1096249033Ssjg Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL, 0); 1097236769Sobrien Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 1098236769Sobrien Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 1099236769Sobrien#ifdef MAKE_VERSION 1100236769Sobrien Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 1101236769Sobrien#endif 1102236769Sobrien Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 1103236769Sobrien /* 1104236769Sobrien * This is the traditional preference for makefiles. 1105236769Sobrien */ 1106236769Sobrien#ifndef MAKEFILE_PREFERENCE_LIST 1107236769Sobrien# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1108236769Sobrien#endif 1109236769Sobrien Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1110236769Sobrien VAR_GLOBAL, 0); 1111236769Sobrien Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 1112236769Sobrien 1113236769Sobrien create = Lst_Init(FALSE); 1114236769Sobrien makefiles = Lst_Init(FALSE); 1115321964Ssjg printVars = 0; 1116240330Smarcel debugVflag = FALSE; 1117236769Sobrien variables = Lst_Init(FALSE); 1118236769Sobrien beSilent = FALSE; /* Print commands as executed */ 1119236769Sobrien ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1120236769Sobrien noExecute = FALSE; /* Execute all commands */ 1121236769Sobrien noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1122236769Sobrien keepgoing = FALSE; /* Stop on error */ 1123236769Sobrien allPrecious = FALSE; /* Remove targets when interrupted */ 1124321964Ssjg deleteOnError = FALSE; /* Historical default behavior */ 1125236769Sobrien queryFlag = FALSE; /* This is not just a check-run */ 1126236769Sobrien noBuiltins = FALSE; /* Read the built-in rules */ 1127236769Sobrien touchFlag = FALSE; /* Actually update targets */ 1128236769Sobrien debug = 0; /* No debug verbosity, please. */ 1129236769Sobrien jobsRunning = FALSE; 1130236769Sobrien 1131236769Sobrien maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1132236769Sobrien maxJobTokens = maxJobs; 1133236769Sobrien compatMake = FALSE; /* No compat mode */ 1134236769Sobrien ignorePWD = FALSE; 1135236769Sobrien 1136236769Sobrien /* 1137236769Sobrien * Initialize the parsing, directory and variable modules to prepare 1138236769Sobrien * for the reading of inclusion paths and variable settings on the 1139236769Sobrien * command line 1140236769Sobrien */ 1141236769Sobrien 1142236769Sobrien /* 1143236769Sobrien * Initialize various variables. 1144236769Sobrien * MAKE also gets this name, for compatibility 1145236769Sobrien * .MAKEFLAGS gets set to the empty string just in case. 1146236769Sobrien * MFLAGS also gets initialized empty, for compatibility. 1147236769Sobrien */ 1148236769Sobrien Parse_Init(); 1149236769Sobrien if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 1150236769Sobrien /* 1151236769Sobrien * Leave alone if it is an absolute path, or if it does 1152236769Sobrien * not contain a '/' in which case we need to find it in 1153236769Sobrien * the path, like execvp(3) and the shells do. 1154236769Sobrien */ 1155236769Sobrien p1 = argv[0]; 1156236769Sobrien } else { 1157236769Sobrien /* 1158236769Sobrien * A relative path, canonicalize it. 1159236769Sobrien */ 1160321964Ssjg p1 = cached_realpath(argv[0], mdpath); 1161236769Sobrien if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 1162236769Sobrien p1 = argv[0]; /* realpath failed */ 1163236769Sobrien } 1164236769Sobrien } 1165236769Sobrien Var_Set("MAKE", p1, VAR_GLOBAL, 0); 1166236769Sobrien Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 1167236769Sobrien Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 1168236769Sobrien Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 1169236769Sobrien Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 1170236769Sobrien Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 1171253883Ssjg /* some makefiles need to know this */ 1172253883Ssjg Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD, 0); 1173236769Sobrien 1174236769Sobrien /* 1175236769Sobrien * Set some other useful macros 1176236769Sobrien */ 1177236769Sobrien { 1178253883Ssjg char tmp[64], *ep; 1179236769Sobrien 1180253883Ssjg makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1181253883Ssjg if (makelevel < 0) 1182253883Ssjg makelevel = 0; 1183253883Ssjg snprintf(tmp, sizeof(tmp), "%d", makelevel); 1184253883Ssjg Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL, 0); 1185236769Sobrien snprintf(tmp, sizeof(tmp), "%u", myPid); 1186236769Sobrien Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 1187236769Sobrien snprintf(tmp, sizeof(tmp), "%u", getppid()); 1188236769Sobrien Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 1189236769Sobrien } 1190253883Ssjg if (makelevel > 0) { 1191253883Ssjg char pn[1024]; 1192253883Ssjg snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1193253883Ssjg progname = bmake_strdup(pn); 1194253883Ssjg } 1195236769Sobrien 1196249033Ssjg#ifdef USE_META 1197249033Ssjg meta_init(); 1198249033Ssjg#endif 1199321964Ssjg Dir_Init(NULL); /* Dir_* safe to call from MainParseArgs */ 1200321964Ssjg 1201236769Sobrien /* 1202236769Sobrien * First snag any flags out of the MAKE environment variable. 1203236769Sobrien * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1204236769Sobrien * in a different format). 1205236769Sobrien */ 1206236769Sobrien#ifdef POSIX 1207253883Ssjg p1 = explode(getenv("MAKEFLAGS")); 1208253883Ssjg Main_ParseArgLine(p1); 1209253883Ssjg free(p1); 1210236769Sobrien#else 1211236769Sobrien Main_ParseArgLine(getenv("MAKE")); 1212236769Sobrien#endif 1213236769Sobrien 1214236769Sobrien /* 1215236769Sobrien * Find where we are (now). 1216236769Sobrien * We take care of PWD for the automounter below... 1217236769Sobrien */ 1218236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 1219236769Sobrien (void)fprintf(stderr, "%s: getcwd: %s.\n", 1220236769Sobrien progname, strerror(errno)); 1221236769Sobrien exit(2); 1222236769Sobrien } 1223236769Sobrien 1224236769Sobrien MainParseArgs(argc, argv); 1225236769Sobrien 1226253883Ssjg if (enterFlag) 1227253883Ssjg printf("%s: Entering directory `%s'\n", progname, curdir); 1228253883Ssjg 1229236769Sobrien /* 1230236769Sobrien * Verify that cwd is sane. 1231236769Sobrien */ 1232236769Sobrien if (stat(curdir, &sa) == -1) { 1233236769Sobrien (void)fprintf(stderr, "%s: %s: %s.\n", 1234236769Sobrien progname, curdir, strerror(errno)); 1235236769Sobrien exit(2); 1236236769Sobrien } 1237236769Sobrien 1238236769Sobrien /* 1239236769Sobrien * All this code is so that we know where we are when we start up 1240236769Sobrien * on a different machine with pmake. 1241236769Sobrien * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1242236769Sobrien * since the value of curdir can vary depending on how we got 1243236769Sobrien * here. Ie sitting at a shell prompt (shell that provides $PWD) 1244236769Sobrien * or via subdir.mk in which case its likely a shell which does 1245236769Sobrien * not provide it. 1246236769Sobrien * So, to stop it breaking this case only, we ignore PWD if 1247236769Sobrien * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 1248236769Sobrien */ 1249236769Sobrien#ifndef NO_PWD_OVERRIDE 1250253883Ssjg if (!ignorePWD) { 1251276305Sngie char *pwd, *ptmp1 = NULL, *ptmp2 = NULL; 1252236769Sobrien 1253253883Ssjg if ((pwd = getenv("PWD")) != NULL && 1254276305Sngie Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &ptmp1) == NULL) { 1255276305Sngie const char *makeobjdir = Var_Value("MAKEOBJDIR", 1256276305Sngie VAR_CMD, &ptmp2); 1257253883Ssjg 1258253883Ssjg if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 1259253883Ssjg if (stat(pwd, &sb) == 0 && 1260253883Ssjg sa.st_ino == sb.st_ino && 1261253883Ssjg sa.st_dev == sb.st_dev) 1262253883Ssjg (void)strncpy(curdir, pwd, MAXPATHLEN); 1263253883Ssjg } 1264236769Sobrien } 1265276305Sngie free(ptmp1); 1266276305Sngie free(ptmp2); 1267236769Sobrien } 1268236769Sobrien#endif 1269236769Sobrien Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 1270236769Sobrien 1271236769Sobrien /* 1272236769Sobrien * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1273236769Sobrien * MAKEOBJDIR is set in the environment, try only that value 1274236769Sobrien * and fall back to .CURDIR if it does not exist. 1275236769Sobrien * 1276321964Ssjg * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1277321964Ssjg * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1278236769Sobrien * of these paths exist, just use .CURDIR. 1279236769Sobrien */ 1280236769Sobrien Dir_Init(curdir); 1281321964Ssjg (void)Main_SetObjdir("%s", curdir); 1282236769Sobrien 1283321964Ssjg if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1284321964Ssjg !Main_SetVarObjdir("MAKEOBJDIR", "") && 1285321964Ssjg !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1286321964Ssjg !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1287321964Ssjg !Main_SetObjdir("%s", _PATH_OBJDIR)) 1288321964Ssjg (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1289236769Sobrien 1290236769Sobrien /* 1291236769Sobrien * Initialize archive, target and suffix modules in preparation for 1292236769Sobrien * parsing the makefile(s) 1293236769Sobrien */ 1294236769Sobrien Arch_Init(); 1295236769Sobrien Targ_Init(); 1296236769Sobrien Suff_Init(); 1297236769Sobrien Trace_Init(tracefile); 1298236769Sobrien 1299236769Sobrien DEFAULT = NULL; 1300236769Sobrien (void)time(&now); 1301236769Sobrien 1302236769Sobrien Trace_Log(MAKESTART, NULL); 1303236769Sobrien 1304236769Sobrien /* 1305236769Sobrien * Set up the .TARGETS variable to contain the list of targets to be 1306236769Sobrien * created. If none specified, make the variable empty -- the parser 1307236769Sobrien * will fill the thing in with the default or .MAIN target. 1308236769Sobrien */ 1309236769Sobrien if (!Lst_IsEmpty(create)) { 1310236769Sobrien LstNode ln; 1311236769Sobrien 1312236769Sobrien for (ln = Lst_First(create); ln != NULL; 1313236769Sobrien ln = Lst_Succ(ln)) { 1314236769Sobrien char *name = (char *)Lst_Datum(ln); 1315236769Sobrien 1316236769Sobrien Var_Append(".TARGETS", name, VAR_GLOBAL); 1317236769Sobrien } 1318236769Sobrien } else 1319236769Sobrien Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 1320236769Sobrien 1321236769Sobrien 1322236769Sobrien /* 1323236769Sobrien * If no user-supplied system path was given (through the -m option) 1324236769Sobrien * add the directories from the DEFSYSPATH (more than one may be given 1325236769Sobrien * as dir1:...:dirn) to the system include path. 1326236769Sobrien */ 1327236769Sobrien if (syspath == NULL || *syspath == '\0') 1328236769Sobrien syspath = defsyspath; 1329236769Sobrien else 1330236769Sobrien syspath = bmake_strdup(syspath); 1331236769Sobrien 1332236769Sobrien for (start = syspath; *start != '\0'; start = cp) { 1333236769Sobrien for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1334236769Sobrien continue; 1335236769Sobrien if (*cp == ':') { 1336236769Sobrien *cp++ = '\0'; 1337236769Sobrien } 1338236769Sobrien /* look for magic parent directory search string */ 1339236769Sobrien if (strncmp(".../", start, 4) != 0) { 1340236769Sobrien (void)Dir_AddDir(defIncPath, start); 1341236769Sobrien } else { 1342236769Sobrien if (Dir_FindHereOrAbove(curdir, start+4, 1343236769Sobrien found_path, sizeof(found_path))) { 1344236769Sobrien (void)Dir_AddDir(defIncPath, found_path); 1345236769Sobrien } 1346236769Sobrien } 1347236769Sobrien } 1348236769Sobrien if (syspath != defsyspath) 1349236769Sobrien free(syspath); 1350236769Sobrien 1351236769Sobrien /* 1352236769Sobrien * Read in the built-in rules first, followed by the specified 1353236769Sobrien * makefile, if it was (makefile != NULL), or the default 1354236769Sobrien * makefile and Makefile, in that order, if it wasn't. 1355236769Sobrien */ 1356236769Sobrien if (!noBuiltins) { 1357236769Sobrien LstNode ln; 1358236769Sobrien 1359236769Sobrien sysMkPath = Lst_Init(FALSE); 1360236769Sobrien Dir_Expand(_PATH_DEFSYSMK, 1361236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1362236769Sobrien sysMkPath); 1363236769Sobrien if (Lst_IsEmpty(sysMkPath)) 1364236769Sobrien Fatal("%s: no system rules (%s).", progname, 1365236769Sobrien _PATH_DEFSYSMK); 1366236769Sobrien ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 1367236769Sobrien if (ln == NULL) 1368236769Sobrien Fatal("%s: cannot open %s.", progname, 1369236769Sobrien (char *)Lst_Datum(ln)); 1370236769Sobrien } 1371236769Sobrien 1372236769Sobrien if (!Lst_IsEmpty(makefiles)) { 1373236769Sobrien LstNode ln; 1374236769Sobrien 1375236769Sobrien ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 1376236769Sobrien if (ln != NULL) 1377236769Sobrien Fatal("%s: cannot open %s.", progname, 1378236769Sobrien (char *)Lst_Datum(ln)); 1379236769Sobrien } else { 1380236769Sobrien p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 1381321964Ssjg VAR_CMD, VARF_WANTRES); 1382236769Sobrien if (p1) { 1383236769Sobrien (void)str2Lst_Append(makefiles, p1, NULL); 1384236769Sobrien (void)Lst_Find(makefiles, NULL, ReadMakefile); 1385236769Sobrien free(p1); 1386236769Sobrien } 1387236769Sobrien } 1388236769Sobrien 1389236769Sobrien /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1390236769Sobrien if (!noBuiltins || !printVars) { 1391236769Sobrien makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 1392321964Ssjg VAR_CMD, VARF_WANTRES); 1393236769Sobrien doing_depend = TRUE; 1394236769Sobrien (void)ReadMakefile(makeDependfile, NULL); 1395236769Sobrien doing_depend = FALSE; 1396236769Sobrien } 1397236769Sobrien 1398292068Ssjg if (enterFlagObj) 1399292068Ssjg printf("%s: Entering directory `%s'\n", progname, objdir); 1400292068Ssjg 1401236769Sobrien MakeMode(NULL); 1402236769Sobrien 1403236769Sobrien Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1404321964Ssjg free(p1); 1405236769Sobrien 1406321964Ssjg if (!forceJobs && !compatMake && 1407321964Ssjg Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) { 1408321964Ssjg char *value; 1409321964Ssjg int n; 1410321964Ssjg 1411321964Ssjg value = Var_Subst(NULL, "${.MAKE.JOBS}", VAR_GLOBAL, VARF_WANTRES); 1412321964Ssjg n = strtol(value, NULL, 0); 1413321964Ssjg if (n < 1) { 1414321964Ssjg (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n", 1415321964Ssjg progname); 1416321964Ssjg exit(1); 1417321964Ssjg } 1418321964Ssjg if (n != maxJobs) { 1419321964Ssjg Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1420321964Ssjg Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1421321964Ssjg } 1422321964Ssjg maxJobs = n; 1423321964Ssjg maxJobTokens = maxJobs; 1424321964Ssjg forceJobs = TRUE; 1425321964Ssjg free(value); 1426321964Ssjg } 1427321964Ssjg 1428321964Ssjg /* 1429321964Ssjg * Be compatible if user did not specify -j and did not explicitly 1430321964Ssjg * turned compatibility on 1431321964Ssjg */ 1432321964Ssjg if (!compatMake && !forceJobs) { 1433321964Ssjg compatMake = TRUE; 1434321964Ssjg } 1435321964Ssjg 1436236769Sobrien if (!compatMake) 1437236769Sobrien Job_ServerStart(maxJobTokens, jp_0, jp_1); 1438236769Sobrien if (DEBUG(JOB)) 1439236769Sobrien fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1440236769Sobrien jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 1441236769Sobrien 1442321964Ssjg if (!printVars) 1443321964Ssjg Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1444321964Ssjg 1445236769Sobrien /* 1446236769Sobrien * For compatibility, look at the directories in the VPATH variable 1447236769Sobrien * and add them to the search path, if the variable is defined. The 1448236769Sobrien * variable's value is in the same format as the PATH envariable, i.e. 1449236769Sobrien * <directory>:<directory>:<directory>... 1450236769Sobrien */ 1451236769Sobrien if (Var_Exists("VPATH", VAR_CMD)) { 1452236769Sobrien char *vpath, savec; 1453236769Sobrien /* 1454236769Sobrien * GCC stores string constants in read-only memory, but 1455236769Sobrien * Var_Subst will want to write this thing, so store it 1456236769Sobrien * in an array 1457236769Sobrien */ 1458236769Sobrien static char VPATH[] = "${VPATH}"; 1459236769Sobrien 1460321964Ssjg vpath = Var_Subst(NULL, VPATH, VAR_CMD, VARF_WANTRES); 1461236769Sobrien path = vpath; 1462236769Sobrien do { 1463236769Sobrien /* skip to end of directory */ 1464236769Sobrien for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1465236769Sobrien continue; 1466236769Sobrien /* Save terminator character so know when to stop */ 1467236769Sobrien savec = *cp; 1468236769Sobrien *cp = '\0'; 1469236769Sobrien /* Add directory to search path */ 1470236769Sobrien (void)Dir_AddDir(dirSearchPath, path); 1471236769Sobrien *cp = savec; 1472236769Sobrien path = cp + 1; 1473236769Sobrien } while (savec == ':'); 1474236769Sobrien free(vpath); 1475236769Sobrien } 1476236769Sobrien 1477236769Sobrien /* 1478236769Sobrien * Now that all search paths have been read for suffixes et al, it's 1479236769Sobrien * time to add the default search path to their lists... 1480236769Sobrien */ 1481236769Sobrien Suff_DoPaths(); 1482236769Sobrien 1483236769Sobrien /* 1484236769Sobrien * Propagate attributes through :: dependency lists. 1485236769Sobrien */ 1486236769Sobrien Targ_Propagate(); 1487236769Sobrien 1488236769Sobrien /* print the initial graph, if the user requested it */ 1489236769Sobrien if (DEBUG(GRAPH1)) 1490236769Sobrien Targ_PrintGraph(1); 1491236769Sobrien 1492236769Sobrien /* print the values of any variables requested by the user */ 1493236769Sobrien if (printVars) { 1494321964Ssjg doPrintVars(); 1495321964Ssjg outOfDate = FALSE; 1496236769Sobrien } else { 1497321964Ssjg outOfDate = runTargets(); 1498236769Sobrien } 1499236769Sobrien 1500236769Sobrien#ifdef CLEANUP 1501236769Sobrien Lst_Destroy(variables, NULL); 1502236769Sobrien Lst_Destroy(makefiles, NULL); 1503236769Sobrien Lst_Destroy(create, (FreeProc *)free); 1504236769Sobrien#endif 1505236769Sobrien 1506236769Sobrien /* print the graph now it's been processed if the user requested it */ 1507236769Sobrien if (DEBUG(GRAPH2)) 1508236769Sobrien Targ_PrintGraph(2); 1509236769Sobrien 1510236769Sobrien Trace_Log(MAKEEND, 0); 1511236769Sobrien 1512292068Ssjg if (enterFlagObj) 1513292068Ssjg printf("%s: Leaving directory `%s'\n", progname, objdir); 1514253883Ssjg if (enterFlag) 1515253883Ssjg printf("%s: Leaving directory `%s'\n", progname, curdir); 1516253883Ssjg 1517321964Ssjg#ifdef USE_META 1518321964Ssjg meta_finish(); 1519321964Ssjg#endif 1520236769Sobrien Suff_End(); 1521236769Sobrien Targ_End(); 1522236769Sobrien Arch_End(); 1523236769Sobrien Var_End(); 1524236769Sobrien Parse_End(); 1525236769Sobrien Dir_End(); 1526236769Sobrien Job_End(); 1527236769Sobrien Trace_End(); 1528236769Sobrien 1529236769Sobrien return outOfDate ? 1 : 0; 1530236769Sobrien} 1531236769Sobrien 1532236769Sobrien/*- 1533236769Sobrien * ReadMakefile -- 1534236769Sobrien * Open and parse the given makefile. 1535236769Sobrien * 1536236769Sobrien * Results: 1537236769Sobrien * 0 if ok. -1 if couldn't open file. 1538236769Sobrien * 1539236769Sobrien * Side Effects: 1540236769Sobrien * lots 1541236769Sobrien */ 1542236769Sobrienstatic int 1543237578SobrienReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 1544236769Sobrien{ 1545236769Sobrien const char *fname = p; /* makefile to read */ 1546236769Sobrien int fd; 1547236769Sobrien size_t len = MAXPATHLEN; 1548236769Sobrien char *name, *path = bmake_malloc(len); 1549236769Sobrien 1550236769Sobrien if (!strcmp(fname, "-")) { 1551236769Sobrien Parse_File(NULL /*stdin*/, -1); 1552255253Ssjg Var_Set("MAKEFILE", "", VAR_INTERNAL, 0); 1553236769Sobrien } else { 1554236769Sobrien /* if we've chdir'd, rebuild the path name */ 1555236769Sobrien if (strcmp(curdir, objdir) && *fname != '/') { 1556236769Sobrien size_t plen = strlen(curdir) + strlen(fname) + 2; 1557236769Sobrien if (len < plen) 1558236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1559236769Sobrien 1560236769Sobrien (void)snprintf(path, len, "%s/%s", curdir, fname); 1561236769Sobrien fd = open(path, O_RDONLY); 1562236769Sobrien if (fd != -1) { 1563236769Sobrien fname = path; 1564236769Sobrien goto found; 1565236769Sobrien } 1566236769Sobrien 1567236769Sobrien /* If curdir failed, try objdir (ala .depend) */ 1568236769Sobrien plen = strlen(objdir) + strlen(fname) + 2; 1569236769Sobrien if (len < plen) 1570236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1571236769Sobrien (void)snprintf(path, len, "%s/%s", objdir, fname); 1572236769Sobrien fd = open(path, O_RDONLY); 1573236769Sobrien if (fd != -1) { 1574236769Sobrien fname = path; 1575236769Sobrien goto found; 1576236769Sobrien } 1577236769Sobrien } else { 1578236769Sobrien fd = open(fname, O_RDONLY); 1579236769Sobrien if (fd != -1) 1580236769Sobrien goto found; 1581236769Sobrien } 1582236769Sobrien /* look in -I and system include directories. */ 1583236769Sobrien name = Dir_FindFile(fname, parseIncPath); 1584236769Sobrien if (!name) 1585236769Sobrien name = Dir_FindFile(fname, 1586236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1587236769Sobrien if (!name || (fd = open(name, O_RDONLY)) == -1) { 1588321964Ssjg free(name); 1589236769Sobrien free(path); 1590236769Sobrien return(-1); 1591236769Sobrien } 1592236769Sobrien fname = name; 1593236769Sobrien /* 1594236769Sobrien * set the MAKEFILE variable desired by System V fans -- the 1595236769Sobrien * placement of the setting here means it gets set to the last 1596236769Sobrien * makefile specified, as it is set by SysV make. 1597236769Sobrien */ 1598236769Sobrienfound: 1599236769Sobrien if (!doing_depend) 1600255253Ssjg Var_Set("MAKEFILE", fname, VAR_INTERNAL, 0); 1601236769Sobrien Parse_File(fname, fd); 1602236769Sobrien } 1603236769Sobrien free(path); 1604236769Sobrien return(0); 1605236769Sobrien} 1606236769Sobrien 1607236769Sobrien 1608236769Sobrien 1609236769Sobrien/*- 1610236769Sobrien * Cmd_Exec -- 1611236769Sobrien * Execute the command in cmd, and return the output of that command 1612236769Sobrien * in a string. 1613236769Sobrien * 1614236769Sobrien * Results: 1615236769Sobrien * A string containing the output of the command, or the empty string 1616236769Sobrien * If errnum is not NULL, it contains the reason for the command failure 1617236769Sobrien * 1618236769Sobrien * Side Effects: 1619236769Sobrien * The string must be freed by the caller. 1620236769Sobrien */ 1621236769Sobrienchar * 1622236769SobrienCmd_Exec(const char *cmd, const char **errnum) 1623236769Sobrien{ 1624236769Sobrien const char *args[4]; /* Args for invoking the shell */ 1625236769Sobrien int fds[2]; /* Pipe streams */ 1626236769Sobrien int cpid; /* Child PID */ 1627236769Sobrien int pid; /* PID from wait() */ 1628236769Sobrien char *res; /* result */ 1629236769Sobrien WAIT_T status; /* command exit status */ 1630236769Sobrien Buffer buf; /* buffer to store the result */ 1631236769Sobrien char *cp; 1632292068Ssjg int cc; /* bytes read, or -1 */ 1633292068Ssjg int savederr; /* saved errno */ 1634236769Sobrien 1635236769Sobrien 1636236769Sobrien *errnum = NULL; 1637236769Sobrien 1638236769Sobrien if (!shellName) 1639236769Sobrien Shell_Init(); 1640236769Sobrien /* 1641236769Sobrien * Set up arguments for shell 1642236769Sobrien */ 1643236769Sobrien args[0] = shellName; 1644236769Sobrien args[1] = "-c"; 1645236769Sobrien args[2] = cmd; 1646236769Sobrien args[3] = NULL; 1647236769Sobrien 1648236769Sobrien /* 1649236769Sobrien * Open a pipe for fetching its output 1650236769Sobrien */ 1651236769Sobrien if (pipe(fds) == -1) { 1652236769Sobrien *errnum = "Couldn't create pipe for \"%s\""; 1653236769Sobrien goto bad; 1654236769Sobrien } 1655236769Sobrien 1656236769Sobrien /* 1657236769Sobrien * Fork 1658236769Sobrien */ 1659236769Sobrien switch (cpid = vFork()) { 1660236769Sobrien case 0: 1661236769Sobrien /* 1662236769Sobrien * Close input side of pipe 1663236769Sobrien */ 1664236769Sobrien (void)close(fds[0]); 1665236769Sobrien 1666236769Sobrien /* 1667236769Sobrien * Duplicate the output stream to the shell's output, then 1668236769Sobrien * shut the extra thing down. Note we don't fetch the error 1669236769Sobrien * stream...why not? Why? 1670236769Sobrien */ 1671236769Sobrien (void)dup2(fds[1], 1); 1672236769Sobrien (void)close(fds[1]); 1673236769Sobrien 1674236769Sobrien Var_ExportVars(); 1675236769Sobrien 1676236769Sobrien (void)execv(shellPath, UNCONST(args)); 1677236769Sobrien _exit(1); 1678236769Sobrien /*NOTREACHED*/ 1679236769Sobrien 1680236769Sobrien case -1: 1681236769Sobrien *errnum = "Couldn't exec \"%s\""; 1682236769Sobrien goto bad; 1683236769Sobrien 1684236769Sobrien default: 1685236769Sobrien /* 1686236769Sobrien * No need for the writing half 1687236769Sobrien */ 1688236769Sobrien (void)close(fds[1]); 1689236769Sobrien 1690292068Ssjg savederr = 0; 1691236769Sobrien Buf_Init(&buf, 0); 1692236769Sobrien 1693236769Sobrien do { 1694236769Sobrien char result[BUFSIZ]; 1695236769Sobrien cc = read(fds[0], result, sizeof(result)); 1696236769Sobrien if (cc > 0) 1697236769Sobrien Buf_AddBytes(&buf, cc, result); 1698236769Sobrien } 1699236769Sobrien while (cc > 0 || (cc == -1 && errno == EINTR)); 1700292068Ssjg if (cc == -1) 1701292068Ssjg savederr = errno; 1702236769Sobrien 1703236769Sobrien /* 1704236769Sobrien * Close the input side of the pipe. 1705236769Sobrien */ 1706236769Sobrien (void)close(fds[0]); 1707236769Sobrien 1708236769Sobrien /* 1709236769Sobrien * Wait for the process to exit. 1710236769Sobrien */ 1711236769Sobrien while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1712236769Sobrien JobReapChild(pid, status, FALSE); 1713236769Sobrien continue; 1714236769Sobrien } 1715236769Sobrien cc = Buf_Size(&buf); 1716236769Sobrien res = Buf_Destroy(&buf, FALSE); 1717236769Sobrien 1718292068Ssjg if (savederr != 0) 1719236769Sobrien *errnum = "Couldn't read shell's output for \"%s\""; 1720236769Sobrien 1721236769Sobrien if (WIFSIGNALED(status)) 1722236769Sobrien *errnum = "\"%s\" exited on a signal"; 1723236769Sobrien else if (WEXITSTATUS(status) != 0) 1724236769Sobrien *errnum = "\"%s\" returned non-zero status"; 1725236769Sobrien 1726236769Sobrien /* 1727236769Sobrien * Null-terminate the result, convert newlines to spaces and 1728236769Sobrien * install it in the variable. 1729236769Sobrien */ 1730236769Sobrien res[cc] = '\0'; 1731236769Sobrien cp = &res[cc]; 1732236769Sobrien 1733236769Sobrien if (cc > 0 && *--cp == '\n') { 1734236769Sobrien /* 1735236769Sobrien * A final newline is just stripped 1736236769Sobrien */ 1737236769Sobrien *cp-- = '\0'; 1738236769Sobrien } 1739236769Sobrien while (cp >= res) { 1740236769Sobrien if (*cp == '\n') { 1741236769Sobrien *cp = ' '; 1742236769Sobrien } 1743236769Sobrien cp--; 1744236769Sobrien } 1745236769Sobrien break; 1746236769Sobrien } 1747236769Sobrien return res; 1748236769Sobrienbad: 1749236769Sobrien res = bmake_malloc(1); 1750236769Sobrien *res = '\0'; 1751236769Sobrien return res; 1752236769Sobrien} 1753236769Sobrien 1754236769Sobrien/*- 1755236769Sobrien * Error -- 1756236769Sobrien * Print an error message given its format. 1757236769Sobrien * 1758236769Sobrien * Results: 1759236769Sobrien * None. 1760236769Sobrien * 1761236769Sobrien * Side Effects: 1762236769Sobrien * The message is printed. 1763236769Sobrien */ 1764236769Sobrien/* VARARGS */ 1765236769Sobrienvoid 1766236769SobrienError(const char *fmt, ...) 1767236769Sobrien{ 1768236769Sobrien va_list ap; 1769236769Sobrien FILE *err_file; 1770236769Sobrien 1771236769Sobrien err_file = debug_file; 1772236769Sobrien if (err_file == stdout) 1773236769Sobrien err_file = stderr; 1774236769Sobrien (void)fflush(stdout); 1775236769Sobrien for (;;) { 1776236769Sobrien va_start(ap, fmt); 1777236769Sobrien fprintf(err_file, "%s: ", progname); 1778236769Sobrien (void)vfprintf(err_file, fmt, ap); 1779236769Sobrien va_end(ap); 1780236769Sobrien (void)fprintf(err_file, "\n"); 1781236769Sobrien (void)fflush(err_file); 1782236769Sobrien if (err_file == stderr) 1783236769Sobrien break; 1784236769Sobrien err_file = stderr; 1785236769Sobrien } 1786236769Sobrien} 1787236769Sobrien 1788236769Sobrien/*- 1789236769Sobrien * Fatal -- 1790236769Sobrien * Produce a Fatal error message. If jobs are running, waits for them 1791236769Sobrien * to finish. 1792236769Sobrien * 1793236769Sobrien * Results: 1794236769Sobrien * None 1795236769Sobrien * 1796236769Sobrien * Side Effects: 1797236769Sobrien * The program exits 1798236769Sobrien */ 1799236769Sobrien/* VARARGS */ 1800236769Sobrienvoid 1801236769SobrienFatal(const char *fmt, ...) 1802236769Sobrien{ 1803236769Sobrien va_list ap; 1804236769Sobrien 1805236769Sobrien va_start(ap, fmt); 1806236769Sobrien if (jobsRunning) 1807236769Sobrien Job_Wait(); 1808236769Sobrien 1809236769Sobrien (void)fflush(stdout); 1810236769Sobrien (void)vfprintf(stderr, fmt, ap); 1811236769Sobrien va_end(ap); 1812236769Sobrien (void)fprintf(stderr, "\n"); 1813236769Sobrien (void)fflush(stderr); 1814236769Sobrien 1815236769Sobrien PrintOnError(NULL, NULL); 1816236769Sobrien 1817236769Sobrien if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1818236769Sobrien Targ_PrintGraph(2); 1819236769Sobrien Trace_Log(MAKEERROR, 0); 1820236769Sobrien exit(2); /* Not 1 so -q can distinguish error */ 1821236769Sobrien} 1822236769Sobrien 1823236769Sobrien/* 1824236769Sobrien * Punt -- 1825236769Sobrien * Major exception once jobs are being created. Kills all jobs, prints 1826236769Sobrien * a message and exits. 1827236769Sobrien * 1828236769Sobrien * Results: 1829236769Sobrien * None 1830236769Sobrien * 1831236769Sobrien * Side Effects: 1832236769Sobrien * All children are killed indiscriminately and the program Lib_Exits 1833236769Sobrien */ 1834236769Sobrien/* VARARGS */ 1835236769Sobrienvoid 1836236769SobrienPunt(const char *fmt, ...) 1837236769Sobrien{ 1838236769Sobrien va_list ap; 1839236769Sobrien 1840236769Sobrien va_start(ap, fmt); 1841236769Sobrien (void)fflush(stdout); 1842236769Sobrien (void)fprintf(stderr, "%s: ", progname); 1843236769Sobrien (void)vfprintf(stderr, fmt, ap); 1844236769Sobrien va_end(ap); 1845236769Sobrien (void)fprintf(stderr, "\n"); 1846236769Sobrien (void)fflush(stderr); 1847236769Sobrien 1848236769Sobrien PrintOnError(NULL, NULL); 1849236769Sobrien 1850236769Sobrien DieHorribly(); 1851236769Sobrien} 1852236769Sobrien 1853236769Sobrien/*- 1854236769Sobrien * DieHorribly -- 1855236769Sobrien * Exit without giving a message. 1856236769Sobrien * 1857236769Sobrien * Results: 1858236769Sobrien * None 1859236769Sobrien * 1860236769Sobrien * Side Effects: 1861236769Sobrien * A big one... 1862236769Sobrien */ 1863236769Sobrienvoid 1864236769SobrienDieHorribly(void) 1865236769Sobrien{ 1866236769Sobrien if (jobsRunning) 1867236769Sobrien Job_AbortAll(); 1868236769Sobrien if (DEBUG(GRAPH2)) 1869236769Sobrien Targ_PrintGraph(2); 1870236769Sobrien Trace_Log(MAKEERROR, 0); 1871236769Sobrien exit(2); /* Not 1, so -q can distinguish error */ 1872236769Sobrien} 1873236769Sobrien 1874236769Sobrien/* 1875236769Sobrien * Finish -- 1876236769Sobrien * Called when aborting due to errors in child shell to signal 1877236769Sobrien * abnormal exit. 1878236769Sobrien * 1879236769Sobrien * Results: 1880236769Sobrien * None 1881236769Sobrien * 1882236769Sobrien * Side Effects: 1883236769Sobrien * The program exits 1884236769Sobrien */ 1885236769Sobrienvoid 1886236769SobrienFinish(int errors) 1887236769Sobrien /* number of errors encountered in Make_Make */ 1888236769Sobrien{ 1889236769Sobrien Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1890236769Sobrien} 1891236769Sobrien 1892236769Sobrien/* 1893249033Ssjg * eunlink -- 1894236769Sobrien * Remove a file carefully, avoiding directories. 1895236769Sobrien */ 1896236769Sobrienint 1897236769Sobrieneunlink(const char *file) 1898236769Sobrien{ 1899236769Sobrien struct stat st; 1900236769Sobrien 1901236769Sobrien if (lstat(file, &st) == -1) 1902236769Sobrien return -1; 1903236769Sobrien 1904236769Sobrien if (S_ISDIR(st.st_mode)) { 1905236769Sobrien errno = EISDIR; 1906236769Sobrien return -1; 1907236769Sobrien } 1908236769Sobrien return unlink(file); 1909236769Sobrien} 1910236769Sobrien 1911236769Sobrien/* 1912236769Sobrien * execError -- 1913236769Sobrien * Print why exec failed, avoiding stdio. 1914236769Sobrien */ 1915236769Sobrienvoid 1916236769SobrienexecError(const char *af, const char *av) 1917236769Sobrien{ 1918236769Sobrien#ifdef USE_IOVEC 1919236769Sobrien int i = 0; 1920236769Sobrien struct iovec iov[8]; 1921236769Sobrien#define IOADD(s) \ 1922236769Sobrien (void)(iov[i].iov_base = UNCONST(s), \ 1923236769Sobrien iov[i].iov_len = strlen(iov[i].iov_base), \ 1924236769Sobrien i++) 1925236769Sobrien#else 1926236769Sobrien#define IOADD(s) (void)write(2, s, strlen(s)) 1927236769Sobrien#endif 1928236769Sobrien 1929236769Sobrien IOADD(progname); 1930236769Sobrien IOADD(": "); 1931236769Sobrien IOADD(af); 1932236769Sobrien IOADD("("); 1933236769Sobrien IOADD(av); 1934236769Sobrien IOADD(") failed ("); 1935236769Sobrien IOADD(strerror(errno)); 1936236769Sobrien IOADD(")\n"); 1937236769Sobrien 1938236769Sobrien#ifdef USE_IOVEC 1939246223Ssjg while (writev(2, iov, 8) == -1 && errno == EAGAIN) 1940246223Ssjg continue; 1941236769Sobrien#endif 1942236769Sobrien} 1943236769Sobrien 1944236769Sobrien/* 1945236769Sobrien * usage -- 1946236769Sobrien * exit with usage message 1947236769Sobrien */ 1948236769Sobrienstatic void 1949236769Sobrienusage(void) 1950236769Sobrien{ 1951253883Ssjg char *p; 1952253883Ssjg if ((p = strchr(progname, '[')) != NULL) 1953253883Ssjg *p = '\0'; 1954253883Ssjg 1955236769Sobrien (void)fprintf(stderr, 1956253883Ssjg"usage: %s [-BeikNnqrstWwX] \n\ 1957236769Sobrien [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 1958236769Sobrien [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1959321964Ssjg [-V variable] [-v variable] [variable=value] [target ...]\n", 1960321964Ssjg progname); 1961236769Sobrien exit(2); 1962236769Sobrien} 1963236769Sobrien 1964321964Ssjg/* 1965321964Ssjg * realpath(3) can get expensive, cache results... 1966321964Ssjg */ 1967321964Ssjgstatic GNode *cached_realpaths = NULL; 1968236769Sobrien 1969321964Ssjgstatic GNode * 1970321964Ssjgget_cached_realpaths(void) 1971321964Ssjg{ 1972321964Ssjg 1973321964Ssjg if (!cached_realpaths) { 1974321964Ssjg cached_realpaths = Targ_NewGN("Realpath"); 1975321964Ssjg#ifndef DEBUG_REALPATH_CACHE 1976321964Ssjg cached_realpaths->flags = INTERNAL; 1977321964Ssjg#endif 1978321964Ssjg } 1979321964Ssjg 1980321964Ssjg return cached_realpaths; 1981321964Ssjg} 1982321964Ssjg 1983321964Ssjg/* purge any relative paths */ 1984321964Ssjgstatic void 1985321964Ssjgpurge_cached_realpaths(void) 1986321964Ssjg{ 1987321964Ssjg GNode *cache = get_cached_realpaths(); 1988321964Ssjg Hash_Entry *he, *nhe; 1989321964Ssjg Hash_Search hs; 1990321964Ssjg 1991321964Ssjg he = Hash_EnumFirst(&cache->context, &hs); 1992321964Ssjg while (he) { 1993321964Ssjg nhe = Hash_EnumNext(&hs); 1994321964Ssjg if (he->name[0] != '/') { 1995321964Ssjg if (DEBUG(DIR)) 1996321964Ssjg fprintf(stderr, "cached_realpath: purging %s\n", he->name); 1997321964Ssjg Hash_DeleteEntry(&cache->context, he); 1998321964Ssjg } 1999321964Ssjg he = nhe; 2000321964Ssjg } 2001321964Ssjg} 2002321964Ssjg 2003321964Ssjgchar * 2004321964Ssjgcached_realpath(const char *pathname, char *resolved) 2005321964Ssjg{ 2006321964Ssjg GNode *cache; 2007321964Ssjg char *rp, *cp; 2008321964Ssjg 2009321964Ssjg if (!pathname || !pathname[0]) 2010321964Ssjg return NULL; 2011321964Ssjg 2012321964Ssjg cache = get_cached_realpaths(); 2013321964Ssjg 2014321964Ssjg if ((rp = Var_Value(pathname, cache, &cp)) != NULL) { 2015321964Ssjg /* a hit */ 2016321964Ssjg strlcpy(resolved, rp, MAXPATHLEN); 2017321964Ssjg } else if ((rp = realpath(pathname, resolved)) != NULL) { 2018321964Ssjg Var_Set(pathname, rp, cache, 0); 2019321964Ssjg } 2020321964Ssjg free(cp); 2021321964Ssjg return rp ? resolved : NULL; 2022321964Ssjg} 2023321964Ssjg 2024236769Sobrienint 2025236769SobrienPrintAddr(void *a, void *b) 2026236769Sobrien{ 2027236769Sobrien printf("%lx ", (unsigned long) a); 2028236769Sobrien return b ? 0 : 0; 2029236769Sobrien} 2030236769Sobrien 2031236769Sobrien 2032321964Ssjgstatic int 2033321964SsjgaddErrorCMD(void *cmdp, void *gnp MAKE_ATTR_UNUSED) 2034321964Ssjg{ 2035321964Ssjg if (cmdp == NULL) 2036321964Ssjg return 1; /* stop */ 2037321964Ssjg Var_Append(".ERROR_CMD", cmdp, VAR_GLOBAL); 2038321964Ssjg return 0; 2039321964Ssjg} 2040236769Sobrien 2041236769Sobrienvoid 2042236769SobrienPrintOnError(GNode *gn, const char *s) 2043236769Sobrien{ 2044236769Sobrien static GNode *en = NULL; 2045236769Sobrien char tmp[64]; 2046236769Sobrien char *cp; 2047236769Sobrien 2048236769Sobrien if (s) 2049236769Sobrien printf("%s", s); 2050236769Sobrien 2051236769Sobrien printf("\n%s: stopped in %s\n", progname, curdir); 2052236769Sobrien 2053236769Sobrien if (en) 2054236769Sobrien return; /* we've been here! */ 2055236769Sobrien if (gn) { 2056236769Sobrien /* 2057236769Sobrien * We can print this even if there is no .ERROR target. 2058236769Sobrien */ 2059236769Sobrien Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 2060321964Ssjg Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2061321964Ssjg Lst_ForEach(gn->commands, addErrorCMD, gn); 2062236769Sobrien } 2063236769Sobrien strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 2064236769Sobrien sizeof(tmp) - 1); 2065321964Ssjg cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); 2066236769Sobrien if (cp) { 2067236769Sobrien if (*cp) 2068236769Sobrien printf("%s", cp); 2069236769Sobrien free(cp); 2070236769Sobrien } 2071292068Ssjg fflush(stdout); 2072292068Ssjg 2073236769Sobrien /* 2074236769Sobrien * Finally, see if there is a .ERROR target, and run it if so. 2075236769Sobrien */ 2076236769Sobrien en = Targ_FindNode(".ERROR", TARG_NOCREATE); 2077236769Sobrien if (en) { 2078236769Sobrien en->type |= OP_SPECIAL; 2079236769Sobrien Compat_Make(en, en); 2080236769Sobrien } 2081236769Sobrien} 2082236769Sobrien 2083236769Sobrienvoid 2084236769SobrienMain_ExportMAKEFLAGS(Boolean first) 2085236769Sobrien{ 2086236769Sobrien static int once = 1; 2087236769Sobrien char tmp[64]; 2088236769Sobrien char *s; 2089236769Sobrien 2090236769Sobrien if (once != first) 2091236769Sobrien return; 2092236769Sobrien once = 0; 2093236769Sobrien 2094236769Sobrien strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 2095236769Sobrien sizeof(tmp)); 2096321964Ssjg s = Var_Subst(NULL, tmp, VAR_CMD, VARF_WANTRES); 2097236769Sobrien if (s && *s) { 2098236769Sobrien#ifdef POSIX 2099236769Sobrien setenv("MAKEFLAGS", s, 1); 2100236769Sobrien#else 2101236769Sobrien setenv("MAKE", s, 1); 2102236769Sobrien#endif 2103236769Sobrien } 2104236769Sobrien} 2105236769Sobrien 2106236769Sobrienchar * 2107236769SobriengetTmpdir(void) 2108236769Sobrien{ 2109236769Sobrien static char *tmpdir = NULL; 2110236769Sobrien 2111236769Sobrien if (!tmpdir) { 2112236769Sobrien struct stat st; 2113236769Sobrien 2114236769Sobrien /* 2115236769Sobrien * Honor $TMPDIR but only if it is valid. 2116236769Sobrien * Ensure it ends with /. 2117236769Sobrien */ 2118292068Ssjg tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 2119321964Ssjg VARF_WANTRES); 2120236769Sobrien if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2121236769Sobrien free(tmpdir); 2122236769Sobrien tmpdir = bmake_strdup(_PATH_TMP); 2123236769Sobrien } 2124236769Sobrien } 2125236769Sobrien return tmpdir; 2126236769Sobrien} 2127236769Sobrien 2128236769Sobrien/* 2129236769Sobrien * Create and open a temp file using "pattern". 2130236769Sobrien * If "fnamep" is provided set it to a copy of the filename created. 2131236769Sobrien * Otherwise unlink the file once open. 2132236769Sobrien */ 2133236769Sobrienint 2134236769SobrienmkTempFile(const char *pattern, char **fnamep) 2135236769Sobrien{ 2136236769Sobrien static char *tmpdir = NULL; 2137236769Sobrien char tfile[MAXPATHLEN]; 2138236769Sobrien int fd; 2139236769Sobrien 2140236769Sobrien if (!pattern) 2141236769Sobrien pattern = TMPPAT; 2142236769Sobrien if (!tmpdir) 2143236769Sobrien tmpdir = getTmpdir(); 2144236769Sobrien if (pattern[0] == '/') { 2145236769Sobrien snprintf(tfile, sizeof(tfile), "%s", pattern); 2146236769Sobrien } else { 2147236769Sobrien snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2148236769Sobrien } 2149236769Sobrien if ((fd = mkstemp(tfile)) < 0) 2150236769Sobrien Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2151236769Sobrien if (fnamep) { 2152236769Sobrien *fnamep = bmake_strdup(tfile); 2153236769Sobrien } else { 2154236769Sobrien unlink(tfile); /* we just want the descriptor */ 2155236769Sobrien } 2156236769Sobrien return fd; 2157236769Sobrien} 2158240330Smarcel 2159321964Ssjg/* 2160321964Ssjg * Convert a string representation of a boolean. 2161321964Ssjg * Anything that looks like "No", "False", "Off", "0" etc, 2162321964Ssjg * is FALSE, otherwise TRUE. 2163321964Ssjg */ 2164321964SsjgBoolean 2165321964Ssjgs2Boolean(const char *s, Boolean bf) 2166321964Ssjg{ 2167321964Ssjg if (s) { 2168321964Ssjg switch(*s) { 2169321964Ssjg case '\0': /* not set - the default wins */ 2170321964Ssjg break; 2171321964Ssjg case '0': 2172321964Ssjg case 'F': 2173321964Ssjg case 'f': 2174321964Ssjg case 'N': 2175321964Ssjg case 'n': 2176321964Ssjg bf = FALSE; 2177321964Ssjg break; 2178321964Ssjg case 'O': 2179321964Ssjg case 'o': 2180321964Ssjg switch (s[1]) { 2181321964Ssjg case 'F': 2182321964Ssjg case 'f': 2183321964Ssjg bf = FALSE; 2184321964Ssjg break; 2185321964Ssjg default: 2186321964Ssjg bf = TRUE; 2187321964Ssjg break; 2188321964Ssjg } 2189321964Ssjg break; 2190321964Ssjg default: 2191321964Ssjg bf = TRUE; 2192321964Ssjg break; 2193321964Ssjg } 2194321964Ssjg } 2195321964Ssjg return (bf); 2196321964Ssjg} 2197240330Smarcel 2198240330Smarcel/* 2199240330Smarcel * Return a Boolean based on setting of a knob. 2200240330Smarcel * 2201240330Smarcel * If the knob is not set, the supplied default is the return value. 2202240330Smarcel * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 2203240330Smarcel * is FALSE, otherwise TRUE. 2204240330Smarcel */ 2205240330SmarcelBoolean 2206240330SmarcelgetBoolean(const char *name, Boolean bf) 2207240330Smarcel{ 2208240330Smarcel char tmp[64]; 2209240330Smarcel char *cp; 2210240330Smarcel 2211321964Ssjg if (snprintf(tmp, sizeof(tmp), "${%s:U:tl}", name) < (int)(sizeof(tmp))) { 2212321964Ssjg cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); 2213240330Smarcel 2214240330Smarcel if (cp) { 2215321964Ssjg bf = s2Boolean(cp, bf); 2216240330Smarcel free(cp); 2217240330Smarcel } 2218240330Smarcel } 2219240330Smarcel return (bf); 2220240330Smarcel} 2221