1359754Skevans/* $NetBSD: main.c,v 1.274 2020/03/30 02:41:06 sjg 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 72359754Skevansstatic char rcsid[] = "$NetBSD: main.c,v 1.274 2020/03/30 02:41:06 sjg 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 84359754Skevans__RCSID("$NetBSD: main.c,v 1.274 2020/03/30 02:41:06 sjg 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 102281812Ssjg * takes a format string and optional arguments 103281812Ssjg * for it. 104236769Sobrien * 105236769Sobrien * Fatal Print an error message and exit. Also takes 106281812Ssjg * a format string and arguments for it. 107236769Sobrien * 108236769Sobrien * Punt Aborts all jobs and exits with a message. Also 109281812Ssjg * 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> 121261212Ssjg#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 122261212Ssjg#include <sys/sysctl.h> 123261212Ssjg#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 150261212Ssjg#ifndef __arraycount 151261212Ssjg# define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 152261212Ssjg#endif 153261212Ssjg 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 */ 158319884SsjgBoolean deleteOnError; /* .DELETE_ON_ERROR: set */ 159236769Sobrien 160236769Sobrienstatic Boolean noBuiltins; /* -r flag */ 161236769Sobrienstatic Lst makefiles; /* ordered list of makefiles to read */ 162321653Ssjgstatic int printVars; /* -[vV] argument */ 163321653Ssjg#define COMPAT_VARS 1 164321653Ssjg#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 */ 177289842SsjgBoolean 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; 192319884Ssjgstatic 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 202359754SkevansFILE *debug_file; 203359754Skevans 204236769SobrienBoolean forceJobs = FALSE; 205236769Sobrien 206236769Sobrien/* 207236769Sobrien * On some systems MACHINE is defined as something other than 208236769Sobrien * what we want. 209236769Sobrien */ 210236769Sobrien#ifdef FORCE_MACHINE 211236769Sobrien# undef MACHINE 212236769Sobrien# define MACHINE FORCE_MACHINE 213236769Sobrien#endif 214236769Sobrien 215236769Sobrienextern Lst parseIncPath; 216236769Sobrien 217253883Ssjg/* 218253883Ssjg * For compatibility with the POSIX version of MAKEFLAGS that includes 219253883Ssjg * all the options with out -, convert flags to -f -l -a -g -s. 220253883Ssjg */ 221253883Ssjgstatic char * 222253883Ssjgexplode(const char *flags) 223253883Ssjg{ 224253883Ssjg size_t len; 225253883Ssjg char *nf, *st; 226253883Ssjg const char *f; 227253883Ssjg 228253883Ssjg if (flags == NULL) 229253883Ssjg return NULL; 230253883Ssjg 231253883Ssjg for (f = flags; *f; f++) 232253883Ssjg if (!isalpha((unsigned char)*f)) 233253883Ssjg break; 234253883Ssjg 235253883Ssjg if (*f) 236253883Ssjg return bmake_strdup(flags); 237253883Ssjg 238253883Ssjg len = strlen(flags); 239253883Ssjg st = nf = bmake_malloc(len * 3 + 1); 240253883Ssjg while (*flags) { 241253883Ssjg *nf++ = '-'; 242253883Ssjg *nf++ = *flags++; 243253883Ssjg *nf++ = ' '; 244253883Ssjg } 245253883Ssjg *nf = '\0'; 246253883Ssjg return st; 247253883Ssjg} 248253883Ssjg 249236769Sobrienstatic void 250236769Sobrienparse_debug_options(const char *argvalue) 251236769Sobrien{ 252236769Sobrien const char *modules; 253236769Sobrien const char *mode; 254236769Sobrien char *fname; 255236769Sobrien int len; 256236769Sobrien 257236769Sobrien for (modules = argvalue; *modules; ++modules) { 258236769Sobrien switch (*modules) { 259236769Sobrien case 'A': 260236769Sobrien debug = ~0; 261236769Sobrien break; 262236769Sobrien case 'a': 263236769Sobrien debug |= DEBUG_ARCH; 264236769Sobrien break; 265236769Sobrien case 'C': 266236769Sobrien debug |= DEBUG_CWD; 267236769Sobrien break; 268236769Sobrien case 'c': 269236769Sobrien debug |= DEBUG_COND; 270236769Sobrien break; 271236769Sobrien case 'd': 272236769Sobrien debug |= DEBUG_DIR; 273236769Sobrien break; 274236769Sobrien case 'e': 275236769Sobrien debug |= DEBUG_ERROR; 276236769Sobrien break; 277236769Sobrien case 'f': 278236769Sobrien debug |= DEBUG_FOR; 279236769Sobrien break; 280236769Sobrien case 'g': 281236769Sobrien if (modules[1] == '1') { 282236769Sobrien debug |= DEBUG_GRAPH1; 283236769Sobrien ++modules; 284236769Sobrien } 285236769Sobrien else if (modules[1] == '2') { 286236769Sobrien debug |= DEBUG_GRAPH2; 287236769Sobrien ++modules; 288236769Sobrien } 289236769Sobrien else if (modules[1] == '3') { 290236769Sobrien debug |= DEBUG_GRAPH3; 291236769Sobrien ++modules; 292236769Sobrien } 293236769Sobrien break; 294236769Sobrien case 'j': 295236769Sobrien debug |= DEBUG_JOB; 296236769Sobrien break; 297236769Sobrien case 'l': 298236769Sobrien debug |= DEBUG_LOUD; 299236769Sobrien break; 300236769Sobrien case 'M': 301236769Sobrien debug |= DEBUG_META; 302236769Sobrien break; 303236769Sobrien case 'm': 304236769Sobrien debug |= DEBUG_MAKE; 305236769Sobrien break; 306236769Sobrien case 'n': 307236769Sobrien debug |= DEBUG_SCRIPT; 308236769Sobrien break; 309236769Sobrien case 'p': 310236769Sobrien debug |= DEBUG_PARSE; 311236769Sobrien break; 312236769Sobrien case 's': 313236769Sobrien debug |= DEBUG_SUFF; 314236769Sobrien break; 315236769Sobrien case 't': 316236769Sobrien debug |= DEBUG_TARG; 317236769Sobrien break; 318240330Smarcel case 'V': 319240330Smarcel debugVflag = TRUE; 320240330Smarcel break; 321236769Sobrien case 'v': 322236769Sobrien debug |= DEBUG_VAR; 323236769Sobrien break; 324236769Sobrien case 'x': 325236769Sobrien debug |= DEBUG_SHELL; 326236769Sobrien break; 327236769Sobrien case 'F': 328236769Sobrien if (debug_file != stdout && debug_file != stderr) 329236769Sobrien fclose(debug_file); 330236769Sobrien if (*++modules == '+') { 331236769Sobrien modules++; 332236769Sobrien mode = "a"; 333236769Sobrien } else 334236769Sobrien mode = "w"; 335236769Sobrien if (strcmp(modules, "stdout") == 0) { 336236769Sobrien debug_file = stdout; 337236769Sobrien goto debug_setbuf; 338236769Sobrien } 339236769Sobrien if (strcmp(modules, "stderr") == 0) { 340236769Sobrien debug_file = stderr; 341236769Sobrien goto debug_setbuf; 342236769Sobrien } 343236769Sobrien len = strlen(modules); 344319884Ssjg fname = bmake_malloc(len + 20); 345236769Sobrien memcpy(fname, modules, len + 1); 346236769Sobrien /* Let the filename be modified by the pid */ 347236769Sobrien if (strcmp(fname + len - 3, ".%d") == 0) 348236769Sobrien snprintf(fname + len - 2, 20, "%d", getpid()); 349236769Sobrien debug_file = fopen(fname, mode); 350236769Sobrien if (!debug_file) { 351236769Sobrien fprintf(stderr, "Cannot open debug file %s\n", 352236769Sobrien fname); 353236769Sobrien usage(); 354236769Sobrien } 355236769Sobrien free(fname); 356236769Sobrien goto debug_setbuf; 357236769Sobrien default: 358236769Sobrien (void)fprintf(stderr, 359236769Sobrien "%s: illegal argument to d option -- %c\n", 360236769Sobrien progname, *modules); 361236769Sobrien usage(); 362236769Sobrien } 363236769Sobrien } 364236769Sobriendebug_setbuf: 365236769Sobrien /* 366236769Sobrien * Make the debug_file unbuffered, and make 367236769Sobrien * stdout line buffered (unless debugfile == stdout). 368236769Sobrien */ 369236769Sobrien setvbuf(debug_file, NULL, _IONBF, 0); 370236769Sobrien if (debug_file != stdout) { 371236769Sobrien setvbuf(stdout, NULL, _IOLBF, 0); 372236769Sobrien } 373236769Sobrien} 374236769Sobrien 375319884Ssjg/* 376319884Ssjg * does path contain any relative components 377319884Ssjg */ 378319884Ssjgstatic int 379319884Ssjgis_relpath(const char *path) 380319884Ssjg{ 381319884Ssjg const char *cp; 382319884Ssjg 383319884Ssjg if (path[0] != '/') 384319884Ssjg return TRUE; 385319884Ssjg cp = path; 386319884Ssjg do { 387319884Ssjg cp = strstr(cp, "/."); 388319884Ssjg if (!cp) 389319884Ssjg break; 390319884Ssjg cp += 2; 391319884Ssjg if (cp[0] == '/' || cp[0] == '\0') 392319884Ssjg return TRUE; 393319884Ssjg else if (cp[0] == '.') { 394319884Ssjg if (cp[1] == '/' || cp[1] == '\0') 395319884Ssjg return TRUE; 396319884Ssjg } 397319884Ssjg } while (cp); 398319884Ssjg return FALSE; 399319884Ssjg} 400319884Ssjg 401236769Sobrien/*- 402236769Sobrien * MainParseArgs -- 403236769Sobrien * Parse a given argument vector. Called from main() and from 404236769Sobrien * Main_ParseArgLine() when the .MAKEFLAGS target is used. 405236769Sobrien * 406236769Sobrien * XXX: Deal with command line overriding .MAKEFLAGS in makefile 407236769Sobrien * 408236769Sobrien * Results: 409236769Sobrien * None 410236769Sobrien * 411236769Sobrien * Side Effects: 412236769Sobrien * Various global and local flags will be set depending on the flags 413236769Sobrien * given 414236769Sobrien */ 415236769Sobrienstatic void 416236769SobrienMainParseArgs(int argc, char **argv) 417236769Sobrien{ 418236769Sobrien char *p; 419236769Sobrien int c = '?'; 420236769Sobrien int arginc; 421236769Sobrien char *argvalue; 422236769Sobrien const char *getopt_def; 423319884Ssjg struct stat sa, sb; 424236769Sobrien char *optscan; 425236769Sobrien Boolean inOption, dashDash = FALSE; 426236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 427236769Sobrien 428321653Ssjg#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w" 429236769Sobrien/* Can't actually use getopt(3) because rescanning is not portable */ 430236769Sobrien 431236769Sobrien getopt_def = OPTFLAGS; 432236769Sobrienrearg: 433236769Sobrien inOption = FALSE; 434236769Sobrien optscan = NULL; 435236769Sobrien while(argc > 1) { 436236769Sobrien char *getopt_spec; 437236769Sobrien if(!inOption) 438236769Sobrien optscan = argv[1]; 439236769Sobrien c = *optscan++; 440236769Sobrien arginc = 0; 441236769Sobrien if(inOption) { 442236769Sobrien if(c == '\0') { 443236769Sobrien ++argv; 444236769Sobrien --argc; 445236769Sobrien inOption = FALSE; 446236769Sobrien continue; 447236769Sobrien } 448236769Sobrien } else { 449236769Sobrien if (c != '-' || dashDash) 450236769Sobrien break; 451236769Sobrien inOption = TRUE; 452236769Sobrien c = *optscan++; 453236769Sobrien } 454236769Sobrien /* '-' found at some earlier point */ 455236769Sobrien getopt_spec = strchr(getopt_def, c); 456236769Sobrien if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 457236769Sobrien /* -<something> found, and <something> should have an arg */ 458236769Sobrien inOption = FALSE; 459236769Sobrien arginc = 1; 460236769Sobrien argvalue = optscan; 461236769Sobrien if(*argvalue == '\0') { 462236769Sobrien if (argc < 3) 463236769Sobrien goto noarg; 464236769Sobrien argvalue = argv[2]; 465236769Sobrien arginc = 2; 466236769Sobrien } 467236769Sobrien } else { 468236769Sobrien argvalue = NULL; 469236769Sobrien } 470236769Sobrien switch(c) { 471236769Sobrien case '\0': 472236769Sobrien arginc = 1; 473236769Sobrien inOption = FALSE; 474236769Sobrien break; 475236769Sobrien case 'B': 476236769Sobrien compatMake = TRUE; 477236769Sobrien Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 478236769Sobrien Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 479236769Sobrien break; 480236769Sobrien case 'C': 481236769Sobrien if (chdir(argvalue) == -1) { 482236769Sobrien (void)fprintf(stderr, 483236769Sobrien "%s: chdir %s: %s\n", 484236769Sobrien progname, argvalue, 485236769Sobrien strerror(errno)); 486236769Sobrien exit(1); 487236769Sobrien } 488236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 489236769Sobrien (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 490236769Sobrien exit(2); 491236769Sobrien } 492319884Ssjg if (!is_relpath(argvalue) && 493319884Ssjg stat(argvalue, &sa) != -1 && 494319884Ssjg stat(curdir, &sb) != -1 && 495319884Ssjg sa.st_ino == sb.st_ino && 496319884Ssjg sa.st_dev == sb.st_dev) 497319884Ssjg strncpy(curdir, argvalue, MAXPATHLEN); 498236769Sobrien ignorePWD = TRUE; 499236769Sobrien break; 500236769Sobrien case 'D': 501236769Sobrien if (argvalue == NULL || argvalue[0] == 0) goto noarg; 502236769Sobrien Var_Set(argvalue, "1", VAR_GLOBAL, 0); 503236769Sobrien Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 504236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 505236769Sobrien break; 506236769Sobrien case 'I': 507236769Sobrien if (argvalue == NULL) goto noarg; 508236769Sobrien Parse_AddIncludeDir(argvalue); 509236769Sobrien Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 510236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 511236769Sobrien break; 512236769Sobrien case 'J': 513236769Sobrien if (argvalue == NULL) goto noarg; 514236769Sobrien if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 515236769Sobrien (void)fprintf(stderr, 516236769Sobrien "%s: internal error -- J option malformed (%s)\n", 517236769Sobrien progname, argvalue); 518236769Sobrien usage(); 519236769Sobrien } 520236769Sobrien if ((fcntl(jp_0, F_GETFD, 0) < 0) || 521236769Sobrien (fcntl(jp_1, F_GETFD, 0) < 0)) { 522236769Sobrien#if 0 523236769Sobrien (void)fprintf(stderr, 524236769Sobrien "%s: ###### warning -- J descriptors were closed!\n", 525236769Sobrien progname); 526236769Sobrien exit(2); 527236769Sobrien#endif 528236769Sobrien jp_0 = -1; 529236769Sobrien jp_1 = -1; 530236769Sobrien compatMake = TRUE; 531236769Sobrien } else { 532236769Sobrien Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 533236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 534236769Sobrien jobServer = TRUE; 535236769Sobrien } 536236769Sobrien break; 537236769Sobrien case 'N': 538236769Sobrien noExecute = TRUE; 539236769Sobrien noRecursiveExecute = TRUE; 540236769Sobrien Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 541236769Sobrien break; 542236769Sobrien case 'S': 543236769Sobrien keepgoing = FALSE; 544236769Sobrien Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 545236769Sobrien break; 546236769Sobrien case 'T': 547236769Sobrien if (argvalue == NULL) goto noarg; 548236769Sobrien tracefile = bmake_strdup(argvalue); 549236769Sobrien Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 550236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 551236769Sobrien break; 552236769Sobrien case 'V': 553321653Ssjg case 'v': 554236769Sobrien if (argvalue == NULL) goto noarg; 555321653Ssjg printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; 556236769Sobrien (void)Lst_AtEnd(variables, argvalue); 557236769Sobrien Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 558236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 559236769Sobrien break; 560236769Sobrien case 'W': 561236769Sobrien parseWarnFatal = TRUE; 562236769Sobrien break; 563236769Sobrien case 'X': 564236769Sobrien varNoExportEnv = TRUE; 565236769Sobrien Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 566236769Sobrien break; 567236769Sobrien case 'd': 568236769Sobrien if (argvalue == NULL) goto noarg; 569236769Sobrien /* If '-d-opts' don't pass to children */ 570236769Sobrien if (argvalue[0] == '-') 571236769Sobrien argvalue++; 572236769Sobrien else { 573236769Sobrien Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 574236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 575236769Sobrien } 576236769Sobrien parse_debug_options(argvalue); 577236769Sobrien break; 578236769Sobrien case 'e': 579236769Sobrien checkEnvFirst = TRUE; 580236769Sobrien Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 581236769Sobrien break; 582236769Sobrien case 'f': 583236769Sobrien if (argvalue == NULL) goto noarg; 584236769Sobrien (void)Lst_AtEnd(makefiles, argvalue); 585236769Sobrien break; 586236769Sobrien case 'i': 587236769Sobrien ignoreErrors = TRUE; 588236769Sobrien Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 589236769Sobrien break; 590236769Sobrien case 'j': 591236769Sobrien if (argvalue == NULL) goto noarg; 592236769Sobrien forceJobs = TRUE; 593236769Sobrien maxJobs = strtol(argvalue, &p, 0); 594236769Sobrien if (*p != '\0' || maxJobs < 1) { 595236769Sobrien (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 596236769Sobrien progname); 597236769Sobrien exit(1); 598236769Sobrien } 599236769Sobrien Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 600236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 601236769Sobrien Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 602236769Sobrien maxJobTokens = maxJobs; 603236769Sobrien break; 604236769Sobrien case 'k': 605236769Sobrien keepgoing = TRUE; 606236769Sobrien Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 607236769Sobrien break; 608236769Sobrien case 'm': 609236769Sobrien if (argvalue == NULL) goto noarg; 610236769Sobrien /* look for magic parent directory search string */ 611236769Sobrien if (strncmp(".../", argvalue, 4) == 0) { 612236769Sobrien if (!Dir_FindHereOrAbove(curdir, argvalue+4, 613236769Sobrien found_path, sizeof(found_path))) 614236769Sobrien break; /* nothing doing */ 615236769Sobrien (void)Dir_AddDir(sysIncPath, found_path); 616236769Sobrien } else { 617236769Sobrien (void)Dir_AddDir(sysIncPath, argvalue); 618236769Sobrien } 619236769Sobrien Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 620236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 621236769Sobrien break; 622236769Sobrien case 'n': 623236769Sobrien noExecute = TRUE; 624236769Sobrien Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 625236769Sobrien break; 626236769Sobrien case 'q': 627236769Sobrien queryFlag = TRUE; 628236769Sobrien /* Kind of nonsensical, wot? */ 629236769Sobrien Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 630236769Sobrien break; 631236769Sobrien case 'r': 632236769Sobrien noBuiltins = TRUE; 633236769Sobrien Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 634236769Sobrien break; 635236769Sobrien case 's': 636236769Sobrien beSilent = TRUE; 637236769Sobrien Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 638236769Sobrien break; 639236769Sobrien case 't': 640236769Sobrien touchFlag = TRUE; 641236769Sobrien Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 642236769Sobrien break; 643253883Ssjg case 'w': 644253883Ssjg enterFlag = TRUE; 645253883Ssjg Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 646253883Ssjg break; 647236769Sobrien case '-': 648236769Sobrien dashDash = TRUE; 649236769Sobrien break; 650236769Sobrien default: 651236769Sobrien case '?': 652236769Sobrien#ifndef MAKE_NATIVE 653236769Sobrien fprintf(stderr, "getopt(%s) -> %d (%c)\n", 654236769Sobrien OPTFLAGS, c, c); 655236769Sobrien#endif 656236769Sobrien usage(); 657236769Sobrien } 658236769Sobrien argv += arginc; 659236769Sobrien argc -= arginc; 660236769Sobrien } 661236769Sobrien 662236769Sobrien oldVars = TRUE; 663236769Sobrien 664236769Sobrien /* 665236769Sobrien * See if the rest of the arguments are variable assignments and 666236769Sobrien * perform them if so. Else take them to be targets and stuff them 667236769Sobrien * on the end of the "create" list. 668236769Sobrien */ 669236769Sobrien for (; argc > 1; ++argv, --argc) 670236769Sobrien if (Parse_IsVar(argv[1])) { 671236769Sobrien Parse_DoVar(argv[1], VAR_CMD); 672236769Sobrien } else { 673236769Sobrien if (!*argv[1]) 674236769Sobrien Punt("illegal (null) argument."); 675236769Sobrien if (*argv[1] == '-' && !dashDash) 676236769Sobrien goto rearg; 677236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 678236769Sobrien } 679236769Sobrien 680236769Sobrien return; 681236769Sobriennoarg: 682236769Sobrien (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 683236769Sobrien progname, c); 684236769Sobrien usage(); 685236769Sobrien} 686236769Sobrien 687236769Sobrien/*- 688236769Sobrien * Main_ParseArgLine -- 689236769Sobrien * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 690236769Sobrien * is encountered and by main() when reading the .MAKEFLAGS envariable. 691236769Sobrien * Takes a line of arguments and breaks it into its 692236769Sobrien * component words and passes those words and the number of them to the 693236769Sobrien * MainParseArgs function. 694236769Sobrien * The line should have all its leading whitespace removed. 695236769Sobrien * 696236769Sobrien * Input: 697236769Sobrien * line Line to fracture 698236769Sobrien * 699236769Sobrien * Results: 700236769Sobrien * None 701236769Sobrien * 702236769Sobrien * Side Effects: 703236769Sobrien * Only those that come from the various arguments. 704236769Sobrien */ 705236769Sobrienvoid 706236769SobrienMain_ParseArgLine(const char *line) 707236769Sobrien{ 708236769Sobrien char **argv; /* Manufactured argument vector */ 709236769Sobrien int argc; /* Number of arguments in argv */ 710236769Sobrien char *args; /* Space used by the args */ 711236769Sobrien char *buf, *p1; 712236769Sobrien char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 713236769Sobrien size_t len; 714236769Sobrien 715236769Sobrien if (line == NULL) 716236769Sobrien return; 717236769Sobrien for (; *line == ' '; ++line) 718236769Sobrien continue; 719236769Sobrien if (!*line) 720236769Sobrien return; 721236769Sobrien 722236769Sobrien#ifndef POSIX 723236769Sobrien { 724236769Sobrien /* 725236769Sobrien * $MAKE may simply be naming the make(1) binary 726236769Sobrien */ 727236769Sobrien char *cp; 728236769Sobrien 729236769Sobrien if (!(cp = strrchr(line, '/'))) 730236769Sobrien cp = line; 731236769Sobrien if ((cp = strstr(cp, "make")) && 732236769Sobrien strcmp(cp, "make") == 0) 733236769Sobrien return; 734236769Sobrien } 735236769Sobrien#endif 736236769Sobrien buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 737236769Sobrien (void)snprintf(buf, len, "%s %s", argv0, line); 738296637Ssjg free(p1); 739236769Sobrien 740236769Sobrien argv = brk_string(buf, &argc, TRUE, &args); 741236769Sobrien if (argv == NULL) { 742236769Sobrien Error("Unterminated quoted string [%s]", buf); 743236769Sobrien free(buf); 744236769Sobrien return; 745236769Sobrien } 746236769Sobrien free(buf); 747236769Sobrien MainParseArgs(argc, argv); 748236769Sobrien 749236769Sobrien free(args); 750236769Sobrien free(argv); 751236769Sobrien} 752236769Sobrien 753236769SobrienBoolean 754319884SsjgMain_SetObjdir(const char *fmt, ...) 755236769Sobrien{ 756236769Sobrien struct stat sb; 757319884Ssjg char *path; 758236769Sobrien char buf[MAXPATHLEN + 1]; 759319884Ssjg char buf2[MAXPATHLEN + 1]; 760236769Sobrien Boolean rc = FALSE; 761319884Ssjg va_list ap; 762236769Sobrien 763319884Ssjg va_start(ap, fmt); 764319884Ssjg vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 765319884Ssjg va_end(ap); 766236769Sobrien 767236769Sobrien if (path[0] != '/') { 768319884Ssjg snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 769319884Ssjg path = buf2; 770236769Sobrien } 771236769Sobrien 772236769Sobrien /* look for the directory and try to chdir there */ 773236769Sobrien if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 774236769Sobrien if (chdir(path)) { 775236769Sobrien (void)fprintf(stderr, "make warning: %s: %s.\n", 776236769Sobrien path, strerror(errno)); 777236769Sobrien } else { 778236769Sobrien strncpy(objdir, path, MAXPATHLEN); 779236769Sobrien Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 780236769Sobrien setenv("PWD", objdir, 1); 781236769Sobrien Dir_InitDot(); 782319884Ssjg purge_cached_realpaths(); 783236769Sobrien rc = TRUE; 784289842Ssjg if (enterFlag && strcmp(objdir, curdir) != 0) 785289842Ssjg enterFlagObj = TRUE; 786236769Sobrien } 787236769Sobrien } 788236769Sobrien 789236769Sobrien return rc; 790236769Sobrien} 791236769Sobrien 792319884Ssjgstatic Boolean 793319884SsjgMain_SetVarObjdir(const char *var, const char *suffix) 794319884Ssjg{ 795319884Ssjg char *p, *path, *xpath; 796319884Ssjg 797331246Ssjg if ((path = Var_Value(var, VAR_CMD, &p)) == NULL || 798331246Ssjg *path == '\0') 799319884Ssjg return FALSE; 800319884Ssjg 801319884Ssjg /* expand variable substitutions */ 802319884Ssjg if (strchr(path, '$') != 0) 803319884Ssjg xpath = Var_Subst(NULL, path, VAR_GLOBAL, VARF_WANTRES); 804319884Ssjg else 805319884Ssjg xpath = path; 806319884Ssjg 807319884Ssjg (void)Main_SetObjdir("%s%s", xpath, suffix); 808319884Ssjg 809319884Ssjg if (xpath != path) 810319884Ssjg free(xpath); 811319884Ssjg free(p); 812319884Ssjg return TRUE; 813319884Ssjg} 814319884Ssjg 815236769Sobrien/*- 816236769Sobrien * ReadAllMakefiles -- 817236769Sobrien * wrapper around ReadMakefile() to read all. 818236769Sobrien * 819236769Sobrien * Results: 820236769Sobrien * TRUE if ok, FALSE on error 821236769Sobrien */ 822236769Sobrienstatic int 823236769SobrienReadAllMakefiles(const void *p, const void *q) 824236769Sobrien{ 825236769Sobrien return (ReadMakefile(p, q) == 0); 826236769Sobrien} 827236769Sobrien 828236769Sobrienint 829236769Sobrienstr2Lst_Append(Lst lp, char *str, const char *sep) 830236769Sobrien{ 831236769Sobrien char *cp; 832236769Sobrien int n; 833236769Sobrien 834236769Sobrien if (!sep) 835236769Sobrien sep = " \t"; 836236769Sobrien 837236769Sobrien for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 838236769Sobrien (void)Lst_AtEnd(lp, cp); 839236769Sobrien n++; 840236769Sobrien } 841236769Sobrien return (n); 842236769Sobrien} 843236769Sobrien 844236769Sobrien#ifdef SIGINFO 845236769Sobrien/*ARGSUSED*/ 846236769Sobrienstatic void 847237578Sobriensiginfo(int signo MAKE_ATTR_UNUSED) 848236769Sobrien{ 849236769Sobrien char dir[MAXPATHLEN]; 850236769Sobrien char str[2 * MAXPATHLEN]; 851236769Sobrien int len; 852236769Sobrien if (getcwd(dir, sizeof(dir)) == NULL) 853236769Sobrien return; 854236769Sobrien len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 855236769Sobrien if (len > 0) 856236769Sobrien (void)write(STDERR_FILENO, str, (size_t)len); 857236769Sobrien} 858236769Sobrien#endif 859236769Sobrien 860236769Sobrien/* 861236769Sobrien * Allow makefiles some control over the mode we run in. 862236769Sobrien */ 863236769Sobrienvoid 864236769SobrienMakeMode(const char *mode) 865236769Sobrien{ 866236769Sobrien char *mp = NULL; 867236769Sobrien 868236769Sobrien if (!mode) 869289842Ssjg mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", 870296637Ssjg VAR_GLOBAL, VARF_WANTRES); 871236769Sobrien 872236769Sobrien if (mode && *mode) { 873236769Sobrien if (strstr(mode, "compat")) { 874236769Sobrien compatMake = TRUE; 875236769Sobrien forceJobs = FALSE; 876236769Sobrien } 877236769Sobrien#if USE_META 878236769Sobrien if (strstr(mode, "meta")) 879249033Ssjg meta_mode_init(mode); 880236769Sobrien#endif 881236769Sobrien } 882296637Ssjg 883296637Ssjg free(mp); 884236769Sobrien} 885236769Sobrien 886321653Ssjgstatic void 887321653SsjgdoPrintVars(void) 888321653Ssjg{ 889321653Ssjg LstNode ln; 890321653Ssjg Boolean expandVars; 891321653Ssjg 892321653Ssjg if (printVars == EXPAND_VARS) 893321653Ssjg expandVars = TRUE; 894321653Ssjg else if (debugVflag) 895321653Ssjg expandVars = FALSE; 896321653Ssjg else 897321653Ssjg expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 898321653Ssjg 899321653Ssjg for (ln = Lst_First(variables); ln != NULL; 900321653Ssjg ln = Lst_Succ(ln)) { 901321653Ssjg char *var = (char *)Lst_Datum(ln); 902321653Ssjg char *value; 903321653Ssjg char *p1; 904321653Ssjg 905321653Ssjg if (strchr(var, '$')) { 906321653Ssjg value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 907321653Ssjg VARF_WANTRES); 908321653Ssjg } else if (expandVars) { 909321653Ssjg char tmp[128]; 910321653Ssjg int len = snprintf(tmp, sizeof(tmp), "${%s}", var); 911321653Ssjg 912321653Ssjg if (len >= (int)sizeof(tmp)) 913321653Ssjg Fatal("%s: variable name too big: %s", 914321653Ssjg progname, var); 915321653Ssjg value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, 916321653Ssjg VARF_WANTRES); 917321653Ssjg } else { 918321653Ssjg value = Var_Value(var, VAR_GLOBAL, &p1); 919321653Ssjg } 920321653Ssjg printf("%s\n", value ? value : ""); 921321653Ssjg free(p1); 922321653Ssjg } 923321653Ssjg} 924321653Ssjg 925321653Ssjgstatic Boolean 926321653SsjgrunTargets(void) 927321653Ssjg{ 928321653Ssjg Lst targs; /* target nodes to create -- passed to Make_Init */ 929321653Ssjg Boolean outOfDate; /* FALSE if all targets up to date */ 930321653Ssjg 931321653Ssjg /* 932321653Ssjg * Have now read the entire graph and need to make a list of 933321653Ssjg * targets to create. If none was given on the command line, 934321653Ssjg * we consult the parsing module to find the main target(s) 935321653Ssjg * to create. 936321653Ssjg */ 937321653Ssjg if (Lst_IsEmpty(create)) 938321653Ssjg targs = Parse_MainName(); 939321653Ssjg else 940321653Ssjg targs = Targ_FindList(create, TARG_CREATE); 941321653Ssjg 942321653Ssjg if (!compatMake) { 943321653Ssjg /* 944321653Ssjg * Initialize job module before traversing the graph 945321653Ssjg * now that any .BEGIN and .END targets have been read. 946321653Ssjg * This is done only if the -q flag wasn't given 947321653Ssjg * (to prevent the .BEGIN from being executed should 948321653Ssjg * it exist). 949321653Ssjg */ 950321653Ssjg if (!queryFlag) { 951321653Ssjg Job_Init(); 952321653Ssjg jobsRunning = TRUE; 953321653Ssjg } 954321653Ssjg 955321653Ssjg /* Traverse the graph, checking on all the targets */ 956321653Ssjg outOfDate = Make_Run(targs); 957321653Ssjg } else { 958321653Ssjg /* 959321653Ssjg * Compat_Init will take care of creating all the 960321653Ssjg * targets as well as initializing the module. 961321653Ssjg */ 962321653Ssjg Compat_Run(targs); 963321653Ssjg outOfDate = FALSE; 964321653Ssjg } 965321653Ssjg Lst_Destroy(targs, NULL); 966321653Ssjg return outOfDate; 967321653Ssjg} 968321653Ssjg 969236769Sobrien/*- 970236769Sobrien * main -- 971236769Sobrien * The main function, for obvious reasons. Initializes variables 972236769Sobrien * and a few modules, then parses the arguments give it in the 973236769Sobrien * environment and on the command line. Reads the system makefile 974236769Sobrien * followed by either Makefile, makefile or the file given by the 975236769Sobrien * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 976236769Sobrien * flags it has received by then uses either the Make or the Compat 977236769Sobrien * module to create the initial list of targets. 978236769Sobrien * 979236769Sobrien * Results: 980236769Sobrien * If -q was given, exits -1 if anything was out-of-date. Else it exits 981236769Sobrien * 0. 982236769Sobrien * 983236769Sobrien * Side Effects: 984236769Sobrien * The program exits when done. Targets are created. etc. etc. etc. 985236769Sobrien */ 986236769Sobrienint 987236769Sobrienmain(int argc, char **argv) 988236769Sobrien{ 989321653Ssjg Boolean outOfDate; /* FALSE if all targets up to date */ 990236769Sobrien struct stat sb, sa; 991250750Ssjg char *p1, *path; 992236769Sobrien char mdpath[MAXPATHLEN]; 993236769Sobrien#ifdef FORCE_MACHINE 994236769Sobrien const char *machine = FORCE_MACHINE; 995236769Sobrien#else 996236769Sobrien const char *machine = getenv("MACHINE"); 997236769Sobrien#endif 998236769Sobrien const char *machine_arch = getenv("MACHINE_ARCH"); 999236769Sobrien char *syspath = getenv("MAKESYSPATH"); 1000236769Sobrien Lst sysMkPath; /* Path of sys.mk */ 1001236769Sobrien char *cp = NULL, *start; 1002236769Sobrien /* avoid faults on read-only strings */ 1003236769Sobrien static char defsyspath[] = _PATH_DEFSYSPATH; 1004236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 1005236769Sobrien struct timeval rightnow; /* to initialize random seed */ 1006236769Sobrien struct utsname utsname; 1007236769Sobrien 1008236769Sobrien /* default to writing debug to stderr */ 1009236769Sobrien debug_file = stderr; 1010236769Sobrien 1011236769Sobrien#ifdef SIGINFO 1012236769Sobrien (void)bmake_signal(SIGINFO, siginfo); 1013236769Sobrien#endif 1014236769Sobrien /* 1015236769Sobrien * Set the seed to produce a different random sequence 1016236769Sobrien * on each program execution. 1017236769Sobrien */ 1018236769Sobrien gettimeofday(&rightnow, NULL); 1019236769Sobrien srandom(rightnow.tv_sec + rightnow.tv_usec); 1020236769Sobrien 1021236769Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 1022236769Sobrien progname++; 1023236769Sobrien else 1024236769Sobrien progname = argv[0]; 1025249033Ssjg#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1026236769Sobrien /* 1027236769Sobrien * get rid of resource limit on file descriptors 1028236769Sobrien */ 1029236769Sobrien { 1030236769Sobrien struct rlimit rl; 1031236769Sobrien if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1032236769Sobrien rl.rlim_cur != rl.rlim_max) { 1033236769Sobrien rl.rlim_cur = rl.rlim_max; 1034236769Sobrien (void)setrlimit(RLIMIT_NOFILE, &rl); 1035236769Sobrien } 1036236769Sobrien } 1037236769Sobrien#endif 1038236769Sobrien 1039249033Ssjg if (uname(&utsname) == -1) { 1040249033Ssjg (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1041249033Ssjg strerror(errno)); 1042249033Ssjg exit(2); 1043249033Ssjg } 1044249033Ssjg 1045236769Sobrien /* 1046236769Sobrien * Get the name of this type of MACHINE from utsname 1047236769Sobrien * so we can share an executable for similar machines. 1048236769Sobrien * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1049236769Sobrien * 1050236769Sobrien * Note that both MACHINE and MACHINE_ARCH are decided at 1051236769Sobrien * run-time. 1052236769Sobrien */ 1053236769Sobrien if (!machine) { 1054236769Sobrien#ifdef MAKE_NATIVE 1055236769Sobrien machine = utsname.machine; 1056236769Sobrien#else 1057236769Sobrien#ifdef MAKE_MACHINE 1058236769Sobrien machine = MAKE_MACHINE; 1059236769Sobrien#else 1060236769Sobrien machine = "unknown"; 1061236769Sobrien#endif 1062236769Sobrien#endif 1063236769Sobrien } 1064236769Sobrien 1065236769Sobrien if (!machine_arch) { 1066261212Ssjg#if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_MACHINE_ARCH) 1067261212Ssjg static char machine_arch_buf[sizeof(utsname.machine)]; 1068261212Ssjg int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1069261212Ssjg size_t len = sizeof(machine_arch_buf); 1070261212Ssjg 1071261212Ssjg if (sysctl(mib, __arraycount(mib), machine_arch_buf, 1072261212Ssjg &len, NULL, 0) < 0) { 1073261212Ssjg (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 1074261212Ssjg strerror(errno)); 1075261212Ssjg exit(2); 1076261212Ssjg } 1077261212Ssjg 1078261212Ssjg machine_arch = machine_arch_buf; 1079261212Ssjg#else 1080236769Sobrien#ifndef MACHINE_ARCH 1081236769Sobrien#ifdef MAKE_MACHINE_ARCH 1082236769Sobrien machine_arch = MAKE_MACHINE_ARCH; 1083236769Sobrien#else 1084236769Sobrien machine_arch = "unknown"; 1085236769Sobrien#endif 1086236769Sobrien#else 1087236769Sobrien machine_arch = MACHINE_ARCH; 1088236769Sobrien#endif 1089261212Ssjg#endif 1090236769Sobrien } 1091236769Sobrien 1092236769Sobrien myPid = getpid(); /* remember this for vFork() */ 1093236769Sobrien 1094236769Sobrien /* 1095236769Sobrien * Just in case MAKEOBJDIR wants us to do something tricky. 1096236769Sobrien */ 1097236769Sobrien Var_Init(); /* Initialize the lists of variables for 1098236769Sobrien * parsing arguments */ 1099249033Ssjg Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL, 0); 1100236769Sobrien Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 1101236769Sobrien Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 1102236769Sobrien#ifdef MAKE_VERSION 1103236769Sobrien Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 1104236769Sobrien#endif 1105236769Sobrien Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 1106236769Sobrien /* 1107236769Sobrien * This is the traditional preference for makefiles. 1108236769Sobrien */ 1109236769Sobrien#ifndef MAKEFILE_PREFERENCE_LIST 1110236769Sobrien# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1111236769Sobrien#endif 1112236769Sobrien Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1113236769Sobrien VAR_GLOBAL, 0); 1114236769Sobrien Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 1115236769Sobrien 1116236769Sobrien create = Lst_Init(FALSE); 1117236769Sobrien makefiles = Lst_Init(FALSE); 1118321653Ssjg printVars = 0; 1119240330Smarcel debugVflag = FALSE; 1120236769Sobrien variables = Lst_Init(FALSE); 1121236769Sobrien beSilent = FALSE; /* Print commands as executed */ 1122236769Sobrien ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1123236769Sobrien noExecute = FALSE; /* Execute all commands */ 1124236769Sobrien noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1125236769Sobrien keepgoing = FALSE; /* Stop on error */ 1126236769Sobrien allPrecious = FALSE; /* Remove targets when interrupted */ 1127319884Ssjg deleteOnError = FALSE; /* Historical default behavior */ 1128236769Sobrien queryFlag = FALSE; /* This is not just a check-run */ 1129236769Sobrien noBuiltins = FALSE; /* Read the built-in rules */ 1130236769Sobrien touchFlag = FALSE; /* Actually update targets */ 1131236769Sobrien debug = 0; /* No debug verbosity, please. */ 1132236769Sobrien jobsRunning = FALSE; 1133236769Sobrien 1134236769Sobrien maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1135236769Sobrien maxJobTokens = maxJobs; 1136236769Sobrien compatMake = FALSE; /* No compat mode */ 1137236769Sobrien ignorePWD = FALSE; 1138236769Sobrien 1139236769Sobrien /* 1140236769Sobrien * Initialize the parsing, directory and variable modules to prepare 1141236769Sobrien * for the reading of inclusion paths and variable settings on the 1142236769Sobrien * command line 1143236769Sobrien */ 1144236769Sobrien 1145236769Sobrien /* 1146236769Sobrien * Initialize various variables. 1147236769Sobrien * MAKE also gets this name, for compatibility 1148236769Sobrien * .MAKEFLAGS gets set to the empty string just in case. 1149236769Sobrien * MFLAGS also gets initialized empty, for compatibility. 1150236769Sobrien */ 1151236769Sobrien Parse_Init(); 1152236769Sobrien if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 1153236769Sobrien /* 1154236769Sobrien * Leave alone if it is an absolute path, or if it does 1155236769Sobrien * not contain a '/' in which case we need to find it in 1156236769Sobrien * the path, like execvp(3) and the shells do. 1157236769Sobrien */ 1158236769Sobrien p1 = argv[0]; 1159236769Sobrien } else { 1160236769Sobrien /* 1161236769Sobrien * A relative path, canonicalize it. 1162236769Sobrien */ 1163301462Ssjg p1 = cached_realpath(argv[0], mdpath); 1164236769Sobrien if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 1165236769Sobrien p1 = argv[0]; /* realpath failed */ 1166236769Sobrien } 1167236769Sobrien } 1168236769Sobrien Var_Set("MAKE", p1, VAR_GLOBAL, 0); 1169236769Sobrien Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 1170236769Sobrien Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 1171236769Sobrien Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 1172236769Sobrien Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 1173236769Sobrien Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 1174253883Ssjg /* some makefiles need to know this */ 1175253883Ssjg Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD, 0); 1176236769Sobrien 1177236769Sobrien /* 1178236769Sobrien * Set some other useful macros 1179236769Sobrien */ 1180236769Sobrien { 1181253883Ssjg char tmp[64], *ep; 1182236769Sobrien 1183253883Ssjg makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1184253883Ssjg if (makelevel < 0) 1185253883Ssjg makelevel = 0; 1186253883Ssjg snprintf(tmp, sizeof(tmp), "%d", makelevel); 1187253883Ssjg Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL, 0); 1188236769Sobrien snprintf(tmp, sizeof(tmp), "%u", myPid); 1189236769Sobrien Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 1190236769Sobrien snprintf(tmp, sizeof(tmp), "%u", getppid()); 1191236769Sobrien Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 1192236769Sobrien } 1193253883Ssjg if (makelevel > 0) { 1194253883Ssjg char pn[1024]; 1195253883Ssjg snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1196253883Ssjg progname = bmake_strdup(pn); 1197253883Ssjg } 1198236769Sobrien 1199249033Ssjg#ifdef USE_META 1200249033Ssjg meta_init(); 1201249033Ssjg#endif 1202319884Ssjg Dir_Init(NULL); /* Dir_* safe to call from MainParseArgs */ 1203319884Ssjg 1204236769Sobrien /* 1205236769Sobrien * First snag any flags out of the MAKE environment variable. 1206236769Sobrien * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1207236769Sobrien * in a different format). 1208236769Sobrien */ 1209236769Sobrien#ifdef POSIX 1210253883Ssjg p1 = explode(getenv("MAKEFLAGS")); 1211253883Ssjg Main_ParseArgLine(p1); 1212253883Ssjg free(p1); 1213236769Sobrien#else 1214236769Sobrien Main_ParseArgLine(getenv("MAKE")); 1215236769Sobrien#endif 1216236769Sobrien 1217236769Sobrien /* 1218236769Sobrien * Find where we are (now). 1219236769Sobrien * We take care of PWD for the automounter below... 1220236769Sobrien */ 1221236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 1222236769Sobrien (void)fprintf(stderr, "%s: getcwd: %s.\n", 1223236769Sobrien progname, strerror(errno)); 1224236769Sobrien exit(2); 1225236769Sobrien } 1226236769Sobrien 1227236769Sobrien MainParseArgs(argc, argv); 1228236769Sobrien 1229253883Ssjg if (enterFlag) 1230253883Ssjg printf("%s: Entering directory `%s'\n", progname, curdir); 1231253883Ssjg 1232236769Sobrien /* 1233236769Sobrien * Verify that cwd is sane. 1234236769Sobrien */ 1235236769Sobrien if (stat(curdir, &sa) == -1) { 1236236769Sobrien (void)fprintf(stderr, "%s: %s: %s.\n", 1237236769Sobrien progname, curdir, strerror(errno)); 1238236769Sobrien exit(2); 1239236769Sobrien } 1240236769Sobrien 1241236769Sobrien /* 1242236769Sobrien * All this code is so that we know where we are when we start up 1243236769Sobrien * on a different machine with pmake. 1244236769Sobrien * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1245236769Sobrien * since the value of curdir can vary depending on how we got 1246236769Sobrien * here. Ie sitting at a shell prompt (shell that provides $PWD) 1247236769Sobrien * or via subdir.mk in which case its likely a shell which does 1248236769Sobrien * not provide it. 1249236769Sobrien * So, to stop it breaking this case only, we ignore PWD if 1250236769Sobrien * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 1251236769Sobrien */ 1252236769Sobrien#ifndef NO_PWD_OVERRIDE 1253253883Ssjg if (!ignorePWD) { 1254268437Ssjg char *pwd, *ptmp1 = NULL, *ptmp2 = NULL; 1255236769Sobrien 1256253883Ssjg if ((pwd = getenv("PWD")) != NULL && 1257268437Ssjg Var_Value("MAKEOBJDIRPREFIX", VAR_CMD, &ptmp1) == NULL) { 1258268437Ssjg const char *makeobjdir = Var_Value("MAKEOBJDIR", 1259268437Ssjg VAR_CMD, &ptmp2); 1260253883Ssjg 1261253883Ssjg if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 1262253883Ssjg if (stat(pwd, &sb) == 0 && 1263253883Ssjg sa.st_ino == sb.st_ino && 1264253883Ssjg sa.st_dev == sb.st_dev) 1265253883Ssjg (void)strncpy(curdir, pwd, MAXPATHLEN); 1266253883Ssjg } 1267236769Sobrien } 1268268437Ssjg free(ptmp1); 1269268437Ssjg free(ptmp2); 1270236769Sobrien } 1271236769Sobrien#endif 1272236769Sobrien Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 1273236769Sobrien 1274236769Sobrien /* 1275236769Sobrien * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1276236769Sobrien * MAKEOBJDIR is set in the environment, try only that value 1277236769Sobrien * and fall back to .CURDIR if it does not exist. 1278236769Sobrien * 1279319884Ssjg * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1280319884Ssjg * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1281236769Sobrien * of these paths exist, just use .CURDIR. 1282236769Sobrien */ 1283236769Sobrien Dir_Init(curdir); 1284319884Ssjg (void)Main_SetObjdir("%s", curdir); 1285236769Sobrien 1286319884Ssjg if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1287319884Ssjg !Main_SetVarObjdir("MAKEOBJDIR", "") && 1288319884Ssjg !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1289319884Ssjg !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1290319884Ssjg !Main_SetObjdir("%s", _PATH_OBJDIR)) 1291319884Ssjg (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1292236769Sobrien 1293236769Sobrien /* 1294236769Sobrien * Initialize archive, target and suffix modules in preparation for 1295236769Sobrien * parsing the makefile(s) 1296236769Sobrien */ 1297236769Sobrien Arch_Init(); 1298236769Sobrien Targ_Init(); 1299236769Sobrien Suff_Init(); 1300236769Sobrien Trace_Init(tracefile); 1301236769Sobrien 1302236769Sobrien DEFAULT = NULL; 1303236769Sobrien (void)time(&now); 1304236769Sobrien 1305236769Sobrien Trace_Log(MAKESTART, NULL); 1306236769Sobrien 1307236769Sobrien /* 1308236769Sobrien * Set up the .TARGETS variable to contain the list of targets to be 1309236769Sobrien * created. If none specified, make the variable empty -- the parser 1310236769Sobrien * will fill the thing in with the default or .MAIN target. 1311236769Sobrien */ 1312236769Sobrien if (!Lst_IsEmpty(create)) { 1313236769Sobrien LstNode ln; 1314236769Sobrien 1315236769Sobrien for (ln = Lst_First(create); ln != NULL; 1316236769Sobrien ln = Lst_Succ(ln)) { 1317236769Sobrien char *name = (char *)Lst_Datum(ln); 1318236769Sobrien 1319236769Sobrien Var_Append(".TARGETS", name, VAR_GLOBAL); 1320236769Sobrien } 1321236769Sobrien } else 1322236769Sobrien Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 1323236769Sobrien 1324236769Sobrien 1325236769Sobrien /* 1326236769Sobrien * If no user-supplied system path was given (through the -m option) 1327236769Sobrien * add the directories from the DEFSYSPATH (more than one may be given 1328236769Sobrien * as dir1:...:dirn) to the system include path. 1329236769Sobrien */ 1330236769Sobrien if (syspath == NULL || *syspath == '\0') 1331236769Sobrien syspath = defsyspath; 1332236769Sobrien else 1333236769Sobrien syspath = bmake_strdup(syspath); 1334236769Sobrien 1335236769Sobrien for (start = syspath; *start != '\0'; start = cp) { 1336236769Sobrien for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1337236769Sobrien continue; 1338236769Sobrien if (*cp == ':') { 1339236769Sobrien *cp++ = '\0'; 1340236769Sobrien } 1341236769Sobrien /* look for magic parent directory search string */ 1342236769Sobrien if (strncmp(".../", start, 4) != 0) { 1343236769Sobrien (void)Dir_AddDir(defIncPath, start); 1344236769Sobrien } else { 1345236769Sobrien if (Dir_FindHereOrAbove(curdir, start+4, 1346236769Sobrien found_path, sizeof(found_path))) { 1347236769Sobrien (void)Dir_AddDir(defIncPath, found_path); 1348236769Sobrien } 1349236769Sobrien } 1350236769Sobrien } 1351236769Sobrien if (syspath != defsyspath) 1352236769Sobrien free(syspath); 1353236769Sobrien 1354236769Sobrien /* 1355236769Sobrien * Read in the built-in rules first, followed by the specified 1356236769Sobrien * makefile, if it was (makefile != NULL), or the default 1357236769Sobrien * makefile and Makefile, in that order, if it wasn't. 1358236769Sobrien */ 1359236769Sobrien if (!noBuiltins) { 1360236769Sobrien LstNode ln; 1361236769Sobrien 1362236769Sobrien sysMkPath = Lst_Init(FALSE); 1363236769Sobrien Dir_Expand(_PATH_DEFSYSMK, 1364236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1365236769Sobrien sysMkPath); 1366236769Sobrien if (Lst_IsEmpty(sysMkPath)) 1367236769Sobrien Fatal("%s: no system rules (%s).", progname, 1368236769Sobrien _PATH_DEFSYSMK); 1369236769Sobrien ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 1370236769Sobrien if (ln == NULL) 1371236769Sobrien Fatal("%s: cannot open %s.", progname, 1372236769Sobrien (char *)Lst_Datum(ln)); 1373236769Sobrien } 1374236769Sobrien 1375236769Sobrien if (!Lst_IsEmpty(makefiles)) { 1376236769Sobrien LstNode ln; 1377236769Sobrien 1378236769Sobrien ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 1379236769Sobrien if (ln != NULL) 1380236769Sobrien Fatal("%s: cannot open %s.", progname, 1381236769Sobrien (char *)Lst_Datum(ln)); 1382236769Sobrien } else { 1383236769Sobrien p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 1384296637Ssjg VAR_CMD, VARF_WANTRES); 1385236769Sobrien if (p1) { 1386236769Sobrien (void)str2Lst_Append(makefiles, p1, NULL); 1387236769Sobrien (void)Lst_Find(makefiles, NULL, ReadMakefile); 1388236769Sobrien free(p1); 1389236769Sobrien } 1390236769Sobrien } 1391236769Sobrien 1392236769Sobrien /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1393236769Sobrien if (!noBuiltins || !printVars) { 1394236769Sobrien makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 1395296637Ssjg VAR_CMD, VARF_WANTRES); 1396236769Sobrien doing_depend = TRUE; 1397236769Sobrien (void)ReadMakefile(makeDependfile, NULL); 1398236769Sobrien doing_depend = FALSE; 1399236769Sobrien } 1400236769Sobrien 1401289842Ssjg if (enterFlagObj) 1402289842Ssjg printf("%s: Entering directory `%s'\n", progname, objdir); 1403289842Ssjg 1404236769Sobrien MakeMode(NULL); 1405236769Sobrien 1406236769Sobrien Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1407296637Ssjg free(p1); 1408236769Sobrien 1409300313Ssjg if (!forceJobs && !compatMake && 1410300313Ssjg Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) { 1411300313Ssjg char *value; 1412300313Ssjg int n; 1413300313Ssjg 1414300313Ssjg value = Var_Subst(NULL, "${.MAKE.JOBS}", VAR_GLOBAL, VARF_WANTRES); 1415300313Ssjg n = strtol(value, NULL, 0); 1416300313Ssjg if (n < 1) { 1417300313Ssjg (void)fprintf(stderr, "%s: illegal value for .MAKE.JOBS -- must be positive integer!\n", 1418300313Ssjg progname); 1419300313Ssjg exit(1); 1420300313Ssjg } 1421300313Ssjg if (n != maxJobs) { 1422300313Ssjg Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1423300313Ssjg Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1424300313Ssjg } 1425300313Ssjg maxJobs = n; 1426300313Ssjg maxJobTokens = maxJobs; 1427300313Ssjg forceJobs = TRUE; 1428300313Ssjg free(value); 1429300313Ssjg } 1430300313Ssjg 1431300313Ssjg /* 1432300313Ssjg * Be compatible if user did not specify -j and did not explicitly 1433300313Ssjg * turned compatibility on 1434300313Ssjg */ 1435300313Ssjg if (!compatMake && !forceJobs) { 1436300313Ssjg compatMake = TRUE; 1437300313Ssjg } 1438300313Ssjg 1439236769Sobrien if (!compatMake) 1440236769Sobrien Job_ServerStart(maxJobTokens, jp_0, jp_1); 1441236769Sobrien if (DEBUG(JOB)) 1442236769Sobrien fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1443236769Sobrien jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 1444236769Sobrien 1445319884Ssjg if (!printVars) 1446319884Ssjg Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1447319884Ssjg 1448236769Sobrien /* 1449236769Sobrien * For compatibility, look at the directories in the VPATH variable 1450236769Sobrien * and add them to the search path, if the variable is defined. The 1451236769Sobrien * variable's value is in the same format as the PATH envariable, i.e. 1452236769Sobrien * <directory>:<directory>:<directory>... 1453236769Sobrien */ 1454236769Sobrien if (Var_Exists("VPATH", VAR_CMD)) { 1455236769Sobrien char *vpath, savec; 1456236769Sobrien /* 1457236769Sobrien * GCC stores string constants in read-only memory, but 1458236769Sobrien * Var_Subst will want to write this thing, so store it 1459236769Sobrien * in an array 1460236769Sobrien */ 1461236769Sobrien static char VPATH[] = "${VPATH}"; 1462236769Sobrien 1463296637Ssjg vpath = Var_Subst(NULL, VPATH, VAR_CMD, VARF_WANTRES); 1464236769Sobrien path = vpath; 1465236769Sobrien do { 1466236769Sobrien /* skip to end of directory */ 1467236769Sobrien for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1468236769Sobrien continue; 1469236769Sobrien /* Save terminator character so know when to stop */ 1470236769Sobrien savec = *cp; 1471236769Sobrien *cp = '\0'; 1472236769Sobrien /* Add directory to search path */ 1473236769Sobrien (void)Dir_AddDir(dirSearchPath, path); 1474236769Sobrien *cp = savec; 1475236769Sobrien path = cp + 1; 1476236769Sobrien } while (savec == ':'); 1477236769Sobrien free(vpath); 1478236769Sobrien } 1479236769Sobrien 1480236769Sobrien /* 1481236769Sobrien * Now that all search paths have been read for suffixes et al, it's 1482236769Sobrien * time to add the default search path to their lists... 1483236769Sobrien */ 1484236769Sobrien Suff_DoPaths(); 1485236769Sobrien 1486236769Sobrien /* 1487236769Sobrien * Propagate attributes through :: dependency lists. 1488236769Sobrien */ 1489236769Sobrien Targ_Propagate(); 1490236769Sobrien 1491236769Sobrien /* print the initial graph, if the user requested it */ 1492236769Sobrien if (DEBUG(GRAPH1)) 1493236769Sobrien Targ_PrintGraph(1); 1494236769Sobrien 1495236769Sobrien /* print the values of any variables requested by the user */ 1496236769Sobrien if (printVars) { 1497321653Ssjg doPrintVars(); 1498321653Ssjg outOfDate = FALSE; 1499236769Sobrien } else { 1500321653Ssjg outOfDate = runTargets(); 1501236769Sobrien } 1502236769Sobrien 1503236769Sobrien#ifdef CLEANUP 1504236769Sobrien Lst_Destroy(variables, NULL); 1505236769Sobrien Lst_Destroy(makefiles, NULL); 1506236769Sobrien Lst_Destroy(create, (FreeProc *)free); 1507236769Sobrien#endif 1508236769Sobrien 1509236769Sobrien /* print the graph now it's been processed if the user requested it */ 1510236769Sobrien if (DEBUG(GRAPH2)) 1511236769Sobrien Targ_PrintGraph(2); 1512236769Sobrien 1513236769Sobrien Trace_Log(MAKEEND, 0); 1514236769Sobrien 1515289842Ssjg if (enterFlagObj) 1516289842Ssjg printf("%s: Leaving directory `%s'\n", progname, objdir); 1517253883Ssjg if (enterFlag) 1518253883Ssjg printf("%s: Leaving directory `%s'\n", progname, curdir); 1519253883Ssjg 1520296637Ssjg#ifdef USE_META 1521296637Ssjg meta_finish(); 1522296637Ssjg#endif 1523236769Sobrien Suff_End(); 1524236769Sobrien Targ_End(); 1525236769Sobrien Arch_End(); 1526236769Sobrien Var_End(); 1527236769Sobrien Parse_End(); 1528236769Sobrien Dir_End(); 1529236769Sobrien Job_End(); 1530236769Sobrien Trace_End(); 1531236769Sobrien 1532236769Sobrien return outOfDate ? 1 : 0; 1533236769Sobrien} 1534236769Sobrien 1535236769Sobrien/*- 1536236769Sobrien * ReadMakefile -- 1537236769Sobrien * Open and parse the given makefile. 1538236769Sobrien * 1539236769Sobrien * Results: 1540236769Sobrien * 0 if ok. -1 if couldn't open file. 1541236769Sobrien * 1542236769Sobrien * Side Effects: 1543236769Sobrien * lots 1544236769Sobrien */ 1545236769Sobrienstatic int 1546237578SobrienReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 1547236769Sobrien{ 1548236769Sobrien const char *fname = p; /* makefile to read */ 1549236769Sobrien int fd; 1550236769Sobrien size_t len = MAXPATHLEN; 1551236769Sobrien char *name, *path = bmake_malloc(len); 1552236769Sobrien 1553236769Sobrien if (!strcmp(fname, "-")) { 1554236769Sobrien Parse_File(NULL /*stdin*/, -1); 1555255253Ssjg Var_Set("MAKEFILE", "", VAR_INTERNAL, 0); 1556236769Sobrien } else { 1557236769Sobrien /* if we've chdir'd, rebuild the path name */ 1558236769Sobrien if (strcmp(curdir, objdir) && *fname != '/') { 1559236769Sobrien size_t plen = strlen(curdir) + strlen(fname) + 2; 1560236769Sobrien if (len < plen) 1561236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1562236769Sobrien 1563236769Sobrien (void)snprintf(path, len, "%s/%s", curdir, fname); 1564236769Sobrien fd = open(path, O_RDONLY); 1565236769Sobrien if (fd != -1) { 1566236769Sobrien fname = path; 1567236769Sobrien goto found; 1568236769Sobrien } 1569236769Sobrien 1570236769Sobrien /* If curdir failed, try objdir (ala .depend) */ 1571236769Sobrien plen = strlen(objdir) + strlen(fname) + 2; 1572236769Sobrien if (len < plen) 1573236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1574236769Sobrien (void)snprintf(path, len, "%s/%s", objdir, fname); 1575236769Sobrien fd = open(path, O_RDONLY); 1576236769Sobrien if (fd != -1) { 1577236769Sobrien fname = path; 1578236769Sobrien goto found; 1579236769Sobrien } 1580236769Sobrien } else { 1581236769Sobrien fd = open(fname, O_RDONLY); 1582236769Sobrien if (fd != -1) 1583236769Sobrien goto found; 1584236769Sobrien } 1585236769Sobrien /* look in -I and system include directories. */ 1586236769Sobrien name = Dir_FindFile(fname, parseIncPath); 1587236769Sobrien if (!name) 1588236769Sobrien name = Dir_FindFile(fname, 1589236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1590236769Sobrien if (!name || (fd = open(name, O_RDONLY)) == -1) { 1591296637Ssjg free(name); 1592236769Sobrien free(path); 1593236769Sobrien return(-1); 1594236769Sobrien } 1595236769Sobrien fname = name; 1596236769Sobrien /* 1597236769Sobrien * set the MAKEFILE variable desired by System V fans -- the 1598236769Sobrien * placement of the setting here means it gets set to the last 1599236769Sobrien * makefile specified, as it is set by SysV make. 1600236769Sobrien */ 1601236769Sobrienfound: 1602236769Sobrien if (!doing_depend) 1603255253Ssjg Var_Set("MAKEFILE", fname, VAR_INTERNAL, 0); 1604236769Sobrien Parse_File(fname, fd); 1605236769Sobrien } 1606236769Sobrien free(path); 1607236769Sobrien return(0); 1608236769Sobrien} 1609236769Sobrien 1610236769Sobrien 1611236769Sobrien 1612236769Sobrien/*- 1613236769Sobrien * Cmd_Exec -- 1614236769Sobrien * Execute the command in cmd, and return the output of that command 1615236769Sobrien * in a string. 1616236769Sobrien * 1617236769Sobrien * Results: 1618236769Sobrien * A string containing the output of the command, or the empty string 1619236769Sobrien * If errnum is not NULL, it contains the reason for the command failure 1620236769Sobrien * 1621236769Sobrien * Side Effects: 1622236769Sobrien * The string must be freed by the caller. 1623236769Sobrien */ 1624236769Sobrienchar * 1625236769SobrienCmd_Exec(const char *cmd, const char **errnum) 1626236769Sobrien{ 1627236769Sobrien const char *args[4]; /* Args for invoking the shell */ 1628236769Sobrien int fds[2]; /* Pipe streams */ 1629236769Sobrien int cpid; /* Child PID */ 1630236769Sobrien int pid; /* PID from wait() */ 1631236769Sobrien char *res; /* result */ 1632236769Sobrien WAIT_T status; /* command exit status */ 1633236769Sobrien Buffer buf; /* buffer to store the result */ 1634236769Sobrien char *cp; 1635281812Ssjg int cc; /* bytes read, or -1 */ 1636281812Ssjg int savederr; /* saved errno */ 1637236769Sobrien 1638236769Sobrien 1639236769Sobrien *errnum = NULL; 1640236769Sobrien 1641236769Sobrien if (!shellName) 1642236769Sobrien Shell_Init(); 1643236769Sobrien /* 1644236769Sobrien * Set up arguments for shell 1645236769Sobrien */ 1646236769Sobrien args[0] = shellName; 1647236769Sobrien args[1] = "-c"; 1648236769Sobrien args[2] = cmd; 1649236769Sobrien args[3] = NULL; 1650236769Sobrien 1651236769Sobrien /* 1652236769Sobrien * Open a pipe for fetching its output 1653236769Sobrien */ 1654236769Sobrien if (pipe(fds) == -1) { 1655236769Sobrien *errnum = "Couldn't create pipe for \"%s\""; 1656236769Sobrien goto bad; 1657236769Sobrien } 1658236769Sobrien 1659236769Sobrien /* 1660236769Sobrien * Fork 1661236769Sobrien */ 1662236769Sobrien switch (cpid = vFork()) { 1663236769Sobrien case 0: 1664236769Sobrien /* 1665236769Sobrien * Close input side of pipe 1666236769Sobrien */ 1667236769Sobrien (void)close(fds[0]); 1668236769Sobrien 1669236769Sobrien /* 1670236769Sobrien * Duplicate the output stream to the shell's output, then 1671236769Sobrien * shut the extra thing down. Note we don't fetch the error 1672236769Sobrien * stream...why not? Why? 1673236769Sobrien */ 1674236769Sobrien (void)dup2(fds[1], 1); 1675236769Sobrien (void)close(fds[1]); 1676236769Sobrien 1677236769Sobrien Var_ExportVars(); 1678236769Sobrien 1679236769Sobrien (void)execv(shellPath, UNCONST(args)); 1680236769Sobrien _exit(1); 1681236769Sobrien /*NOTREACHED*/ 1682236769Sobrien 1683236769Sobrien case -1: 1684236769Sobrien *errnum = "Couldn't exec \"%s\""; 1685236769Sobrien goto bad; 1686236769Sobrien 1687236769Sobrien default: 1688236769Sobrien /* 1689236769Sobrien * No need for the writing half 1690236769Sobrien */ 1691236769Sobrien (void)close(fds[1]); 1692236769Sobrien 1693281812Ssjg savederr = 0; 1694236769Sobrien Buf_Init(&buf, 0); 1695236769Sobrien 1696236769Sobrien do { 1697236769Sobrien char result[BUFSIZ]; 1698236769Sobrien cc = read(fds[0], result, sizeof(result)); 1699236769Sobrien if (cc > 0) 1700236769Sobrien Buf_AddBytes(&buf, cc, result); 1701236769Sobrien } 1702236769Sobrien while (cc > 0 || (cc == -1 && errno == EINTR)); 1703281812Ssjg if (cc == -1) 1704281812Ssjg savederr = errno; 1705236769Sobrien 1706236769Sobrien /* 1707236769Sobrien * Close the input side of the pipe. 1708236769Sobrien */ 1709236769Sobrien (void)close(fds[0]); 1710236769Sobrien 1711236769Sobrien /* 1712236769Sobrien * Wait for the process to exit. 1713236769Sobrien */ 1714236769Sobrien while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1715236769Sobrien JobReapChild(pid, status, FALSE); 1716236769Sobrien continue; 1717236769Sobrien } 1718236769Sobrien cc = Buf_Size(&buf); 1719236769Sobrien res = Buf_Destroy(&buf, FALSE); 1720236769Sobrien 1721281812Ssjg if (savederr != 0) 1722236769Sobrien *errnum = "Couldn't read shell's output for \"%s\""; 1723236769Sobrien 1724236769Sobrien if (WIFSIGNALED(status)) 1725236769Sobrien *errnum = "\"%s\" exited on a signal"; 1726236769Sobrien else if (WEXITSTATUS(status) != 0) 1727236769Sobrien *errnum = "\"%s\" returned non-zero status"; 1728236769Sobrien 1729236769Sobrien /* 1730236769Sobrien * Null-terminate the result, convert newlines to spaces and 1731236769Sobrien * install it in the variable. 1732236769Sobrien */ 1733236769Sobrien res[cc] = '\0'; 1734236769Sobrien cp = &res[cc]; 1735236769Sobrien 1736236769Sobrien if (cc > 0 && *--cp == '\n') { 1737236769Sobrien /* 1738236769Sobrien * A final newline is just stripped 1739236769Sobrien */ 1740236769Sobrien *cp-- = '\0'; 1741236769Sobrien } 1742236769Sobrien while (cp >= res) { 1743236769Sobrien if (*cp == '\n') { 1744236769Sobrien *cp = ' '; 1745236769Sobrien } 1746236769Sobrien cp--; 1747236769Sobrien } 1748236769Sobrien break; 1749236769Sobrien } 1750236769Sobrien return res; 1751236769Sobrienbad: 1752236769Sobrien res = bmake_malloc(1); 1753236769Sobrien *res = '\0'; 1754236769Sobrien return res; 1755236769Sobrien} 1756236769Sobrien 1757236769Sobrien/*- 1758236769Sobrien * Error -- 1759236769Sobrien * Print an error message given its format. 1760236769Sobrien * 1761236769Sobrien * Results: 1762236769Sobrien * None. 1763236769Sobrien * 1764236769Sobrien * Side Effects: 1765236769Sobrien * The message is printed. 1766236769Sobrien */ 1767236769Sobrien/* VARARGS */ 1768236769Sobrienvoid 1769236769SobrienError(const char *fmt, ...) 1770236769Sobrien{ 1771236769Sobrien va_list ap; 1772236769Sobrien FILE *err_file; 1773236769Sobrien 1774236769Sobrien err_file = debug_file; 1775236769Sobrien if (err_file == stdout) 1776236769Sobrien err_file = stderr; 1777236769Sobrien (void)fflush(stdout); 1778236769Sobrien for (;;) { 1779236769Sobrien va_start(ap, fmt); 1780236769Sobrien fprintf(err_file, "%s: ", progname); 1781236769Sobrien (void)vfprintf(err_file, fmt, ap); 1782236769Sobrien va_end(ap); 1783236769Sobrien (void)fprintf(err_file, "\n"); 1784236769Sobrien (void)fflush(err_file); 1785236769Sobrien if (err_file == stderr) 1786236769Sobrien break; 1787236769Sobrien err_file = stderr; 1788236769Sobrien } 1789236769Sobrien} 1790236769Sobrien 1791236769Sobrien/*- 1792236769Sobrien * Fatal -- 1793236769Sobrien * Produce a Fatal error message. If jobs are running, waits for them 1794236769Sobrien * to finish. 1795236769Sobrien * 1796236769Sobrien * Results: 1797236769Sobrien * None 1798236769Sobrien * 1799236769Sobrien * Side Effects: 1800236769Sobrien * The program exits 1801236769Sobrien */ 1802236769Sobrien/* VARARGS */ 1803236769Sobrienvoid 1804236769SobrienFatal(const char *fmt, ...) 1805236769Sobrien{ 1806236769Sobrien va_list ap; 1807236769Sobrien 1808236769Sobrien va_start(ap, fmt); 1809236769Sobrien if (jobsRunning) 1810236769Sobrien Job_Wait(); 1811236769Sobrien 1812236769Sobrien (void)fflush(stdout); 1813236769Sobrien (void)vfprintf(stderr, fmt, ap); 1814236769Sobrien va_end(ap); 1815236769Sobrien (void)fprintf(stderr, "\n"); 1816236769Sobrien (void)fflush(stderr); 1817236769Sobrien 1818236769Sobrien PrintOnError(NULL, NULL); 1819236769Sobrien 1820236769Sobrien if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1821236769Sobrien Targ_PrintGraph(2); 1822236769Sobrien Trace_Log(MAKEERROR, 0); 1823236769Sobrien exit(2); /* Not 1 so -q can distinguish error */ 1824236769Sobrien} 1825236769Sobrien 1826236769Sobrien/* 1827236769Sobrien * Punt -- 1828236769Sobrien * Major exception once jobs are being created. Kills all jobs, prints 1829236769Sobrien * a message and exits. 1830236769Sobrien * 1831236769Sobrien * Results: 1832236769Sobrien * None 1833236769Sobrien * 1834236769Sobrien * Side Effects: 1835236769Sobrien * All children are killed indiscriminately and the program Lib_Exits 1836236769Sobrien */ 1837236769Sobrien/* VARARGS */ 1838236769Sobrienvoid 1839236769SobrienPunt(const char *fmt, ...) 1840236769Sobrien{ 1841236769Sobrien va_list ap; 1842236769Sobrien 1843236769Sobrien va_start(ap, fmt); 1844236769Sobrien (void)fflush(stdout); 1845236769Sobrien (void)fprintf(stderr, "%s: ", progname); 1846236769Sobrien (void)vfprintf(stderr, fmt, ap); 1847236769Sobrien va_end(ap); 1848236769Sobrien (void)fprintf(stderr, "\n"); 1849236769Sobrien (void)fflush(stderr); 1850236769Sobrien 1851236769Sobrien PrintOnError(NULL, NULL); 1852236769Sobrien 1853236769Sobrien DieHorribly(); 1854236769Sobrien} 1855236769Sobrien 1856236769Sobrien/*- 1857236769Sobrien * DieHorribly -- 1858236769Sobrien * Exit without giving a message. 1859236769Sobrien * 1860236769Sobrien * Results: 1861236769Sobrien * None 1862236769Sobrien * 1863236769Sobrien * Side Effects: 1864236769Sobrien * A big one... 1865236769Sobrien */ 1866236769Sobrienvoid 1867236769SobrienDieHorribly(void) 1868236769Sobrien{ 1869236769Sobrien if (jobsRunning) 1870236769Sobrien Job_AbortAll(); 1871236769Sobrien if (DEBUG(GRAPH2)) 1872236769Sobrien Targ_PrintGraph(2); 1873236769Sobrien Trace_Log(MAKEERROR, 0); 1874236769Sobrien exit(2); /* Not 1, so -q can distinguish error */ 1875236769Sobrien} 1876236769Sobrien 1877236769Sobrien/* 1878236769Sobrien * Finish -- 1879236769Sobrien * Called when aborting due to errors in child shell to signal 1880236769Sobrien * abnormal exit. 1881236769Sobrien * 1882236769Sobrien * Results: 1883236769Sobrien * None 1884236769Sobrien * 1885236769Sobrien * Side Effects: 1886236769Sobrien * The program exits 1887236769Sobrien */ 1888236769Sobrienvoid 1889236769SobrienFinish(int errors) 1890236769Sobrien /* number of errors encountered in Make_Make */ 1891236769Sobrien{ 1892236769Sobrien Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1893236769Sobrien} 1894236769Sobrien 1895236769Sobrien/* 1896249033Ssjg * eunlink -- 1897236769Sobrien * Remove a file carefully, avoiding directories. 1898236769Sobrien */ 1899236769Sobrienint 1900236769Sobrieneunlink(const char *file) 1901236769Sobrien{ 1902236769Sobrien struct stat st; 1903236769Sobrien 1904236769Sobrien if (lstat(file, &st) == -1) 1905236769Sobrien return -1; 1906236769Sobrien 1907236769Sobrien if (S_ISDIR(st.st_mode)) { 1908236769Sobrien errno = EISDIR; 1909236769Sobrien return -1; 1910236769Sobrien } 1911236769Sobrien return unlink(file); 1912236769Sobrien} 1913236769Sobrien 1914236769Sobrien/* 1915236769Sobrien * execError -- 1916236769Sobrien * Print why exec failed, avoiding stdio. 1917236769Sobrien */ 1918236769Sobrienvoid 1919236769SobrienexecError(const char *af, const char *av) 1920236769Sobrien{ 1921236769Sobrien#ifdef USE_IOVEC 1922236769Sobrien int i = 0; 1923236769Sobrien struct iovec iov[8]; 1924236769Sobrien#define IOADD(s) \ 1925236769Sobrien (void)(iov[i].iov_base = UNCONST(s), \ 1926236769Sobrien iov[i].iov_len = strlen(iov[i].iov_base), \ 1927236769Sobrien i++) 1928236769Sobrien#else 1929236769Sobrien#define IOADD(s) (void)write(2, s, strlen(s)) 1930236769Sobrien#endif 1931236769Sobrien 1932236769Sobrien IOADD(progname); 1933236769Sobrien IOADD(": "); 1934236769Sobrien IOADD(af); 1935236769Sobrien IOADD("("); 1936236769Sobrien IOADD(av); 1937236769Sobrien IOADD(") failed ("); 1938236769Sobrien IOADD(strerror(errno)); 1939236769Sobrien IOADD(")\n"); 1940236769Sobrien 1941236769Sobrien#ifdef USE_IOVEC 1942246223Ssjg while (writev(2, iov, 8) == -1 && errno == EAGAIN) 1943246223Ssjg continue; 1944236769Sobrien#endif 1945236769Sobrien} 1946236769Sobrien 1947236769Sobrien/* 1948236769Sobrien * usage -- 1949236769Sobrien * exit with usage message 1950236769Sobrien */ 1951236769Sobrienstatic void 1952236769Sobrienusage(void) 1953236769Sobrien{ 1954253883Ssjg char *p; 1955253883Ssjg if ((p = strchr(progname, '[')) != NULL) 1956253883Ssjg *p = '\0'; 1957253883Ssjg 1958236769Sobrien (void)fprintf(stderr, 1959253883Ssjg"usage: %s [-BeikNnqrstWwX] \n\ 1960236769Sobrien [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 1961236769Sobrien [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1962321653Ssjg [-V variable] [-v variable] [variable=value] [target ...]\n", 1963321653Ssjg progname); 1964236769Sobrien exit(2); 1965236769Sobrien} 1966236769Sobrien 1967301462Ssjg/* 1968301462Ssjg * realpath(3) can get expensive, cache results... 1969301462Ssjg */ 1970319884Ssjgstatic GNode *cached_realpaths = NULL; 1971319884Ssjg 1972319884Ssjgstatic GNode * 1973319884Ssjgget_cached_realpaths(void) 1974319884Ssjg{ 1975319884Ssjg 1976319884Ssjg if (!cached_realpaths) { 1977319884Ssjg cached_realpaths = Targ_NewGN("Realpath"); 1978319884Ssjg#ifndef DEBUG_REALPATH_CACHE 1979319884Ssjg cached_realpaths->flags = INTERNAL; 1980319884Ssjg#endif 1981319884Ssjg } 1982319884Ssjg 1983319884Ssjg return cached_realpaths; 1984319884Ssjg} 1985319884Ssjg 1986319884Ssjg/* purge any relative paths */ 1987319884Ssjgstatic void 1988319884Ssjgpurge_cached_realpaths(void) 1989319884Ssjg{ 1990319884Ssjg GNode *cache = get_cached_realpaths(); 1991319884Ssjg Hash_Entry *he, *nhe; 1992319884Ssjg Hash_Search hs; 1993319884Ssjg 1994319884Ssjg he = Hash_EnumFirst(&cache->context, &hs); 1995319884Ssjg while (he) { 1996319884Ssjg nhe = Hash_EnumNext(&hs); 1997319884Ssjg if (he->name[0] != '/') { 1998319884Ssjg if (DEBUG(DIR)) 1999319884Ssjg fprintf(stderr, "cached_realpath: purging %s\n", he->name); 2000319884Ssjg Hash_DeleteEntry(&cache->context, he); 2001319884Ssjg } 2002319884Ssjg he = nhe; 2003319884Ssjg } 2004319884Ssjg} 2005319884Ssjg 2006301462Ssjgchar * 2007301462Ssjgcached_realpath(const char *pathname, char *resolved) 2008301462Ssjg{ 2009319884Ssjg GNode *cache; 2010301462Ssjg char *rp, *cp; 2011301462Ssjg 2012301462Ssjg if (!pathname || !pathname[0]) 2013301462Ssjg return NULL; 2014301462Ssjg 2015319884Ssjg cache = get_cached_realpaths(); 2016301462Ssjg 2017319884Ssjg if ((rp = Var_Value(pathname, cache, &cp)) != NULL) { 2018301462Ssjg /* a hit */ 2019301665Ssjg strlcpy(resolved, rp, MAXPATHLEN); 2020319884Ssjg } else if ((rp = realpath(pathname, resolved)) != NULL) { 2021301665Ssjg Var_Set(pathname, rp, cache, 0); 2022301462Ssjg } 2023301665Ssjg free(cp); 2024301462Ssjg return rp ? resolved : NULL; 2025301462Ssjg} 2026301462Ssjg 2027236769Sobrienint 2028236769SobrienPrintAddr(void *a, void *b) 2029236769Sobrien{ 2030236769Sobrien printf("%lx ", (unsigned long) a); 2031236769Sobrien return b ? 0 : 0; 2032236769Sobrien} 2033236769Sobrien 2034236769Sobrien 2035319884Ssjgstatic int 2036319884SsjgaddErrorCMD(void *cmdp, void *gnp MAKE_ATTR_UNUSED) 2037319884Ssjg{ 2038319884Ssjg if (cmdp == NULL) 2039319884Ssjg return 1; /* stop */ 2040319884Ssjg Var_Append(".ERROR_CMD", cmdp, VAR_GLOBAL); 2041319884Ssjg return 0; 2042319884Ssjg} 2043236769Sobrien 2044236769Sobrienvoid 2045236769SobrienPrintOnError(GNode *gn, const char *s) 2046236769Sobrien{ 2047236769Sobrien static GNode *en = NULL; 2048236769Sobrien char tmp[64]; 2049236769Sobrien char *cp; 2050236769Sobrien 2051236769Sobrien if (s) 2052236769Sobrien printf("%s", s); 2053236769Sobrien 2054236769Sobrien printf("\n%s: stopped in %s\n", progname, curdir); 2055236769Sobrien 2056236769Sobrien if (en) 2057236769Sobrien return; /* we've been here! */ 2058236769Sobrien if (gn) { 2059236769Sobrien /* 2060236769Sobrien * We can print this even if there is no .ERROR target. 2061236769Sobrien */ 2062236769Sobrien Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 2063319884Ssjg Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2064319884Ssjg Lst_ForEach(gn->commands, addErrorCMD, gn); 2065236769Sobrien } 2066236769Sobrien strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 2067236769Sobrien sizeof(tmp) - 1); 2068296637Ssjg cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); 2069236769Sobrien if (cp) { 2070236769Sobrien if (*cp) 2071236769Sobrien printf("%s", cp); 2072236769Sobrien free(cp); 2073236769Sobrien } 2074291978Ssjg fflush(stdout); 2075291978Ssjg 2076236769Sobrien /* 2077236769Sobrien * Finally, see if there is a .ERROR target, and run it if so. 2078236769Sobrien */ 2079236769Sobrien en = Targ_FindNode(".ERROR", TARG_NOCREATE); 2080236769Sobrien if (en) { 2081236769Sobrien en->type |= OP_SPECIAL; 2082236769Sobrien Compat_Make(en, en); 2083236769Sobrien } 2084236769Sobrien} 2085236769Sobrien 2086236769Sobrienvoid 2087236769SobrienMain_ExportMAKEFLAGS(Boolean first) 2088236769Sobrien{ 2089236769Sobrien static int once = 1; 2090236769Sobrien char tmp[64]; 2091236769Sobrien char *s; 2092236769Sobrien 2093236769Sobrien if (once != first) 2094236769Sobrien return; 2095236769Sobrien once = 0; 2096236769Sobrien 2097236769Sobrien strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 2098236769Sobrien sizeof(tmp)); 2099296637Ssjg s = Var_Subst(NULL, tmp, VAR_CMD, VARF_WANTRES); 2100236769Sobrien if (s && *s) { 2101236769Sobrien#ifdef POSIX 2102236769Sobrien setenv("MAKEFLAGS", s, 1); 2103236769Sobrien#else 2104236769Sobrien setenv("MAKE", s, 1); 2105236769Sobrien#endif 2106236769Sobrien } 2107236769Sobrien} 2108236769Sobrien 2109236769Sobrienchar * 2110236769SobriengetTmpdir(void) 2111236769Sobrien{ 2112236769Sobrien static char *tmpdir = NULL; 2113236769Sobrien 2114236769Sobrien if (!tmpdir) { 2115236769Sobrien struct stat st; 2116236769Sobrien 2117236769Sobrien /* 2118236769Sobrien * Honor $TMPDIR but only if it is valid. 2119236769Sobrien * Ensure it ends with /. 2120236769Sobrien */ 2121289842Ssjg tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 2122296637Ssjg VARF_WANTRES); 2123236769Sobrien if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2124236769Sobrien free(tmpdir); 2125236769Sobrien tmpdir = bmake_strdup(_PATH_TMP); 2126236769Sobrien } 2127236769Sobrien } 2128236769Sobrien return tmpdir; 2129236769Sobrien} 2130236769Sobrien 2131236769Sobrien/* 2132236769Sobrien * Create and open a temp file using "pattern". 2133236769Sobrien * If "fnamep" is provided set it to a copy of the filename created. 2134236769Sobrien * Otherwise unlink the file once open. 2135236769Sobrien */ 2136236769Sobrienint 2137236769SobrienmkTempFile(const char *pattern, char **fnamep) 2138236769Sobrien{ 2139236769Sobrien static char *tmpdir = NULL; 2140236769Sobrien char tfile[MAXPATHLEN]; 2141236769Sobrien int fd; 2142236769Sobrien 2143236769Sobrien if (!pattern) 2144236769Sobrien pattern = TMPPAT; 2145236769Sobrien if (!tmpdir) 2146236769Sobrien tmpdir = getTmpdir(); 2147236769Sobrien if (pattern[0] == '/') { 2148236769Sobrien snprintf(tfile, sizeof(tfile), "%s", pattern); 2149236769Sobrien } else { 2150236769Sobrien snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2151236769Sobrien } 2152236769Sobrien if ((fd = mkstemp(tfile)) < 0) 2153236769Sobrien Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2154236769Sobrien if (fnamep) { 2155236769Sobrien *fnamep = bmake_strdup(tfile); 2156236769Sobrien } else { 2157236769Sobrien unlink(tfile); /* we just want the descriptor */ 2158236769Sobrien } 2159236769Sobrien return fd; 2160236769Sobrien} 2161240330Smarcel 2162296637Ssjg/* 2163296637Ssjg * Convert a string representation of a boolean. 2164296637Ssjg * Anything that looks like "No", "False", "Off", "0" etc, 2165296637Ssjg * is FALSE, otherwise TRUE. 2166296637Ssjg */ 2167296637SsjgBoolean 2168296637Ssjgs2Boolean(const char *s, Boolean bf) 2169296637Ssjg{ 2170296637Ssjg if (s) { 2171296637Ssjg switch(*s) { 2172296637Ssjg case '\0': /* not set - the default wins */ 2173296637Ssjg break; 2174296637Ssjg case '0': 2175296637Ssjg case 'F': 2176296637Ssjg case 'f': 2177296637Ssjg case 'N': 2178296637Ssjg case 'n': 2179296637Ssjg bf = FALSE; 2180296637Ssjg break; 2181296637Ssjg case 'O': 2182296637Ssjg case 'o': 2183296637Ssjg switch (s[1]) { 2184296637Ssjg case 'F': 2185296637Ssjg case 'f': 2186296637Ssjg bf = FALSE; 2187296637Ssjg break; 2188296637Ssjg default: 2189296637Ssjg bf = TRUE; 2190296637Ssjg break; 2191296637Ssjg } 2192296637Ssjg break; 2193296637Ssjg default: 2194296637Ssjg bf = TRUE; 2195296637Ssjg break; 2196296637Ssjg } 2197296637Ssjg } 2198296637Ssjg return (bf); 2199296637Ssjg} 2200240330Smarcel 2201240330Smarcel/* 2202240330Smarcel * Return a Boolean based on setting of a knob. 2203240330Smarcel * 2204240330Smarcel * If the knob is not set, the supplied default is the return value. 2205240330Smarcel * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 2206240330Smarcel * is FALSE, otherwise TRUE. 2207240330Smarcel */ 2208240330SmarcelBoolean 2209240330SmarcelgetBoolean(const char *name, Boolean bf) 2210240330Smarcel{ 2211240330Smarcel char tmp[64]; 2212240330Smarcel char *cp; 2213240330Smarcel 2214296637Ssjg if (snprintf(tmp, sizeof(tmp), "${%s:U:tl}", name) < (int)(sizeof(tmp))) { 2215296637Ssjg cp = Var_Subst(NULL, tmp, VAR_GLOBAL, VARF_WANTRES); 2216240330Smarcel 2217240330Smarcel if (cp) { 2218296637Ssjg bf = s2Boolean(cp, bf); 2219240330Smarcel free(cp); 2220240330Smarcel } 2221240330Smarcel } 2222240330Smarcel return (bf); 2223240330Smarcel} 2224