1255253Ssjg/* $NetBSD: main.c,v 1.224 2013/09/04 15:38:26 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 72255253Ssjgstatic char rcsid[] = "$NetBSD: main.c,v 1.224 2013/09/04 15:38:26 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 84255253Ssjg__RCSID("$NetBSD: main.c,v 1.224 2013/09/04 15:38:26 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 102236769Sobrien * takes a format string and two optional 103236769Sobrien * arguments for it. 104236769Sobrien * 105236769Sobrien * Fatal Print an error message and exit. Also takes 106236769Sobrien * a format string and two arguments. 107236769Sobrien * 108236769Sobrien * Punt Aborts all jobs and exits with a message. Also 109236769Sobrien * takes a format string and two arguments. 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> 121236769Sobrien#include <sys/utsname.h> 122236769Sobrien#include "wait.h" 123236769Sobrien 124236769Sobrien#include <errno.h> 125236769Sobrien#include <fcntl.h> 126253883Ssjg#include <signal.h> 127236769Sobrien#include <stdarg.h> 128236769Sobrien#include <stdio.h> 129236769Sobrien#include <stdlib.h> 130236769Sobrien#include <time.h> 131253883Ssjg#include <ctype.h> 132236769Sobrien 133236769Sobrien#include "make.h" 134236769Sobrien#include "hash.h" 135236769Sobrien#include "dir.h" 136236769Sobrien#include "job.h" 137236769Sobrien#include "pathnames.h" 138236769Sobrien#include "trace.h" 139236769Sobrien 140236769Sobrien#ifdef USE_IOVEC 141236769Sobrien#include <sys/uio.h> 142236769Sobrien#endif 143236769Sobrien 144236769Sobrien#ifndef DEFMAXLOCAL 145236769Sobrien#define DEFMAXLOCAL DEFMAXJOBS 146236769Sobrien#endif /* DEFMAXLOCAL */ 147236769Sobrien 148236769SobrienLst create; /* Targets to be made */ 149236769Sobrientime_t now; /* Time at start of make */ 150236769SobrienGNode *DEFAULT; /* .DEFAULT node */ 151236769SobrienBoolean allPrecious; /* .PRECIOUS given on line by itself */ 152236769Sobrien 153236769Sobrienstatic Boolean noBuiltins; /* -r flag */ 154236769Sobrienstatic Lst makefiles; /* ordered list of makefiles to read */ 155236769Sobrienstatic Boolean printVars; /* print value of one or more vars */ 156236769Sobrienstatic Lst variables; /* list of variables to print */ 157236769Sobrienint maxJobs; /* -j argument */ 158236769Sobrienstatic int maxJobTokens; /* -j argument */ 159236769SobrienBoolean compatMake; /* -B argument */ 160236769Sobrienint debug; /* -d argument */ 161240330SmarcelBoolean debugVflag; /* -dV */ 162236769SobrienBoolean noExecute; /* -n flag */ 163236769SobrienBoolean noRecursiveExecute; /* -N flag */ 164236769SobrienBoolean keepgoing; /* -k flag */ 165236769SobrienBoolean queryFlag; /* -q flag */ 166236769SobrienBoolean touchFlag; /* -t flag */ 167253883SsjgBoolean enterFlag; /* -w flag */ 168236769SobrienBoolean ignoreErrors; /* -i flag */ 169236769SobrienBoolean beSilent; /* -s flag */ 170236769SobrienBoolean oldVars; /* variable substitution style */ 171236769SobrienBoolean checkEnvFirst; /* -e flag */ 172236769SobrienBoolean parseWarnFatal; /* -W flag */ 173236769SobrienBoolean jobServer; /* -J flag */ 174236769Sobrienstatic int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 175236769SobrienBoolean varNoExportEnv; /* -X flag */ 176236769SobrienBoolean doing_depend; /* Set while reading .depend */ 177236769Sobrienstatic Boolean jobsRunning; /* TRUE if the jobs might be running */ 178236769Sobrienstatic const char * tracefile; 179236769Sobrienstatic void MainParseArgs(int, char **); 180236769Sobrienstatic int ReadMakefile(const void *, const void *); 181237578Sobrienstatic void usage(void) MAKE_ATTR_DEAD; 182236769Sobrien 183236769Sobrienstatic Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 184236769Sobrienstatic char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 185236769Sobrienchar curdir[MAXPATHLEN + 1]; /* Startup directory */ 186236769Sobrienchar *progname; /* the program name */ 187236769Sobrienchar *makeDependfile; 188236769Sobrienpid_t myPid; 189253883Ssjgint makelevel; 190236769Sobrien 191236769SobrienBoolean forceJobs = FALSE; 192236769Sobrien 193236769Sobrien/* 194236769Sobrien * On some systems MACHINE is defined as something other than 195236769Sobrien * what we want. 196236769Sobrien */ 197236769Sobrien#ifdef FORCE_MACHINE 198236769Sobrien# undef MACHINE 199236769Sobrien# define MACHINE FORCE_MACHINE 200236769Sobrien#endif 201236769Sobrien 202236769Sobrienextern Lst parseIncPath; 203236769Sobrien 204253883Ssjg/* 205253883Ssjg * For compatibility with the POSIX version of MAKEFLAGS that includes 206253883Ssjg * all the options with out -, convert flags to -f -l -a -g -s. 207253883Ssjg */ 208253883Ssjgstatic char * 209253883Ssjgexplode(const char *flags) 210253883Ssjg{ 211253883Ssjg size_t len; 212253883Ssjg char *nf, *st; 213253883Ssjg const char *f; 214253883Ssjg 215253883Ssjg if (flags == NULL) 216253883Ssjg return NULL; 217253883Ssjg 218253883Ssjg for (f = flags; *f; f++) 219253883Ssjg if (!isalpha((unsigned char)*f)) 220253883Ssjg break; 221253883Ssjg 222253883Ssjg if (*f) 223253883Ssjg return bmake_strdup(flags); 224253883Ssjg 225253883Ssjg len = strlen(flags); 226253883Ssjg st = nf = bmake_malloc(len * 3 + 1); 227253883Ssjg while (*flags) { 228253883Ssjg *nf++ = '-'; 229253883Ssjg *nf++ = *flags++; 230253883Ssjg *nf++ = ' '; 231253883Ssjg } 232253883Ssjg *nf = '\0'; 233253883Ssjg return st; 234253883Ssjg} 235253883Ssjg 236236769Sobrienstatic void 237236769Sobrienparse_debug_options(const char *argvalue) 238236769Sobrien{ 239236769Sobrien const char *modules; 240236769Sobrien const char *mode; 241236769Sobrien char *fname; 242236769Sobrien int len; 243236769Sobrien 244236769Sobrien for (modules = argvalue; *modules; ++modules) { 245236769Sobrien switch (*modules) { 246236769Sobrien case 'A': 247236769Sobrien debug = ~0; 248236769Sobrien break; 249236769Sobrien case 'a': 250236769Sobrien debug |= DEBUG_ARCH; 251236769Sobrien break; 252236769Sobrien case 'C': 253236769Sobrien debug |= DEBUG_CWD; 254236769Sobrien break; 255236769Sobrien case 'c': 256236769Sobrien debug |= DEBUG_COND; 257236769Sobrien break; 258236769Sobrien case 'd': 259236769Sobrien debug |= DEBUG_DIR; 260236769Sobrien break; 261236769Sobrien case 'e': 262236769Sobrien debug |= DEBUG_ERROR; 263236769Sobrien break; 264236769Sobrien case 'f': 265236769Sobrien debug |= DEBUG_FOR; 266236769Sobrien break; 267236769Sobrien case 'g': 268236769Sobrien if (modules[1] == '1') { 269236769Sobrien debug |= DEBUG_GRAPH1; 270236769Sobrien ++modules; 271236769Sobrien } 272236769Sobrien else if (modules[1] == '2') { 273236769Sobrien debug |= DEBUG_GRAPH2; 274236769Sobrien ++modules; 275236769Sobrien } 276236769Sobrien else if (modules[1] == '3') { 277236769Sobrien debug |= DEBUG_GRAPH3; 278236769Sobrien ++modules; 279236769Sobrien } 280236769Sobrien break; 281236769Sobrien case 'j': 282236769Sobrien debug |= DEBUG_JOB; 283236769Sobrien break; 284236769Sobrien case 'l': 285236769Sobrien debug |= DEBUG_LOUD; 286236769Sobrien break; 287236769Sobrien case 'M': 288236769Sobrien debug |= DEBUG_META; 289236769Sobrien break; 290236769Sobrien case 'm': 291236769Sobrien debug |= DEBUG_MAKE; 292236769Sobrien break; 293236769Sobrien case 'n': 294236769Sobrien debug |= DEBUG_SCRIPT; 295236769Sobrien break; 296236769Sobrien case 'p': 297236769Sobrien debug |= DEBUG_PARSE; 298236769Sobrien break; 299236769Sobrien case 's': 300236769Sobrien debug |= DEBUG_SUFF; 301236769Sobrien break; 302236769Sobrien case 't': 303236769Sobrien debug |= DEBUG_TARG; 304236769Sobrien break; 305240330Smarcel case 'V': 306240330Smarcel debugVflag = TRUE; 307240330Smarcel break; 308236769Sobrien case 'v': 309236769Sobrien debug |= DEBUG_VAR; 310236769Sobrien break; 311236769Sobrien case 'x': 312236769Sobrien debug |= DEBUG_SHELL; 313236769Sobrien break; 314236769Sobrien case 'F': 315236769Sobrien if (debug_file != stdout && debug_file != stderr) 316236769Sobrien fclose(debug_file); 317236769Sobrien if (*++modules == '+') { 318236769Sobrien modules++; 319236769Sobrien mode = "a"; 320236769Sobrien } else 321236769Sobrien mode = "w"; 322236769Sobrien if (strcmp(modules, "stdout") == 0) { 323236769Sobrien debug_file = stdout; 324236769Sobrien goto debug_setbuf; 325236769Sobrien } 326236769Sobrien if (strcmp(modules, "stderr") == 0) { 327236769Sobrien debug_file = stderr; 328236769Sobrien goto debug_setbuf; 329236769Sobrien } 330236769Sobrien len = strlen(modules); 331236769Sobrien fname = malloc(len + 20); 332236769Sobrien memcpy(fname, modules, len + 1); 333236769Sobrien /* Let the filename be modified by the pid */ 334236769Sobrien if (strcmp(fname + len - 3, ".%d") == 0) 335236769Sobrien snprintf(fname + len - 2, 20, "%d", getpid()); 336236769Sobrien debug_file = fopen(fname, mode); 337236769Sobrien if (!debug_file) { 338236769Sobrien fprintf(stderr, "Cannot open debug file %s\n", 339236769Sobrien fname); 340236769Sobrien usage(); 341236769Sobrien } 342236769Sobrien free(fname); 343236769Sobrien goto debug_setbuf; 344236769Sobrien default: 345236769Sobrien (void)fprintf(stderr, 346236769Sobrien "%s: illegal argument to d option -- %c\n", 347236769Sobrien progname, *modules); 348236769Sobrien usage(); 349236769Sobrien } 350236769Sobrien } 351236769Sobriendebug_setbuf: 352236769Sobrien /* 353236769Sobrien * Make the debug_file unbuffered, and make 354236769Sobrien * stdout line buffered (unless debugfile == stdout). 355236769Sobrien */ 356236769Sobrien setvbuf(debug_file, NULL, _IONBF, 0); 357236769Sobrien if (debug_file != stdout) { 358236769Sobrien setvbuf(stdout, NULL, _IOLBF, 0); 359236769Sobrien } 360236769Sobrien} 361236769Sobrien 362236769Sobrien/*- 363236769Sobrien * MainParseArgs -- 364236769Sobrien * Parse a given argument vector. Called from main() and from 365236769Sobrien * Main_ParseArgLine() when the .MAKEFLAGS target is used. 366236769Sobrien * 367236769Sobrien * XXX: Deal with command line overriding .MAKEFLAGS in makefile 368236769Sobrien * 369236769Sobrien * Results: 370236769Sobrien * None 371236769Sobrien * 372236769Sobrien * Side Effects: 373236769Sobrien * Various global and local flags will be set depending on the flags 374236769Sobrien * given 375236769Sobrien */ 376236769Sobrienstatic void 377236769SobrienMainParseArgs(int argc, char **argv) 378236769Sobrien{ 379236769Sobrien char *p; 380236769Sobrien int c = '?'; 381236769Sobrien int arginc; 382236769Sobrien char *argvalue; 383236769Sobrien const char *getopt_def; 384236769Sobrien char *optscan; 385236769Sobrien Boolean inOption, dashDash = FALSE; 386236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 387236769Sobrien 388253883Ssjg#define OPTFLAGS "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstw" 389236769Sobrien/* Can't actually use getopt(3) because rescanning is not portable */ 390236769Sobrien 391236769Sobrien getopt_def = OPTFLAGS; 392236769Sobrienrearg: 393236769Sobrien inOption = FALSE; 394236769Sobrien optscan = NULL; 395236769Sobrien while(argc > 1) { 396236769Sobrien char *getopt_spec; 397236769Sobrien if(!inOption) 398236769Sobrien optscan = argv[1]; 399236769Sobrien c = *optscan++; 400236769Sobrien arginc = 0; 401236769Sobrien if(inOption) { 402236769Sobrien if(c == '\0') { 403236769Sobrien ++argv; 404236769Sobrien --argc; 405236769Sobrien inOption = FALSE; 406236769Sobrien continue; 407236769Sobrien } 408236769Sobrien } else { 409236769Sobrien if (c != '-' || dashDash) 410236769Sobrien break; 411236769Sobrien inOption = TRUE; 412236769Sobrien c = *optscan++; 413236769Sobrien } 414236769Sobrien /* '-' found at some earlier point */ 415236769Sobrien getopt_spec = strchr(getopt_def, c); 416236769Sobrien if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 417236769Sobrien /* -<something> found, and <something> should have an arg */ 418236769Sobrien inOption = FALSE; 419236769Sobrien arginc = 1; 420236769Sobrien argvalue = optscan; 421236769Sobrien if(*argvalue == '\0') { 422236769Sobrien if (argc < 3) 423236769Sobrien goto noarg; 424236769Sobrien argvalue = argv[2]; 425236769Sobrien arginc = 2; 426236769Sobrien } 427236769Sobrien } else { 428236769Sobrien argvalue = NULL; 429236769Sobrien } 430236769Sobrien switch(c) { 431236769Sobrien case '\0': 432236769Sobrien arginc = 1; 433236769Sobrien inOption = FALSE; 434236769Sobrien break; 435236769Sobrien case 'B': 436236769Sobrien compatMake = TRUE; 437236769Sobrien Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 438236769Sobrien Var_Set(MAKE_MODE, "compat", VAR_GLOBAL, 0); 439236769Sobrien break; 440236769Sobrien case 'C': 441236769Sobrien if (chdir(argvalue) == -1) { 442236769Sobrien (void)fprintf(stderr, 443236769Sobrien "%s: chdir %s: %s\n", 444236769Sobrien progname, argvalue, 445236769Sobrien strerror(errno)); 446236769Sobrien exit(1); 447236769Sobrien } 448236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 449236769Sobrien (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 450236769Sobrien exit(2); 451236769Sobrien } 452236769Sobrien ignorePWD = TRUE; 453236769Sobrien break; 454236769Sobrien case 'D': 455236769Sobrien if (argvalue == NULL || argvalue[0] == 0) goto noarg; 456236769Sobrien Var_Set(argvalue, "1", VAR_GLOBAL, 0); 457236769Sobrien Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 458236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 459236769Sobrien break; 460236769Sobrien case 'I': 461236769Sobrien if (argvalue == NULL) goto noarg; 462236769Sobrien Parse_AddIncludeDir(argvalue); 463236769Sobrien Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 464236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 465236769Sobrien break; 466236769Sobrien case 'J': 467236769Sobrien if (argvalue == NULL) goto noarg; 468236769Sobrien if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 469236769Sobrien (void)fprintf(stderr, 470236769Sobrien "%s: internal error -- J option malformed (%s)\n", 471236769Sobrien progname, argvalue); 472236769Sobrien usage(); 473236769Sobrien } 474236769Sobrien if ((fcntl(jp_0, F_GETFD, 0) < 0) || 475236769Sobrien (fcntl(jp_1, F_GETFD, 0) < 0)) { 476236769Sobrien#if 0 477236769Sobrien (void)fprintf(stderr, 478236769Sobrien "%s: ###### warning -- J descriptors were closed!\n", 479236769Sobrien progname); 480236769Sobrien exit(2); 481236769Sobrien#endif 482236769Sobrien jp_0 = -1; 483236769Sobrien jp_1 = -1; 484236769Sobrien compatMake = TRUE; 485236769Sobrien } else { 486236769Sobrien Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 487236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 488236769Sobrien jobServer = TRUE; 489236769Sobrien } 490236769Sobrien break; 491236769Sobrien case 'N': 492236769Sobrien noExecute = TRUE; 493236769Sobrien noRecursiveExecute = TRUE; 494236769Sobrien Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 495236769Sobrien break; 496236769Sobrien case 'S': 497236769Sobrien keepgoing = FALSE; 498236769Sobrien Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 499236769Sobrien break; 500236769Sobrien case 'T': 501236769Sobrien if (argvalue == NULL) goto noarg; 502236769Sobrien tracefile = bmake_strdup(argvalue); 503236769Sobrien Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 504236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 505236769Sobrien break; 506236769Sobrien case 'V': 507236769Sobrien if (argvalue == NULL) goto noarg; 508236769Sobrien printVars = TRUE; 509236769Sobrien (void)Lst_AtEnd(variables, argvalue); 510236769Sobrien Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 511236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 512236769Sobrien break; 513236769Sobrien case 'W': 514236769Sobrien parseWarnFatal = TRUE; 515236769Sobrien break; 516236769Sobrien case 'X': 517236769Sobrien varNoExportEnv = TRUE; 518236769Sobrien Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 519236769Sobrien break; 520236769Sobrien case 'd': 521236769Sobrien if (argvalue == NULL) goto noarg; 522236769Sobrien /* If '-d-opts' don't pass to children */ 523236769Sobrien if (argvalue[0] == '-') 524236769Sobrien argvalue++; 525236769Sobrien else { 526236769Sobrien Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 527236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 528236769Sobrien } 529236769Sobrien parse_debug_options(argvalue); 530236769Sobrien break; 531236769Sobrien case 'e': 532236769Sobrien checkEnvFirst = TRUE; 533236769Sobrien Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 534236769Sobrien break; 535236769Sobrien case 'f': 536236769Sobrien if (argvalue == NULL) goto noarg; 537236769Sobrien (void)Lst_AtEnd(makefiles, argvalue); 538236769Sobrien break; 539236769Sobrien case 'i': 540236769Sobrien ignoreErrors = TRUE; 541236769Sobrien Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 542236769Sobrien break; 543236769Sobrien case 'j': 544236769Sobrien if (argvalue == NULL) goto noarg; 545236769Sobrien forceJobs = TRUE; 546236769Sobrien maxJobs = strtol(argvalue, &p, 0); 547236769Sobrien if (*p != '\0' || maxJobs < 1) { 548236769Sobrien (void)fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 549236769Sobrien progname); 550236769Sobrien exit(1); 551236769Sobrien } 552236769Sobrien Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 553236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 554236769Sobrien Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL, 0); 555236769Sobrien maxJobTokens = maxJobs; 556236769Sobrien break; 557236769Sobrien case 'k': 558236769Sobrien keepgoing = TRUE; 559236769Sobrien Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 560236769Sobrien break; 561236769Sobrien case 'm': 562236769Sobrien if (argvalue == NULL) goto noarg; 563236769Sobrien /* look for magic parent directory search string */ 564236769Sobrien if (strncmp(".../", argvalue, 4) == 0) { 565236769Sobrien if (!Dir_FindHereOrAbove(curdir, argvalue+4, 566236769Sobrien found_path, sizeof(found_path))) 567236769Sobrien break; /* nothing doing */ 568236769Sobrien (void)Dir_AddDir(sysIncPath, found_path); 569236769Sobrien } else { 570236769Sobrien (void)Dir_AddDir(sysIncPath, argvalue); 571236769Sobrien } 572236769Sobrien Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 573236769Sobrien Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 574236769Sobrien break; 575236769Sobrien case 'n': 576236769Sobrien noExecute = TRUE; 577236769Sobrien Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 578236769Sobrien break; 579236769Sobrien case 'q': 580236769Sobrien queryFlag = TRUE; 581236769Sobrien /* Kind of nonsensical, wot? */ 582236769Sobrien Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 583236769Sobrien break; 584236769Sobrien case 'r': 585236769Sobrien noBuiltins = TRUE; 586236769Sobrien Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 587236769Sobrien break; 588236769Sobrien case 's': 589236769Sobrien beSilent = TRUE; 590236769Sobrien Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 591236769Sobrien break; 592236769Sobrien case 't': 593236769Sobrien touchFlag = TRUE; 594236769Sobrien Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 595236769Sobrien break; 596253883Ssjg case 'w': 597253883Ssjg enterFlag = TRUE; 598253883Ssjg Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 599253883Ssjg break; 600236769Sobrien case '-': 601236769Sobrien dashDash = TRUE; 602236769Sobrien break; 603236769Sobrien default: 604236769Sobrien case '?': 605236769Sobrien#ifndef MAKE_NATIVE 606236769Sobrien fprintf(stderr, "getopt(%s) -> %d (%c)\n", 607236769Sobrien OPTFLAGS, c, c); 608236769Sobrien#endif 609236769Sobrien usage(); 610236769Sobrien } 611236769Sobrien argv += arginc; 612236769Sobrien argc -= arginc; 613236769Sobrien } 614236769Sobrien 615236769Sobrien oldVars = TRUE; 616236769Sobrien 617236769Sobrien /* 618236769Sobrien * See if the rest of the arguments are variable assignments and 619236769Sobrien * perform them if so. Else take them to be targets and stuff them 620236769Sobrien * on the end of the "create" list. 621236769Sobrien */ 622236769Sobrien for (; argc > 1; ++argv, --argc) 623236769Sobrien if (Parse_IsVar(argv[1])) { 624236769Sobrien Parse_DoVar(argv[1], VAR_CMD); 625236769Sobrien } else { 626236769Sobrien if (!*argv[1]) 627236769Sobrien Punt("illegal (null) argument."); 628236769Sobrien if (*argv[1] == '-' && !dashDash) 629236769Sobrien goto rearg; 630236769Sobrien (void)Lst_AtEnd(create, bmake_strdup(argv[1])); 631236769Sobrien } 632236769Sobrien 633236769Sobrien return; 634236769Sobriennoarg: 635236769Sobrien (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 636236769Sobrien progname, c); 637236769Sobrien usage(); 638236769Sobrien} 639236769Sobrien 640236769Sobrien/*- 641236769Sobrien * Main_ParseArgLine -- 642236769Sobrien * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 643236769Sobrien * is encountered and by main() when reading the .MAKEFLAGS envariable. 644236769Sobrien * Takes a line of arguments and breaks it into its 645236769Sobrien * component words and passes those words and the number of them to the 646236769Sobrien * MainParseArgs function. 647236769Sobrien * The line should have all its leading whitespace removed. 648236769Sobrien * 649236769Sobrien * Input: 650236769Sobrien * line Line to fracture 651236769Sobrien * 652236769Sobrien * Results: 653236769Sobrien * None 654236769Sobrien * 655236769Sobrien * Side Effects: 656236769Sobrien * Only those that come from the various arguments. 657236769Sobrien */ 658236769Sobrienvoid 659236769SobrienMain_ParseArgLine(const char *line) 660236769Sobrien{ 661236769Sobrien char **argv; /* Manufactured argument vector */ 662236769Sobrien int argc; /* Number of arguments in argv */ 663236769Sobrien char *args; /* Space used by the args */ 664236769Sobrien char *buf, *p1; 665236769Sobrien char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 666236769Sobrien size_t len; 667236769Sobrien 668236769Sobrien if (line == NULL) 669236769Sobrien return; 670236769Sobrien for (; *line == ' '; ++line) 671236769Sobrien continue; 672236769Sobrien if (!*line) 673236769Sobrien return; 674236769Sobrien 675236769Sobrien#ifndef POSIX 676236769Sobrien { 677236769Sobrien /* 678236769Sobrien * $MAKE may simply be naming the make(1) binary 679236769Sobrien */ 680236769Sobrien char *cp; 681236769Sobrien 682236769Sobrien if (!(cp = strrchr(line, '/'))) 683236769Sobrien cp = line; 684236769Sobrien if ((cp = strstr(cp, "make")) && 685236769Sobrien strcmp(cp, "make") == 0) 686236769Sobrien return; 687236769Sobrien } 688236769Sobrien#endif 689236769Sobrien buf = bmake_malloc(len = strlen(line) + strlen(argv0) + 2); 690236769Sobrien (void)snprintf(buf, len, "%s %s", argv0, line); 691236769Sobrien if (p1) 692236769Sobrien free(p1); 693236769Sobrien 694236769Sobrien argv = brk_string(buf, &argc, TRUE, &args); 695236769Sobrien if (argv == NULL) { 696236769Sobrien Error("Unterminated quoted string [%s]", buf); 697236769Sobrien free(buf); 698236769Sobrien return; 699236769Sobrien } 700236769Sobrien free(buf); 701236769Sobrien MainParseArgs(argc, argv); 702236769Sobrien 703236769Sobrien free(args); 704236769Sobrien free(argv); 705236769Sobrien} 706236769Sobrien 707236769SobrienBoolean 708236769SobrienMain_SetObjdir(const char *path) 709236769Sobrien{ 710236769Sobrien struct stat sb; 711236769Sobrien char *p = NULL; 712236769Sobrien char buf[MAXPATHLEN + 1]; 713236769Sobrien Boolean rc = FALSE; 714236769Sobrien 715236769Sobrien /* expand variable substitutions */ 716236769Sobrien if (strchr(path, '$') != 0) { 717236769Sobrien snprintf(buf, MAXPATHLEN, "%s", path); 718236769Sobrien path = p = Var_Subst(NULL, buf, VAR_GLOBAL, 0); 719236769Sobrien } 720236769Sobrien 721236769Sobrien if (path[0] != '/') { 722236769Sobrien snprintf(buf, MAXPATHLEN, "%s/%s", curdir, path); 723236769Sobrien path = buf; 724236769Sobrien } 725236769Sobrien 726236769Sobrien /* look for the directory and try to chdir there */ 727236769Sobrien if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 728236769Sobrien if (chdir(path)) { 729236769Sobrien (void)fprintf(stderr, "make warning: %s: %s.\n", 730236769Sobrien path, strerror(errno)); 731236769Sobrien } else { 732236769Sobrien strncpy(objdir, path, MAXPATHLEN); 733236769Sobrien Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 734236769Sobrien setenv("PWD", objdir, 1); 735236769Sobrien Dir_InitDot(); 736236769Sobrien rc = TRUE; 737236769Sobrien } 738236769Sobrien } 739236769Sobrien 740236769Sobrien if (p) 741236769Sobrien free(p); 742236769Sobrien return rc; 743236769Sobrien} 744236769Sobrien 745236769Sobrien/*- 746236769Sobrien * ReadAllMakefiles -- 747236769Sobrien * wrapper around ReadMakefile() to read all. 748236769Sobrien * 749236769Sobrien * Results: 750236769Sobrien * TRUE if ok, FALSE on error 751236769Sobrien */ 752236769Sobrienstatic int 753236769SobrienReadAllMakefiles(const void *p, const void *q) 754236769Sobrien{ 755236769Sobrien return (ReadMakefile(p, q) == 0); 756236769Sobrien} 757236769Sobrien 758236769Sobrienint 759236769Sobrienstr2Lst_Append(Lst lp, char *str, const char *sep) 760236769Sobrien{ 761236769Sobrien char *cp; 762236769Sobrien int n; 763236769Sobrien 764236769Sobrien if (!sep) 765236769Sobrien sep = " \t"; 766236769Sobrien 767236769Sobrien for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 768236769Sobrien (void)Lst_AtEnd(lp, cp); 769236769Sobrien n++; 770236769Sobrien } 771236769Sobrien return (n); 772236769Sobrien} 773236769Sobrien 774236769Sobrien#ifdef SIGINFO 775236769Sobrien/*ARGSUSED*/ 776236769Sobrienstatic void 777237578Sobriensiginfo(int signo MAKE_ATTR_UNUSED) 778236769Sobrien{ 779236769Sobrien char dir[MAXPATHLEN]; 780236769Sobrien char str[2 * MAXPATHLEN]; 781236769Sobrien int len; 782236769Sobrien if (getcwd(dir, sizeof(dir)) == NULL) 783236769Sobrien return; 784236769Sobrien len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 785236769Sobrien if (len > 0) 786236769Sobrien (void)write(STDERR_FILENO, str, (size_t)len); 787236769Sobrien} 788236769Sobrien#endif 789236769Sobrien 790236769Sobrien/* 791236769Sobrien * Allow makefiles some control over the mode we run in. 792236769Sobrien */ 793236769Sobrienvoid 794236769SobrienMakeMode(const char *mode) 795236769Sobrien{ 796236769Sobrien char *mp = NULL; 797236769Sobrien 798236769Sobrien if (!mode) 799236769Sobrien mode = mp = Var_Subst(NULL, "${" MAKE_MODE ":tl}", VAR_GLOBAL, 0); 800236769Sobrien 801236769Sobrien if (mode && *mode) { 802236769Sobrien if (strstr(mode, "compat")) { 803236769Sobrien compatMake = TRUE; 804236769Sobrien forceJobs = FALSE; 805236769Sobrien } 806236769Sobrien#if USE_META 807236769Sobrien if (strstr(mode, "meta")) 808249033Ssjg meta_mode_init(mode); 809236769Sobrien#endif 810236769Sobrien } 811236769Sobrien if (mp) 812236769Sobrien free(mp); 813236769Sobrien} 814236769Sobrien 815236769Sobrien/*- 816236769Sobrien * main -- 817236769Sobrien * The main function, for obvious reasons. Initializes variables 818236769Sobrien * and a few modules, then parses the arguments give it in the 819236769Sobrien * environment and on the command line. Reads the system makefile 820236769Sobrien * followed by either Makefile, makefile or the file given by the 821236769Sobrien * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 822236769Sobrien * flags it has received by then uses either the Make or the Compat 823236769Sobrien * module to create the initial list of targets. 824236769Sobrien * 825236769Sobrien * Results: 826236769Sobrien * If -q was given, exits -1 if anything was out-of-date. Else it exits 827236769Sobrien * 0. 828236769Sobrien * 829236769Sobrien * Side Effects: 830236769Sobrien * The program exits when done. Targets are created. etc. etc. etc. 831236769Sobrien */ 832236769Sobrienint 833236769Sobrienmain(int argc, char **argv) 834236769Sobrien{ 835236769Sobrien Lst targs; /* target nodes to create -- passed to Make_Init */ 836236769Sobrien Boolean outOfDate = FALSE; /* FALSE if all targets up to date */ 837236769Sobrien struct stat sb, sa; 838250750Ssjg char *p1, *path; 839236769Sobrien char mdpath[MAXPATHLEN]; 840236769Sobrien#ifdef FORCE_MACHINE 841236769Sobrien const char *machine = FORCE_MACHINE; 842236769Sobrien#else 843236769Sobrien const char *machine = getenv("MACHINE"); 844236769Sobrien#endif 845236769Sobrien const char *machine_arch = getenv("MACHINE_ARCH"); 846236769Sobrien char *syspath = getenv("MAKESYSPATH"); 847236769Sobrien Lst sysMkPath; /* Path of sys.mk */ 848236769Sobrien char *cp = NULL, *start; 849236769Sobrien /* avoid faults on read-only strings */ 850236769Sobrien static char defsyspath[] = _PATH_DEFSYSPATH; 851236769Sobrien char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 852236769Sobrien struct timeval rightnow; /* to initialize random seed */ 853236769Sobrien struct utsname utsname; 854236769Sobrien 855236769Sobrien /* default to writing debug to stderr */ 856236769Sobrien debug_file = stderr; 857236769Sobrien 858236769Sobrien#ifdef SIGINFO 859236769Sobrien (void)bmake_signal(SIGINFO, siginfo); 860236769Sobrien#endif 861236769Sobrien /* 862236769Sobrien * Set the seed to produce a different random sequence 863236769Sobrien * on each program execution. 864236769Sobrien */ 865236769Sobrien gettimeofday(&rightnow, NULL); 866236769Sobrien srandom(rightnow.tv_sec + rightnow.tv_usec); 867236769Sobrien 868236769Sobrien if ((progname = strrchr(argv[0], '/')) != NULL) 869236769Sobrien progname++; 870236769Sobrien else 871236769Sobrien progname = argv[0]; 872249033Ssjg#if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 873236769Sobrien /* 874236769Sobrien * get rid of resource limit on file descriptors 875236769Sobrien */ 876236769Sobrien { 877236769Sobrien struct rlimit rl; 878236769Sobrien if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 879236769Sobrien rl.rlim_cur != rl.rlim_max) { 880236769Sobrien rl.rlim_cur = rl.rlim_max; 881236769Sobrien (void)setrlimit(RLIMIT_NOFILE, &rl); 882236769Sobrien } 883236769Sobrien } 884236769Sobrien#endif 885236769Sobrien 886249033Ssjg if (uname(&utsname) == -1) { 887249033Ssjg (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 888249033Ssjg strerror(errno)); 889249033Ssjg exit(2); 890249033Ssjg } 891249033Ssjg 892236769Sobrien /* 893236769Sobrien * Get the name of this type of MACHINE from utsname 894236769Sobrien * so we can share an executable for similar machines. 895236769Sobrien * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 896236769Sobrien * 897236769Sobrien * Note that both MACHINE and MACHINE_ARCH are decided at 898236769Sobrien * run-time. 899236769Sobrien */ 900236769Sobrien if (!machine) { 901236769Sobrien#ifdef MAKE_NATIVE 902236769Sobrien machine = utsname.machine; 903236769Sobrien#else 904236769Sobrien#ifdef MAKE_MACHINE 905236769Sobrien machine = MAKE_MACHINE; 906236769Sobrien#else 907236769Sobrien machine = "unknown"; 908236769Sobrien#endif 909236769Sobrien#endif 910236769Sobrien } 911236769Sobrien 912236769Sobrien if (!machine_arch) { 913236769Sobrien#ifndef MACHINE_ARCH 914236769Sobrien#ifdef MAKE_MACHINE_ARCH 915236769Sobrien machine_arch = MAKE_MACHINE_ARCH; 916236769Sobrien#else 917236769Sobrien machine_arch = "unknown"; 918236769Sobrien#endif 919236769Sobrien#else 920236769Sobrien machine_arch = MACHINE_ARCH; 921236769Sobrien#endif 922236769Sobrien } 923236769Sobrien 924236769Sobrien myPid = getpid(); /* remember this for vFork() */ 925236769Sobrien 926236769Sobrien /* 927236769Sobrien * Just in case MAKEOBJDIR wants us to do something tricky. 928236769Sobrien */ 929236769Sobrien Var_Init(); /* Initialize the lists of variables for 930236769Sobrien * parsing arguments */ 931249033Ssjg Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL, 0); 932236769Sobrien Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 933236769Sobrien Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 934236769Sobrien#ifdef MAKE_VERSION 935236769Sobrien Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 936236769Sobrien#endif 937236769Sobrien Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 938236769Sobrien /* 939236769Sobrien * This is the traditional preference for makefiles. 940236769Sobrien */ 941236769Sobrien#ifndef MAKEFILE_PREFERENCE_LIST 942236769Sobrien# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 943236769Sobrien#endif 944236769Sobrien Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 945236769Sobrien VAR_GLOBAL, 0); 946236769Sobrien Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL, 0); 947236769Sobrien 948236769Sobrien create = Lst_Init(FALSE); 949236769Sobrien makefiles = Lst_Init(FALSE); 950236769Sobrien printVars = FALSE; 951240330Smarcel debugVflag = FALSE; 952236769Sobrien variables = Lst_Init(FALSE); 953236769Sobrien beSilent = FALSE; /* Print commands as executed */ 954236769Sobrien ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 955236769Sobrien noExecute = FALSE; /* Execute all commands */ 956236769Sobrien noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 957236769Sobrien keepgoing = FALSE; /* Stop on error */ 958236769Sobrien allPrecious = FALSE; /* Remove targets when interrupted */ 959236769Sobrien queryFlag = FALSE; /* This is not just a check-run */ 960236769Sobrien noBuiltins = FALSE; /* Read the built-in rules */ 961236769Sobrien touchFlag = FALSE; /* Actually update targets */ 962236769Sobrien debug = 0; /* No debug verbosity, please. */ 963236769Sobrien jobsRunning = FALSE; 964236769Sobrien 965236769Sobrien maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 966236769Sobrien maxJobTokens = maxJobs; 967236769Sobrien compatMake = FALSE; /* No compat mode */ 968236769Sobrien ignorePWD = FALSE; 969236769Sobrien 970236769Sobrien /* 971236769Sobrien * Initialize the parsing, directory and variable modules to prepare 972236769Sobrien * for the reading of inclusion paths and variable settings on the 973236769Sobrien * command line 974236769Sobrien */ 975236769Sobrien 976236769Sobrien /* 977236769Sobrien * Initialize various variables. 978236769Sobrien * MAKE also gets this name, for compatibility 979236769Sobrien * .MAKEFLAGS gets set to the empty string just in case. 980236769Sobrien * MFLAGS also gets initialized empty, for compatibility. 981236769Sobrien */ 982236769Sobrien Parse_Init(); 983236769Sobrien if (argv[0][0] == '/' || strchr(argv[0], '/') == NULL) { 984236769Sobrien /* 985236769Sobrien * Leave alone if it is an absolute path, or if it does 986236769Sobrien * not contain a '/' in which case we need to find it in 987236769Sobrien * the path, like execvp(3) and the shells do. 988236769Sobrien */ 989236769Sobrien p1 = argv[0]; 990236769Sobrien } else { 991236769Sobrien /* 992236769Sobrien * A relative path, canonicalize it. 993236769Sobrien */ 994236769Sobrien p1 = realpath(argv[0], mdpath); 995236769Sobrien if (!p1 || *p1 != '/' || stat(p1, &sb) < 0) { 996236769Sobrien p1 = argv[0]; /* realpath failed */ 997236769Sobrien } 998236769Sobrien } 999236769Sobrien Var_Set("MAKE", p1, VAR_GLOBAL, 0); 1000236769Sobrien Var_Set(".MAKE", p1, VAR_GLOBAL, 0); 1001236769Sobrien Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 1002236769Sobrien Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 1003236769Sobrien Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 1004236769Sobrien Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 1005253883Ssjg /* some makefiles need to know this */ 1006253883Ssjg Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMD, 0); 1007236769Sobrien 1008236769Sobrien /* 1009236769Sobrien * Set some other useful macros 1010236769Sobrien */ 1011236769Sobrien { 1012253883Ssjg char tmp[64], *ep; 1013236769Sobrien 1014253883Ssjg makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1015253883Ssjg if (makelevel < 0) 1016253883Ssjg makelevel = 0; 1017253883Ssjg snprintf(tmp, sizeof(tmp), "%d", makelevel); 1018253883Ssjg Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL, 0); 1019236769Sobrien snprintf(tmp, sizeof(tmp), "%u", myPid); 1020236769Sobrien Var_Set(".MAKE.PID", tmp, VAR_GLOBAL, 0); 1021236769Sobrien snprintf(tmp, sizeof(tmp), "%u", getppid()); 1022236769Sobrien Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL, 0); 1023236769Sobrien } 1024253883Ssjg if (makelevel > 0) { 1025253883Ssjg char pn[1024]; 1026253883Ssjg snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1027253883Ssjg progname = bmake_strdup(pn); 1028253883Ssjg } 1029236769Sobrien 1030249033Ssjg#ifdef USE_META 1031249033Ssjg meta_init(); 1032249033Ssjg#endif 1033236769Sobrien /* 1034236769Sobrien * First snag any flags out of the MAKE environment variable. 1035236769Sobrien * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1036236769Sobrien * in a different format). 1037236769Sobrien */ 1038236769Sobrien#ifdef POSIX 1039253883Ssjg p1 = explode(getenv("MAKEFLAGS")); 1040253883Ssjg Main_ParseArgLine(p1); 1041253883Ssjg free(p1); 1042236769Sobrien#else 1043236769Sobrien Main_ParseArgLine(getenv("MAKE")); 1044236769Sobrien#endif 1045236769Sobrien 1046236769Sobrien /* 1047236769Sobrien * Find where we are (now). 1048236769Sobrien * We take care of PWD for the automounter below... 1049236769Sobrien */ 1050236769Sobrien if (getcwd(curdir, MAXPATHLEN) == NULL) { 1051236769Sobrien (void)fprintf(stderr, "%s: getcwd: %s.\n", 1052236769Sobrien progname, strerror(errno)); 1053236769Sobrien exit(2); 1054236769Sobrien } 1055236769Sobrien 1056236769Sobrien MainParseArgs(argc, argv); 1057236769Sobrien 1058253883Ssjg if (enterFlag) 1059253883Ssjg printf("%s: Entering directory `%s'\n", progname, curdir); 1060253883Ssjg 1061236769Sobrien /* 1062236769Sobrien * Verify that cwd is sane. 1063236769Sobrien */ 1064236769Sobrien if (stat(curdir, &sa) == -1) { 1065236769Sobrien (void)fprintf(stderr, "%s: %s: %s.\n", 1066236769Sobrien progname, curdir, strerror(errno)); 1067236769Sobrien exit(2); 1068236769Sobrien } 1069236769Sobrien 1070236769Sobrien /* 1071236769Sobrien * All this code is so that we know where we are when we start up 1072236769Sobrien * on a different machine with pmake. 1073236769Sobrien * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1074236769Sobrien * since the value of curdir can vary depending on how we got 1075236769Sobrien * here. Ie sitting at a shell prompt (shell that provides $PWD) 1076236769Sobrien * or via subdir.mk in which case its likely a shell which does 1077236769Sobrien * not provide it. 1078236769Sobrien * So, to stop it breaking this case only, we ignore PWD if 1079236769Sobrien * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 1080236769Sobrien */ 1081236769Sobrien#ifndef NO_PWD_OVERRIDE 1082253883Ssjg if (!ignorePWD) { 1083253883Ssjg char *pwd; 1084236769Sobrien 1085253883Ssjg if ((pwd = getenv("PWD")) != NULL && 1086253883Ssjg getenv("MAKEOBJDIRPREFIX") == NULL) { 1087253883Ssjg const char *makeobjdir = getenv("MAKEOBJDIR"); 1088253883Ssjg 1089253883Ssjg if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 1090253883Ssjg if (stat(pwd, &sb) == 0 && 1091253883Ssjg sa.st_ino == sb.st_ino && 1092253883Ssjg sa.st_dev == sb.st_dev) 1093253883Ssjg (void)strncpy(curdir, pwd, MAXPATHLEN); 1094253883Ssjg } 1095236769Sobrien } 1096236769Sobrien } 1097236769Sobrien#endif 1098236769Sobrien Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 1099236769Sobrien 1100236769Sobrien /* 1101236769Sobrien * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1102236769Sobrien * MAKEOBJDIR is set in the environment, try only that value 1103236769Sobrien * and fall back to .CURDIR if it does not exist. 1104236769Sobrien * 1105236769Sobrien * Otherwise, try _PATH_OBJDIR.MACHINE, _PATH_OBJDIR, and 1106236769Sobrien * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1107236769Sobrien * of these paths exist, just use .CURDIR. 1108236769Sobrien */ 1109236769Sobrien Dir_Init(curdir); 1110236769Sobrien (void)Main_SetObjdir(curdir); 1111236769Sobrien 1112236769Sobrien if ((path = getenv("MAKEOBJDIRPREFIX")) != NULL) { 1113236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir); 1114236769Sobrien (void)Main_SetObjdir(mdpath); 1115236769Sobrien } else if ((path = getenv("MAKEOBJDIR")) != NULL) { 1116236769Sobrien (void)Main_SetObjdir(path); 1117236769Sobrien } else { 1118236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s.%s", _PATH_OBJDIR, machine); 1119236769Sobrien if (!Main_SetObjdir(mdpath) && !Main_SetObjdir(_PATH_OBJDIR)) { 1120236769Sobrien (void)snprintf(mdpath, MAXPATHLEN, "%s%s", 1121236769Sobrien _PATH_OBJDIRPREFIX, curdir); 1122236769Sobrien (void)Main_SetObjdir(mdpath); 1123236769Sobrien } 1124236769Sobrien } 1125236769Sobrien 1126236769Sobrien /* 1127236769Sobrien * Be compatible if user did not specify -j and did not explicitly 1128236769Sobrien * turned compatibility on 1129236769Sobrien */ 1130236769Sobrien if (!compatMake && !forceJobs) { 1131236769Sobrien compatMake = TRUE; 1132236769Sobrien } 1133236769Sobrien 1134236769Sobrien /* 1135236769Sobrien * Initialize archive, target and suffix modules in preparation for 1136236769Sobrien * parsing the makefile(s) 1137236769Sobrien */ 1138236769Sobrien Arch_Init(); 1139236769Sobrien Targ_Init(); 1140236769Sobrien Suff_Init(); 1141236769Sobrien Trace_Init(tracefile); 1142236769Sobrien 1143236769Sobrien DEFAULT = NULL; 1144236769Sobrien (void)time(&now); 1145236769Sobrien 1146236769Sobrien Trace_Log(MAKESTART, NULL); 1147236769Sobrien 1148236769Sobrien /* 1149236769Sobrien * Set up the .TARGETS variable to contain the list of targets to be 1150236769Sobrien * created. If none specified, make the variable empty -- the parser 1151236769Sobrien * will fill the thing in with the default or .MAIN target. 1152236769Sobrien */ 1153236769Sobrien if (!Lst_IsEmpty(create)) { 1154236769Sobrien LstNode ln; 1155236769Sobrien 1156236769Sobrien for (ln = Lst_First(create); ln != NULL; 1157236769Sobrien ln = Lst_Succ(ln)) { 1158236769Sobrien char *name = (char *)Lst_Datum(ln); 1159236769Sobrien 1160236769Sobrien Var_Append(".TARGETS", name, VAR_GLOBAL); 1161236769Sobrien } 1162236769Sobrien } else 1163236769Sobrien Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 1164236769Sobrien 1165236769Sobrien 1166236769Sobrien /* 1167236769Sobrien * If no user-supplied system path was given (through the -m option) 1168236769Sobrien * add the directories from the DEFSYSPATH (more than one may be given 1169236769Sobrien * as dir1:...:dirn) to the system include path. 1170236769Sobrien */ 1171236769Sobrien if (syspath == NULL || *syspath == '\0') 1172236769Sobrien syspath = defsyspath; 1173236769Sobrien else 1174236769Sobrien syspath = bmake_strdup(syspath); 1175236769Sobrien 1176236769Sobrien for (start = syspath; *start != '\0'; start = cp) { 1177236769Sobrien for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1178236769Sobrien continue; 1179236769Sobrien if (*cp == ':') { 1180236769Sobrien *cp++ = '\0'; 1181236769Sobrien } 1182236769Sobrien /* look for magic parent directory search string */ 1183236769Sobrien if (strncmp(".../", start, 4) != 0) { 1184236769Sobrien (void)Dir_AddDir(defIncPath, start); 1185236769Sobrien } else { 1186236769Sobrien if (Dir_FindHereOrAbove(curdir, start+4, 1187236769Sobrien found_path, sizeof(found_path))) { 1188236769Sobrien (void)Dir_AddDir(defIncPath, found_path); 1189236769Sobrien } 1190236769Sobrien } 1191236769Sobrien } 1192236769Sobrien if (syspath != defsyspath) 1193236769Sobrien free(syspath); 1194236769Sobrien 1195236769Sobrien /* 1196236769Sobrien * Read in the built-in rules first, followed by the specified 1197236769Sobrien * makefile, if it was (makefile != NULL), or the default 1198236769Sobrien * makefile and Makefile, in that order, if it wasn't. 1199236769Sobrien */ 1200236769Sobrien if (!noBuiltins) { 1201236769Sobrien LstNode ln; 1202236769Sobrien 1203236769Sobrien sysMkPath = Lst_Init(FALSE); 1204236769Sobrien Dir_Expand(_PATH_DEFSYSMK, 1205236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 1206236769Sobrien sysMkPath); 1207236769Sobrien if (Lst_IsEmpty(sysMkPath)) 1208236769Sobrien Fatal("%s: no system rules (%s).", progname, 1209236769Sobrien _PATH_DEFSYSMK); 1210236769Sobrien ln = Lst_Find(sysMkPath, NULL, ReadMakefile); 1211236769Sobrien if (ln == NULL) 1212236769Sobrien Fatal("%s: cannot open %s.", progname, 1213236769Sobrien (char *)Lst_Datum(ln)); 1214236769Sobrien } 1215236769Sobrien 1216236769Sobrien if (!Lst_IsEmpty(makefiles)) { 1217236769Sobrien LstNode ln; 1218236769Sobrien 1219236769Sobrien ln = Lst_Find(makefiles, NULL, ReadAllMakefiles); 1220236769Sobrien if (ln != NULL) 1221236769Sobrien Fatal("%s: cannot open %s.", progname, 1222236769Sobrien (char *)Lst_Datum(ln)); 1223236769Sobrien } else { 1224236769Sobrien p1 = Var_Subst(NULL, "${" MAKEFILE_PREFERENCE "}", 1225236769Sobrien VAR_CMD, 0); 1226236769Sobrien if (p1) { 1227236769Sobrien (void)str2Lst_Append(makefiles, p1, NULL); 1228236769Sobrien (void)Lst_Find(makefiles, NULL, ReadMakefile); 1229236769Sobrien free(p1); 1230236769Sobrien } 1231236769Sobrien } 1232236769Sobrien 1233236769Sobrien /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1234236769Sobrien if (!noBuiltins || !printVars) { 1235236769Sobrien makeDependfile = Var_Subst(NULL, "${.MAKE.DEPENDFILE:T}", 1236236769Sobrien VAR_CMD, 0); 1237236769Sobrien doing_depend = TRUE; 1238236769Sobrien (void)ReadMakefile(makeDependfile, NULL); 1239236769Sobrien doing_depend = FALSE; 1240236769Sobrien } 1241236769Sobrien 1242236769Sobrien MakeMode(NULL); 1243236769Sobrien 1244236769Sobrien Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 1245236769Sobrien if (p1) 1246236769Sobrien free(p1); 1247236769Sobrien 1248236769Sobrien if (!compatMake) 1249236769Sobrien Job_ServerStart(maxJobTokens, jp_0, jp_1); 1250236769Sobrien if (DEBUG(JOB)) 1251236769Sobrien fprintf(debug_file, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1252236769Sobrien jp_0, jp_1, maxJobs, maxJobTokens, compatMake); 1253236769Sobrien 1254236769Sobrien Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1255236769Sobrien 1256236769Sobrien /* 1257236769Sobrien * For compatibility, look at the directories in the VPATH variable 1258236769Sobrien * and add them to the search path, if the variable is defined. The 1259236769Sobrien * variable's value is in the same format as the PATH envariable, i.e. 1260236769Sobrien * <directory>:<directory>:<directory>... 1261236769Sobrien */ 1262236769Sobrien if (Var_Exists("VPATH", VAR_CMD)) { 1263236769Sobrien char *vpath, savec; 1264236769Sobrien /* 1265236769Sobrien * GCC stores string constants in read-only memory, but 1266236769Sobrien * Var_Subst will want to write this thing, so store it 1267236769Sobrien * in an array 1268236769Sobrien */ 1269236769Sobrien static char VPATH[] = "${VPATH}"; 1270236769Sobrien 1271236769Sobrien vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 1272236769Sobrien path = vpath; 1273236769Sobrien do { 1274236769Sobrien /* skip to end of directory */ 1275236769Sobrien for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1276236769Sobrien continue; 1277236769Sobrien /* Save terminator character so know when to stop */ 1278236769Sobrien savec = *cp; 1279236769Sobrien *cp = '\0'; 1280236769Sobrien /* Add directory to search path */ 1281236769Sobrien (void)Dir_AddDir(dirSearchPath, path); 1282236769Sobrien *cp = savec; 1283236769Sobrien path = cp + 1; 1284236769Sobrien } while (savec == ':'); 1285236769Sobrien free(vpath); 1286236769Sobrien } 1287236769Sobrien 1288236769Sobrien /* 1289236769Sobrien * Now that all search paths have been read for suffixes et al, it's 1290236769Sobrien * time to add the default search path to their lists... 1291236769Sobrien */ 1292236769Sobrien Suff_DoPaths(); 1293236769Sobrien 1294236769Sobrien /* 1295236769Sobrien * Propagate attributes through :: dependency lists. 1296236769Sobrien */ 1297236769Sobrien Targ_Propagate(); 1298236769Sobrien 1299236769Sobrien /* print the initial graph, if the user requested it */ 1300236769Sobrien if (DEBUG(GRAPH1)) 1301236769Sobrien Targ_PrintGraph(1); 1302236769Sobrien 1303236769Sobrien /* print the values of any variables requested by the user */ 1304236769Sobrien if (printVars) { 1305236769Sobrien LstNode ln; 1306240330Smarcel Boolean expandVars; 1307236769Sobrien 1308240330Smarcel if (debugVflag) 1309240330Smarcel expandVars = FALSE; 1310240330Smarcel else 1311240330Smarcel expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 1312236769Sobrien for (ln = Lst_First(variables); ln != NULL; 1313236769Sobrien ln = Lst_Succ(ln)) { 1314236769Sobrien char *var = (char *)Lst_Datum(ln); 1315236769Sobrien char *value; 1316236769Sobrien 1317236769Sobrien if (strchr(var, '$')) { 1318236769Sobrien value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 0); 1319240330Smarcel } else if (expandVars) { 1320240330Smarcel char tmp[128]; 1321240330Smarcel 1322240330Smarcel if (snprintf(tmp, sizeof(tmp), "${%s}", var) >= (int)(sizeof(tmp))) 1323240330Smarcel Fatal("%s: variable name too big: %s", 1324240330Smarcel progname, var); 1325240330Smarcel value = p1 = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1326236769Sobrien } else { 1327236769Sobrien value = Var_Value(var, VAR_GLOBAL, &p1); 1328236769Sobrien } 1329236769Sobrien printf("%s\n", value ? value : ""); 1330236769Sobrien if (p1) 1331236769Sobrien free(p1); 1332236769Sobrien } 1333236769Sobrien } else { 1334236769Sobrien /* 1335236769Sobrien * Have now read the entire graph and need to make a list of 1336236769Sobrien * targets to create. If none was given on the command line, 1337236769Sobrien * we consult the parsing module to find the main target(s) 1338236769Sobrien * to create. 1339236769Sobrien */ 1340236769Sobrien if (Lst_IsEmpty(create)) 1341236769Sobrien targs = Parse_MainName(); 1342236769Sobrien else 1343236769Sobrien targs = Targ_FindList(create, TARG_CREATE); 1344236769Sobrien 1345236769Sobrien if (!compatMake) { 1346236769Sobrien /* 1347236769Sobrien * Initialize job module before traversing the graph 1348236769Sobrien * now that any .BEGIN and .END targets have been read. 1349236769Sobrien * This is done only if the -q flag wasn't given 1350236769Sobrien * (to prevent the .BEGIN from being executed should 1351236769Sobrien * it exist). 1352236769Sobrien */ 1353236769Sobrien if (!queryFlag) { 1354236769Sobrien Job_Init(); 1355236769Sobrien jobsRunning = TRUE; 1356236769Sobrien } 1357236769Sobrien 1358236769Sobrien /* Traverse the graph, checking on all the targets */ 1359236769Sobrien outOfDate = Make_Run(targs); 1360236769Sobrien } else { 1361236769Sobrien /* 1362236769Sobrien * Compat_Init will take care of creating all the 1363236769Sobrien * targets as well as initializing the module. 1364236769Sobrien */ 1365236769Sobrien Compat_Run(targs); 1366236769Sobrien } 1367236769Sobrien } 1368236769Sobrien 1369236769Sobrien#ifdef CLEANUP 1370236769Sobrien Lst_Destroy(targs, NULL); 1371236769Sobrien Lst_Destroy(variables, NULL); 1372236769Sobrien Lst_Destroy(makefiles, NULL); 1373236769Sobrien Lst_Destroy(create, (FreeProc *)free); 1374236769Sobrien#endif 1375236769Sobrien 1376236769Sobrien /* print the graph now it's been processed if the user requested it */ 1377236769Sobrien if (DEBUG(GRAPH2)) 1378236769Sobrien Targ_PrintGraph(2); 1379236769Sobrien 1380236769Sobrien Trace_Log(MAKEEND, 0); 1381236769Sobrien 1382253883Ssjg if (enterFlag) 1383253883Ssjg printf("%s: Leaving directory `%s'\n", progname, curdir); 1384253883Ssjg 1385236769Sobrien Suff_End(); 1386236769Sobrien Targ_End(); 1387236769Sobrien Arch_End(); 1388236769Sobrien Var_End(); 1389236769Sobrien Parse_End(); 1390236769Sobrien Dir_End(); 1391236769Sobrien Job_End(); 1392236769Sobrien Trace_End(); 1393236769Sobrien 1394236769Sobrien return outOfDate ? 1 : 0; 1395236769Sobrien} 1396236769Sobrien 1397236769Sobrien/*- 1398236769Sobrien * ReadMakefile -- 1399236769Sobrien * Open and parse the given makefile. 1400236769Sobrien * 1401236769Sobrien * Results: 1402236769Sobrien * 0 if ok. -1 if couldn't open file. 1403236769Sobrien * 1404236769Sobrien * Side Effects: 1405236769Sobrien * lots 1406236769Sobrien */ 1407236769Sobrienstatic int 1408237578SobrienReadMakefile(const void *p, const void *q MAKE_ATTR_UNUSED) 1409236769Sobrien{ 1410236769Sobrien const char *fname = p; /* makefile to read */ 1411236769Sobrien int fd; 1412236769Sobrien size_t len = MAXPATHLEN; 1413236769Sobrien char *name, *path = bmake_malloc(len); 1414236769Sobrien 1415236769Sobrien if (!strcmp(fname, "-")) { 1416236769Sobrien Parse_File(NULL /*stdin*/, -1); 1417255253Ssjg Var_Set("MAKEFILE", "", VAR_INTERNAL, 0); 1418236769Sobrien } else { 1419236769Sobrien /* if we've chdir'd, rebuild the path name */ 1420236769Sobrien if (strcmp(curdir, objdir) && *fname != '/') { 1421236769Sobrien size_t plen = strlen(curdir) + strlen(fname) + 2; 1422236769Sobrien if (len < plen) 1423236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1424236769Sobrien 1425236769Sobrien (void)snprintf(path, len, "%s/%s", curdir, fname); 1426236769Sobrien fd = open(path, O_RDONLY); 1427236769Sobrien if (fd != -1) { 1428236769Sobrien fname = path; 1429236769Sobrien goto found; 1430236769Sobrien } 1431236769Sobrien 1432236769Sobrien /* If curdir failed, try objdir (ala .depend) */ 1433236769Sobrien plen = strlen(objdir) + strlen(fname) + 2; 1434236769Sobrien if (len < plen) 1435236769Sobrien path = bmake_realloc(path, len = 2 * plen); 1436236769Sobrien (void)snprintf(path, len, "%s/%s", objdir, fname); 1437236769Sobrien fd = open(path, O_RDONLY); 1438236769Sobrien if (fd != -1) { 1439236769Sobrien fname = path; 1440236769Sobrien goto found; 1441236769Sobrien } 1442236769Sobrien } else { 1443236769Sobrien fd = open(fname, O_RDONLY); 1444236769Sobrien if (fd != -1) 1445236769Sobrien goto found; 1446236769Sobrien } 1447236769Sobrien /* look in -I and system include directories. */ 1448236769Sobrien name = Dir_FindFile(fname, parseIncPath); 1449236769Sobrien if (!name) 1450236769Sobrien name = Dir_FindFile(fname, 1451236769Sobrien Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1452236769Sobrien if (!name || (fd = open(name, O_RDONLY)) == -1) { 1453236769Sobrien if (name) 1454236769Sobrien free(name); 1455236769Sobrien free(path); 1456236769Sobrien return(-1); 1457236769Sobrien } 1458236769Sobrien fname = name; 1459236769Sobrien /* 1460236769Sobrien * set the MAKEFILE variable desired by System V fans -- the 1461236769Sobrien * placement of the setting here means it gets set to the last 1462236769Sobrien * makefile specified, as it is set by SysV make. 1463236769Sobrien */ 1464236769Sobrienfound: 1465236769Sobrien if (!doing_depend) 1466255253Ssjg Var_Set("MAKEFILE", fname, VAR_INTERNAL, 0); 1467236769Sobrien Parse_File(fname, fd); 1468236769Sobrien } 1469236769Sobrien free(path); 1470236769Sobrien return(0); 1471236769Sobrien} 1472236769Sobrien 1473236769Sobrien 1474236769Sobrien 1475236769Sobrien/*- 1476236769Sobrien * Cmd_Exec -- 1477236769Sobrien * Execute the command in cmd, and return the output of that command 1478236769Sobrien * in a string. 1479236769Sobrien * 1480236769Sobrien * Results: 1481236769Sobrien * A string containing the output of the command, or the empty string 1482236769Sobrien * If errnum is not NULL, it contains the reason for the command failure 1483236769Sobrien * 1484236769Sobrien * Side Effects: 1485236769Sobrien * The string must be freed by the caller. 1486236769Sobrien */ 1487236769Sobrienchar * 1488236769SobrienCmd_Exec(const char *cmd, const char **errnum) 1489236769Sobrien{ 1490236769Sobrien const char *args[4]; /* Args for invoking the shell */ 1491236769Sobrien int fds[2]; /* Pipe streams */ 1492236769Sobrien int cpid; /* Child PID */ 1493236769Sobrien int pid; /* PID from wait() */ 1494236769Sobrien char *res; /* result */ 1495236769Sobrien WAIT_T status; /* command exit status */ 1496236769Sobrien Buffer buf; /* buffer to store the result */ 1497236769Sobrien char *cp; 1498236769Sobrien int cc; 1499236769Sobrien 1500236769Sobrien 1501236769Sobrien *errnum = NULL; 1502236769Sobrien 1503236769Sobrien if (!shellName) 1504236769Sobrien Shell_Init(); 1505236769Sobrien /* 1506236769Sobrien * Set up arguments for shell 1507236769Sobrien */ 1508236769Sobrien args[0] = shellName; 1509236769Sobrien args[1] = "-c"; 1510236769Sobrien args[2] = cmd; 1511236769Sobrien args[3] = NULL; 1512236769Sobrien 1513236769Sobrien /* 1514236769Sobrien * Open a pipe for fetching its output 1515236769Sobrien */ 1516236769Sobrien if (pipe(fds) == -1) { 1517236769Sobrien *errnum = "Couldn't create pipe for \"%s\""; 1518236769Sobrien goto bad; 1519236769Sobrien } 1520236769Sobrien 1521236769Sobrien /* 1522236769Sobrien * Fork 1523236769Sobrien */ 1524236769Sobrien switch (cpid = vFork()) { 1525236769Sobrien case 0: 1526236769Sobrien /* 1527236769Sobrien * Close input side of pipe 1528236769Sobrien */ 1529236769Sobrien (void)close(fds[0]); 1530236769Sobrien 1531236769Sobrien /* 1532236769Sobrien * Duplicate the output stream to the shell's output, then 1533236769Sobrien * shut the extra thing down. Note we don't fetch the error 1534236769Sobrien * stream...why not? Why? 1535236769Sobrien */ 1536236769Sobrien (void)dup2(fds[1], 1); 1537236769Sobrien (void)close(fds[1]); 1538236769Sobrien 1539236769Sobrien Var_ExportVars(); 1540236769Sobrien 1541236769Sobrien (void)execv(shellPath, UNCONST(args)); 1542236769Sobrien _exit(1); 1543236769Sobrien /*NOTREACHED*/ 1544236769Sobrien 1545236769Sobrien case -1: 1546236769Sobrien *errnum = "Couldn't exec \"%s\""; 1547236769Sobrien goto bad; 1548236769Sobrien 1549236769Sobrien default: 1550236769Sobrien /* 1551236769Sobrien * No need for the writing half 1552236769Sobrien */ 1553236769Sobrien (void)close(fds[1]); 1554236769Sobrien 1555236769Sobrien Buf_Init(&buf, 0); 1556236769Sobrien 1557236769Sobrien do { 1558236769Sobrien char result[BUFSIZ]; 1559236769Sobrien cc = read(fds[0], result, sizeof(result)); 1560236769Sobrien if (cc > 0) 1561236769Sobrien Buf_AddBytes(&buf, cc, result); 1562236769Sobrien } 1563236769Sobrien while (cc > 0 || (cc == -1 && errno == EINTR)); 1564236769Sobrien 1565236769Sobrien /* 1566236769Sobrien * Close the input side of the pipe. 1567236769Sobrien */ 1568236769Sobrien (void)close(fds[0]); 1569236769Sobrien 1570236769Sobrien /* 1571236769Sobrien * Wait for the process to exit. 1572236769Sobrien */ 1573236769Sobrien while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1574236769Sobrien JobReapChild(pid, status, FALSE); 1575236769Sobrien continue; 1576236769Sobrien } 1577236769Sobrien cc = Buf_Size(&buf); 1578236769Sobrien res = Buf_Destroy(&buf, FALSE); 1579236769Sobrien 1580236769Sobrien if (cc == 0) 1581236769Sobrien *errnum = "Couldn't read shell's output for \"%s\""; 1582236769Sobrien 1583236769Sobrien if (WIFSIGNALED(status)) 1584236769Sobrien *errnum = "\"%s\" exited on a signal"; 1585236769Sobrien else if (WEXITSTATUS(status) != 0) 1586236769Sobrien *errnum = "\"%s\" returned non-zero status"; 1587236769Sobrien 1588236769Sobrien /* 1589236769Sobrien * Null-terminate the result, convert newlines to spaces and 1590236769Sobrien * install it in the variable. 1591236769Sobrien */ 1592236769Sobrien res[cc] = '\0'; 1593236769Sobrien cp = &res[cc]; 1594236769Sobrien 1595236769Sobrien if (cc > 0 && *--cp == '\n') { 1596236769Sobrien /* 1597236769Sobrien * A final newline is just stripped 1598236769Sobrien */ 1599236769Sobrien *cp-- = '\0'; 1600236769Sobrien } 1601236769Sobrien while (cp >= res) { 1602236769Sobrien if (*cp == '\n') { 1603236769Sobrien *cp = ' '; 1604236769Sobrien } 1605236769Sobrien cp--; 1606236769Sobrien } 1607236769Sobrien break; 1608236769Sobrien } 1609236769Sobrien return res; 1610236769Sobrienbad: 1611236769Sobrien res = bmake_malloc(1); 1612236769Sobrien *res = '\0'; 1613236769Sobrien return res; 1614236769Sobrien} 1615236769Sobrien 1616236769Sobrien/*- 1617236769Sobrien * Error -- 1618236769Sobrien * Print an error message given its format. 1619236769Sobrien * 1620236769Sobrien * Results: 1621236769Sobrien * None. 1622236769Sobrien * 1623236769Sobrien * Side Effects: 1624236769Sobrien * The message is printed. 1625236769Sobrien */ 1626236769Sobrien/* VARARGS */ 1627236769Sobrienvoid 1628236769SobrienError(const char *fmt, ...) 1629236769Sobrien{ 1630236769Sobrien va_list ap; 1631236769Sobrien FILE *err_file; 1632236769Sobrien 1633236769Sobrien err_file = debug_file; 1634236769Sobrien if (err_file == stdout) 1635236769Sobrien err_file = stderr; 1636236769Sobrien (void)fflush(stdout); 1637236769Sobrien for (;;) { 1638236769Sobrien va_start(ap, fmt); 1639236769Sobrien fprintf(err_file, "%s: ", progname); 1640236769Sobrien (void)vfprintf(err_file, fmt, ap); 1641236769Sobrien va_end(ap); 1642236769Sobrien (void)fprintf(err_file, "\n"); 1643236769Sobrien (void)fflush(err_file); 1644236769Sobrien if (err_file == stderr) 1645236769Sobrien break; 1646236769Sobrien err_file = stderr; 1647236769Sobrien } 1648236769Sobrien} 1649236769Sobrien 1650236769Sobrien/*- 1651236769Sobrien * Fatal -- 1652236769Sobrien * Produce a Fatal error message. If jobs are running, waits for them 1653236769Sobrien * to finish. 1654236769Sobrien * 1655236769Sobrien * Results: 1656236769Sobrien * None 1657236769Sobrien * 1658236769Sobrien * Side Effects: 1659236769Sobrien * The program exits 1660236769Sobrien */ 1661236769Sobrien/* VARARGS */ 1662236769Sobrienvoid 1663236769SobrienFatal(const char *fmt, ...) 1664236769Sobrien{ 1665236769Sobrien va_list ap; 1666236769Sobrien 1667236769Sobrien va_start(ap, fmt); 1668236769Sobrien if (jobsRunning) 1669236769Sobrien Job_Wait(); 1670236769Sobrien 1671236769Sobrien (void)fflush(stdout); 1672236769Sobrien (void)vfprintf(stderr, fmt, ap); 1673236769Sobrien va_end(ap); 1674236769Sobrien (void)fprintf(stderr, "\n"); 1675236769Sobrien (void)fflush(stderr); 1676236769Sobrien 1677236769Sobrien PrintOnError(NULL, NULL); 1678236769Sobrien 1679236769Sobrien if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1680236769Sobrien Targ_PrintGraph(2); 1681236769Sobrien Trace_Log(MAKEERROR, 0); 1682236769Sobrien exit(2); /* Not 1 so -q can distinguish error */ 1683236769Sobrien} 1684236769Sobrien 1685236769Sobrien/* 1686236769Sobrien * Punt -- 1687236769Sobrien * Major exception once jobs are being created. Kills all jobs, prints 1688236769Sobrien * a message and exits. 1689236769Sobrien * 1690236769Sobrien * Results: 1691236769Sobrien * None 1692236769Sobrien * 1693236769Sobrien * Side Effects: 1694236769Sobrien * All children are killed indiscriminately and the program Lib_Exits 1695236769Sobrien */ 1696236769Sobrien/* VARARGS */ 1697236769Sobrienvoid 1698236769SobrienPunt(const char *fmt, ...) 1699236769Sobrien{ 1700236769Sobrien va_list ap; 1701236769Sobrien 1702236769Sobrien va_start(ap, fmt); 1703236769Sobrien (void)fflush(stdout); 1704236769Sobrien (void)fprintf(stderr, "%s: ", progname); 1705236769Sobrien (void)vfprintf(stderr, fmt, ap); 1706236769Sobrien va_end(ap); 1707236769Sobrien (void)fprintf(stderr, "\n"); 1708236769Sobrien (void)fflush(stderr); 1709236769Sobrien 1710236769Sobrien PrintOnError(NULL, NULL); 1711236769Sobrien 1712236769Sobrien DieHorribly(); 1713236769Sobrien} 1714236769Sobrien 1715236769Sobrien/*- 1716236769Sobrien * DieHorribly -- 1717236769Sobrien * Exit without giving a message. 1718236769Sobrien * 1719236769Sobrien * Results: 1720236769Sobrien * None 1721236769Sobrien * 1722236769Sobrien * Side Effects: 1723236769Sobrien * A big one... 1724236769Sobrien */ 1725236769Sobrienvoid 1726236769SobrienDieHorribly(void) 1727236769Sobrien{ 1728236769Sobrien if (jobsRunning) 1729236769Sobrien Job_AbortAll(); 1730236769Sobrien if (DEBUG(GRAPH2)) 1731236769Sobrien Targ_PrintGraph(2); 1732236769Sobrien Trace_Log(MAKEERROR, 0); 1733236769Sobrien exit(2); /* Not 1, so -q can distinguish error */ 1734236769Sobrien} 1735236769Sobrien 1736236769Sobrien/* 1737236769Sobrien * Finish -- 1738236769Sobrien * Called when aborting due to errors in child shell to signal 1739236769Sobrien * abnormal exit. 1740236769Sobrien * 1741236769Sobrien * Results: 1742236769Sobrien * None 1743236769Sobrien * 1744236769Sobrien * Side Effects: 1745236769Sobrien * The program exits 1746236769Sobrien */ 1747236769Sobrienvoid 1748236769SobrienFinish(int errors) 1749236769Sobrien /* number of errors encountered in Make_Make */ 1750236769Sobrien{ 1751236769Sobrien Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1752236769Sobrien} 1753236769Sobrien 1754236769Sobrien/* 1755249033Ssjg * eunlink -- 1756236769Sobrien * Remove a file carefully, avoiding directories. 1757236769Sobrien */ 1758236769Sobrienint 1759236769Sobrieneunlink(const char *file) 1760236769Sobrien{ 1761236769Sobrien struct stat st; 1762236769Sobrien 1763236769Sobrien if (lstat(file, &st) == -1) 1764236769Sobrien return -1; 1765236769Sobrien 1766236769Sobrien if (S_ISDIR(st.st_mode)) { 1767236769Sobrien errno = EISDIR; 1768236769Sobrien return -1; 1769236769Sobrien } 1770236769Sobrien return unlink(file); 1771236769Sobrien} 1772236769Sobrien 1773236769Sobrien/* 1774236769Sobrien * execError -- 1775236769Sobrien * Print why exec failed, avoiding stdio. 1776236769Sobrien */ 1777236769Sobrienvoid 1778236769SobrienexecError(const char *af, const char *av) 1779236769Sobrien{ 1780236769Sobrien#ifdef USE_IOVEC 1781236769Sobrien int i = 0; 1782236769Sobrien struct iovec iov[8]; 1783236769Sobrien#define IOADD(s) \ 1784236769Sobrien (void)(iov[i].iov_base = UNCONST(s), \ 1785236769Sobrien iov[i].iov_len = strlen(iov[i].iov_base), \ 1786236769Sobrien i++) 1787236769Sobrien#else 1788236769Sobrien#define IOADD(s) (void)write(2, s, strlen(s)) 1789236769Sobrien#endif 1790236769Sobrien 1791236769Sobrien IOADD(progname); 1792236769Sobrien IOADD(": "); 1793236769Sobrien IOADD(af); 1794236769Sobrien IOADD("("); 1795236769Sobrien IOADD(av); 1796236769Sobrien IOADD(") failed ("); 1797236769Sobrien IOADD(strerror(errno)); 1798236769Sobrien IOADD(")\n"); 1799236769Sobrien 1800236769Sobrien#ifdef USE_IOVEC 1801246223Ssjg while (writev(2, iov, 8) == -1 && errno == EAGAIN) 1802246223Ssjg continue; 1803236769Sobrien#endif 1804236769Sobrien} 1805236769Sobrien 1806236769Sobrien/* 1807236769Sobrien * usage -- 1808236769Sobrien * exit with usage message 1809236769Sobrien */ 1810236769Sobrienstatic void 1811236769Sobrienusage(void) 1812236769Sobrien{ 1813253883Ssjg char *p; 1814253883Ssjg if ((p = strchr(progname, '[')) != NULL) 1815253883Ssjg *p = '\0'; 1816253883Ssjg 1817236769Sobrien (void)fprintf(stderr, 1818253883Ssjg"usage: %s [-BeikNnqrstWwX] \n\ 1819236769Sobrien [-C directory] [-D variable] [-d flags] [-f makefile]\n\ 1820236769Sobrien [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1821236769Sobrien [-V variable] [variable=value] [target ...]\n", progname); 1822236769Sobrien exit(2); 1823236769Sobrien} 1824236769Sobrien 1825236769Sobrien 1826236769Sobrienint 1827236769SobrienPrintAddr(void *a, void *b) 1828236769Sobrien{ 1829236769Sobrien printf("%lx ", (unsigned long) a); 1830236769Sobrien return b ? 0 : 0; 1831236769Sobrien} 1832236769Sobrien 1833236769Sobrien 1834236769Sobrien 1835236769Sobrienvoid 1836236769SobrienPrintOnError(GNode *gn, const char *s) 1837236769Sobrien{ 1838236769Sobrien static GNode *en = NULL; 1839236769Sobrien char tmp[64]; 1840236769Sobrien char *cp; 1841236769Sobrien 1842236769Sobrien if (s) 1843236769Sobrien printf("%s", s); 1844236769Sobrien 1845236769Sobrien printf("\n%s: stopped in %s\n", progname, curdir); 1846236769Sobrien 1847236769Sobrien if (en) 1848236769Sobrien return; /* we've been here! */ 1849236769Sobrien if (gn) { 1850236769Sobrien /* 1851236769Sobrien * We can print this even if there is no .ERROR target. 1852236769Sobrien */ 1853236769Sobrien Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL, 0); 1854236769Sobrien } 1855236769Sobrien strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 1856236769Sobrien sizeof(tmp) - 1); 1857236769Sobrien cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1858236769Sobrien if (cp) { 1859236769Sobrien if (*cp) 1860236769Sobrien printf("%s", cp); 1861236769Sobrien free(cp); 1862236769Sobrien } 1863236769Sobrien /* 1864236769Sobrien * Finally, see if there is a .ERROR target, and run it if so. 1865236769Sobrien */ 1866236769Sobrien en = Targ_FindNode(".ERROR", TARG_NOCREATE); 1867236769Sobrien if (en) { 1868236769Sobrien en->type |= OP_SPECIAL; 1869236769Sobrien Compat_Make(en, en); 1870236769Sobrien } 1871236769Sobrien} 1872236769Sobrien 1873236769Sobrienvoid 1874236769SobrienMain_ExportMAKEFLAGS(Boolean first) 1875236769Sobrien{ 1876236769Sobrien static int once = 1; 1877236769Sobrien char tmp[64]; 1878236769Sobrien char *s; 1879236769Sobrien 1880236769Sobrien if (once != first) 1881236769Sobrien return; 1882236769Sobrien once = 0; 1883236769Sobrien 1884236769Sobrien strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 1885236769Sobrien sizeof(tmp)); 1886236769Sobrien s = Var_Subst(NULL, tmp, VAR_CMD, 0); 1887236769Sobrien if (s && *s) { 1888236769Sobrien#ifdef POSIX 1889236769Sobrien setenv("MAKEFLAGS", s, 1); 1890236769Sobrien#else 1891236769Sobrien setenv("MAKE", s, 1); 1892236769Sobrien#endif 1893236769Sobrien } 1894236769Sobrien} 1895236769Sobrien 1896236769Sobrienchar * 1897236769SobriengetTmpdir(void) 1898236769Sobrien{ 1899236769Sobrien static char *tmpdir = NULL; 1900236769Sobrien 1901236769Sobrien if (!tmpdir) { 1902236769Sobrien struct stat st; 1903236769Sobrien 1904236769Sobrien /* 1905236769Sobrien * Honor $TMPDIR but only if it is valid. 1906236769Sobrien * Ensure it ends with /. 1907236769Sobrien */ 1908236769Sobrien tmpdir = Var_Subst(NULL, "${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 0); 1909236769Sobrien if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 1910236769Sobrien free(tmpdir); 1911236769Sobrien tmpdir = bmake_strdup(_PATH_TMP); 1912236769Sobrien } 1913236769Sobrien } 1914236769Sobrien return tmpdir; 1915236769Sobrien} 1916236769Sobrien 1917236769Sobrien/* 1918236769Sobrien * Create and open a temp file using "pattern". 1919236769Sobrien * If "fnamep" is provided set it to a copy of the filename created. 1920236769Sobrien * Otherwise unlink the file once open. 1921236769Sobrien */ 1922236769Sobrienint 1923236769SobrienmkTempFile(const char *pattern, char **fnamep) 1924236769Sobrien{ 1925236769Sobrien static char *tmpdir = NULL; 1926236769Sobrien char tfile[MAXPATHLEN]; 1927236769Sobrien int fd; 1928236769Sobrien 1929236769Sobrien if (!pattern) 1930236769Sobrien pattern = TMPPAT; 1931236769Sobrien if (!tmpdir) 1932236769Sobrien tmpdir = getTmpdir(); 1933236769Sobrien if (pattern[0] == '/') { 1934236769Sobrien snprintf(tfile, sizeof(tfile), "%s", pattern); 1935236769Sobrien } else { 1936236769Sobrien snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 1937236769Sobrien } 1938236769Sobrien if ((fd = mkstemp(tfile)) < 0) 1939236769Sobrien Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 1940236769Sobrien if (fnamep) { 1941236769Sobrien *fnamep = bmake_strdup(tfile); 1942236769Sobrien } else { 1943236769Sobrien unlink(tfile); /* we just want the descriptor */ 1944236769Sobrien } 1945236769Sobrien return fd; 1946236769Sobrien} 1947240330Smarcel 1948240330Smarcel 1949240330Smarcel/* 1950240330Smarcel * Return a Boolean based on setting of a knob. 1951240330Smarcel * 1952240330Smarcel * If the knob is not set, the supplied default is the return value. 1953240330Smarcel * If set, anything that looks or smells like "No", "False", "Off", "0" etc, 1954240330Smarcel * is FALSE, otherwise TRUE. 1955240330Smarcel */ 1956240330SmarcelBoolean 1957240330SmarcelgetBoolean(const char *name, Boolean bf) 1958240330Smarcel{ 1959240330Smarcel char tmp[64]; 1960240330Smarcel char *cp; 1961240330Smarcel 1962240330Smarcel if (snprintf(tmp, sizeof(tmp), "${%s:tl}", name) < (int)(sizeof(tmp))) { 1963240330Smarcel cp = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1964240330Smarcel 1965240330Smarcel if (cp) { 1966240330Smarcel switch(*cp) { 1967240330Smarcel case '\0': /* not set - the default wins */ 1968240330Smarcel break; 1969240330Smarcel case '0': 1970240330Smarcel case 'f': 1971240330Smarcel case 'n': 1972240330Smarcel bf = FALSE; 1973240330Smarcel break; 1974240330Smarcel case 'o': 1975240330Smarcel switch (cp[1]) { 1976240330Smarcel case 'f': 1977240330Smarcel bf = FALSE; 1978240330Smarcel break; 1979240330Smarcel default: 1980240330Smarcel bf = TRUE; 1981240330Smarcel break; 1982240330Smarcel } 1983240330Smarcel break; 1984240330Smarcel default: 1985240330Smarcel bf = TRUE; 1986240330Smarcel break; 1987240330Smarcel } 1988240330Smarcel free(cp); 1989240330Smarcel } 1990240330Smarcel } 1991240330Smarcel return (bf); 1992240330Smarcel} 1993