1 /* $NetBSD: main.c,v 1.421 2020/11/01 00:24:57 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 /*- 72 * main.c -- 73 * The main file for this entire program. Exit routines etc 74 * reside here. 75 * 76 * Utility functions defined in this file: 77 * Main_ParseArgLine Takes a line of arguments, breaks them and 78 * treats them as if they were given when first 79 * invoked. Used by the parse module to implement 80 * the .MFLAGS target. 81 * 82 * Error Print a tagged error message. The global 83 * MAKE variable must have been defined. This 84 * takes a format string and optional arguments 85 * for it. 86 * 87 * Fatal Print an error message and exit. Also takes 88 * a format string and arguments for it. 89 * 90 * Punt Aborts all jobs and exits with a message. Also 91 * takes a format string and arguments for it. 92 * 93 * Finish Finish things up by printing the number of 94 * errors which occurred, as passed to it, and 95 * exiting. 96 */ 97 98 #include <sys/types.h> 99 #include <sys/time.h> 100 #include <sys/param.h> 101 #include <sys/resource.h> 102 #include <sys/stat.h> 103 #if defined(MAKE_NATIVE) && defined(HAVE_SYSCTL) 104 #include <sys/sysctl.h> 105 #endif 106 #include <sys/utsname.h> 107 #include "wait.h" 108 109 #include <errno.h> 110 #include <signal.h> 111 #include <stdarg.h> 112 #include <time.h> 113 114 #include "make.h" 115 #include "dir.h" 116 #include "job.h" 117 #include "pathnames.h" 118 #include "trace.h" 119 120 /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ 121 MAKE_RCSID("$NetBSD: main.c,v 1.421 2020/11/01 00:24:57 rillig Exp $"); 122 #if defined(MAKE_NATIVE) && !defined(lint) 123 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " 124 "The Regents of the University of California. " 125 "All rights reserved."); 126 #endif 127 128 #ifndef DEFMAXLOCAL 129 #define DEFMAXLOCAL DEFMAXJOBS 130 #endif 131 132 #ifndef __arraycount 133 # define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 134 #endif 135 136 CmdOpts opts; 137 time_t now; /* Time at start of make */ 138 GNode *DEFAULT; /* .DEFAULT node */ 139 Boolean allPrecious; /* .PRECIOUS given on line by itself */ 140 Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ 141 142 static int maxJobTokens; /* -j argument */ 143 Boolean enterFlagObj; /* -w and objdir != srcdir */ 144 145 Boolean oldVars; /* variable substitution style */ 146 static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ 147 Boolean doing_depend; /* Set while reading .depend */ 148 static Boolean jobsRunning; /* TRUE if the jobs might be running */ 149 static const char * tracefile; 150 static int ReadMakefile(const char *); 151 static void usage(void) MAKE_ATTR_DEAD; 152 static void purge_cached_realpaths(void); 153 154 static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ 155 static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 156 char curdir[MAXPATHLEN + 1]; /* Startup directory */ 157 char *progname; /* the program name */ 158 char *makeDependfile; 159 pid_t myPid; 160 int makelevel; 161 162 Boolean forceJobs = FALSE; 163 static int errors = 0; 164 165 /* 166 * On some systems MACHINE is defined as something other than 167 * what we want. 168 */ 169 #ifdef FORCE_MACHINE 170 # undef MACHINE 171 # define MACHINE FORCE_MACHINE 172 #endif 173 174 extern SearchPath *parseIncPath; 175 176 /* 177 * For compatibility with the POSIX version of MAKEFLAGS that includes 178 * all the options with out -, convert flags to -f -l -a -g -s. 179 */ 180 static char * 181 explode(const char *flags) 182 { 183 size_t len; 184 char *nf, *st; 185 const char *f; 186 187 if (flags == NULL) 188 return NULL; 189 190 for (f = flags; *f; f++) 191 if (!ch_isalpha(*f)) 192 break; 193 194 if (*f) 195 return bmake_strdup(flags); 196 197 len = strlen(flags); 198 st = nf = bmake_malloc(len * 3 + 1); 199 while (*flags) { 200 *nf++ = '-'; 201 *nf++ = *flags++; 202 *nf++ = ' '; 203 } 204 *nf = '\0'; 205 return st; 206 } 207 208 static void 209 parse_debug_option_F(const char *modules) 210 { 211 const char *mode; 212 size_t len; 213 char *fname; 214 215 if (opts.debug_file != stdout && opts.debug_file != stderr) 216 fclose(opts.debug_file); 217 218 if (*modules == '+') { 219 modules++; 220 mode = "a"; 221 } else 222 mode = "w"; 223 224 if (strcmp(modules, "stdout") == 0) { 225 opts.debug_file = stdout; 226 return; 227 } 228 if (strcmp(modules, "stderr") == 0) { 229 opts.debug_file = stderr; 230 return; 231 } 232 233 len = strlen(modules); 234 fname = bmake_malloc(len + 20); 235 memcpy(fname, modules, len + 1); 236 237 /* Let the filename be modified by the pid */ 238 if (strcmp(fname + len - 3, ".%d") == 0) 239 snprintf(fname + len - 2, 20, "%d", getpid()); 240 241 opts.debug_file = fopen(fname, mode); 242 if (!opts.debug_file) { 243 fprintf(stderr, "Cannot open debug file %s\n", 244 fname); 245 usage(); 246 } 247 free(fname); 248 } 249 250 static void 251 parse_debug_options(const char *argvalue) 252 { 253 const char *modules; 254 255 for (modules = argvalue; *modules; ++modules) { 256 switch (*modules) { 257 case '0': /* undocumented, only intended for tests */ 258 opts.debug &= DEBUG_LINT; 259 break; 260 case 'A': 261 opts.debug = ~(0|DEBUG_LINT); 262 break; 263 case 'a': 264 opts.debug |= DEBUG_ARCH; 265 break; 266 case 'C': 267 opts.debug |= DEBUG_CWD; 268 break; 269 case 'c': 270 opts.debug |= DEBUG_COND; 271 break; 272 case 'd': 273 opts.debug |= DEBUG_DIR; 274 break; 275 case 'e': 276 opts.debug |= DEBUG_ERROR; 277 break; 278 case 'f': 279 opts.debug |= DEBUG_FOR; 280 break; 281 case 'g': 282 if (modules[1] == '1') { 283 opts.debug |= DEBUG_GRAPH1; 284 ++modules; 285 } 286 else if (modules[1] == '2') { 287 opts.debug |= DEBUG_GRAPH2; 288 ++modules; 289 } 290 else if (modules[1] == '3') { 291 opts.debug |= DEBUG_GRAPH3; 292 ++modules; 293 } 294 break; 295 case 'h': 296 opts.debug |= DEBUG_HASH; 297 break; 298 case 'j': 299 opts.debug |= DEBUG_JOB; 300 break; 301 case 'L': 302 opts.debug |= DEBUG_LINT; 303 break; 304 case 'l': 305 opts.debug |= DEBUG_LOUD; 306 break; 307 case 'M': 308 opts.debug |= DEBUG_META; 309 break; 310 case 'm': 311 opts.debug |= DEBUG_MAKE; 312 break; 313 case 'n': 314 opts.debug |= DEBUG_SCRIPT; 315 break; 316 case 'p': 317 opts.debug |= DEBUG_PARSE; 318 break; 319 case 's': 320 opts.debug |= DEBUG_SUFF; 321 break; 322 case 't': 323 opts.debug |= DEBUG_TARG; 324 break; 325 case 'V': 326 opts.debugVflag = TRUE; 327 break; 328 case 'v': 329 opts.debug |= DEBUG_VAR; 330 break; 331 case 'x': 332 opts.debug |= DEBUG_SHELL; 333 break; 334 case 'F': 335 parse_debug_option_F(modules + 1); 336 goto debug_setbuf; 337 default: 338 (void)fprintf(stderr, 339 "%s: illegal argument to d option -- %c\n", 340 progname, *modules); 341 usage(); 342 } 343 } 344 debug_setbuf: 345 /* 346 * Make the debug_file unbuffered, and make 347 * stdout line buffered (unless debugfile == stdout). 348 */ 349 setvbuf(opts.debug_file, NULL, _IONBF, 0); 350 if (opts.debug_file != stdout) { 351 setvbuf(stdout, NULL, _IOLBF, 0); 352 } 353 } 354 355 /* 356 * does path contain any relative components 357 */ 358 static Boolean 359 is_relpath(const char *path) 360 { 361 const char *cp; 362 363 if (path[0] != '/') 364 return TRUE; 365 cp = path; 366 while ((cp = strstr(cp, "/.")) != NULL) { 367 cp += 2; 368 if (cp[0] == '/' || cp[0] == '\0') 369 return TRUE; 370 else if (cp[0] == '.') { 371 if (cp[1] == '/' || cp[1] == '\0') 372 return TRUE; 373 } 374 } 375 return FALSE; 376 } 377 378 static void 379 MainParseArgChdir(const char *argvalue) 380 { 381 struct stat sa, sb; 382 383 if (chdir(argvalue) == -1) { 384 (void)fprintf(stderr, "%s: chdir %s: %s\n", 385 progname, argvalue, strerror(errno)); 386 exit(1); 387 } 388 if (getcwd(curdir, MAXPATHLEN) == NULL) { 389 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 390 exit(2); 391 } 392 if (!is_relpath(argvalue) && 393 stat(argvalue, &sa) != -1 && 394 stat(curdir, &sb) != -1 && 395 sa.st_ino == sb.st_ino && 396 sa.st_dev == sb.st_dev) 397 strncpy(curdir, argvalue, MAXPATHLEN); 398 ignorePWD = TRUE; 399 } 400 401 static void 402 MainParseArgJobsInternal(const char *argvalue) 403 { 404 if (sscanf(argvalue, "%d,%d", &jp_0, &jp_1) != 2) { 405 (void)fprintf(stderr, 406 "%s: internal error -- J option malformed (%s)\n", 407 progname, argvalue); 408 usage(); 409 } 410 if ((fcntl(jp_0, F_GETFD, 0) < 0) || 411 (fcntl(jp_1, F_GETFD, 0) < 0)) { 412 #if 0 413 (void)fprintf(stderr, 414 "%s: ###### warning -- J descriptors were closed!\n", 415 progname); 416 exit(2); 417 #endif 418 jp_0 = -1; 419 jp_1 = -1; 420 opts.compatMake = TRUE; 421 } else { 422 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 423 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 424 } 425 } 426 427 static void 428 MainParseArgJobs(const char *argvalue) 429 { 430 char *p; 431 432 forceJobs = TRUE; 433 opts.maxJobs = (int)strtol(argvalue, &p, 0); 434 if (*p != '\0' || opts.maxJobs < 1) { 435 (void)fprintf(stderr, 436 "%s: illegal argument to -j -- must be positive integer!\n", 437 progname); 438 exit(1); /* XXX: why not 2? */ 439 } 440 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 441 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 442 Var_Set(".MAKE.JOBS", argvalue, VAR_GLOBAL); 443 maxJobTokens = opts.maxJobs; 444 } 445 446 static void 447 MainParseArgSysInc(const char *argvalue) 448 { 449 /* look for magic parent directory search string */ 450 if (strncmp(".../", argvalue, 4) == 0) { 451 char *found_path = Dir_FindHereOrAbove(curdir, argvalue + 4); 452 if (found_path == NULL) 453 return; 454 (void)Dir_AddDir(sysIncPath, found_path); 455 free(found_path); 456 } else { 457 (void)Dir_AddDir(sysIncPath, argvalue); 458 } 459 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 460 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 461 } 462 463 static Boolean 464 MainParseArg(char c, const char *argvalue) 465 { 466 switch (c) { 467 case '\0': 468 break; 469 case 'B': 470 opts.compatMake = TRUE; 471 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 472 Var_Set(MAKE_MODE, "compat", VAR_GLOBAL); 473 break; 474 case 'C': 475 MainParseArgChdir(argvalue); 476 break; 477 case 'D': 478 if (argvalue[0] == '\0') return FALSE; 479 Var_Set(argvalue, "1", VAR_GLOBAL); 480 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 481 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 482 break; 483 case 'I': 484 Parse_AddIncludeDir(argvalue); 485 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 486 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 487 break; 488 case 'J': 489 MainParseArgJobsInternal(argvalue); 490 break; 491 case 'N': 492 opts.noExecute = TRUE; 493 opts.noRecursiveExecute = TRUE; 494 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 495 break; 496 case 'S': 497 opts.keepgoing = FALSE; 498 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 499 break; 500 case 'T': 501 tracefile = bmake_strdup(argvalue); 502 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 503 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 504 break; 505 case 'V': 506 case 'v': 507 opts.printVars = c == 'v' ? EXPAND_VARS : COMPAT_VARS; 508 Lst_Append(opts.variables, bmake_strdup(argvalue)); 509 /* XXX: Why always -V? */ 510 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 511 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 512 break; 513 case 'W': 514 opts.parseWarnFatal = TRUE; 515 break; 516 case 'X': 517 opts.varNoExportEnv = TRUE; 518 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 519 break; 520 case 'd': 521 /* If '-d-opts' don't pass to children */ 522 if (argvalue[0] == '-') 523 argvalue++; 524 else { 525 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 526 Var_Append(MAKEFLAGS, argvalue, VAR_GLOBAL); 527 } 528 parse_debug_options(argvalue); 529 break; 530 case 'e': 531 opts.checkEnvFirst = TRUE; 532 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 533 break; 534 case 'f': 535 Lst_Append(opts.makefiles, bmake_strdup(argvalue)); 536 break; 537 case 'i': 538 opts.ignoreErrors = TRUE; 539 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 540 break; 541 case 'j': 542 MainParseArgJobs(argvalue); 543 break; 544 case 'k': 545 opts.keepgoing = TRUE; 546 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 547 break; 548 case 'm': 549 MainParseArgSysInc(argvalue); 550 break; 551 case 'n': 552 opts.noExecute = TRUE; 553 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 554 break; 555 case 'q': 556 opts.queryFlag = TRUE; 557 /* Kind of nonsensical, wot? */ 558 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 559 break; 560 case 'r': 561 opts.noBuiltins = TRUE; 562 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 563 break; 564 case 's': 565 opts.beSilent = TRUE; 566 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 567 break; 568 case 't': 569 opts.touchFlag = TRUE; 570 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 571 break; 572 case 'w': 573 opts.enterFlag = TRUE; 574 Var_Append(MAKEFLAGS, "-w", VAR_GLOBAL); 575 break; 576 default: 577 case '?': 578 usage(); 579 } 580 return TRUE; 581 } 582 583 /* Parse the given arguments. Called from main() and from 584 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 585 * 586 * The arguments must be treated as read-only and will be freed after the 587 * call. 588 * 589 * XXX: Deal with command line overriding .MAKEFLAGS in makefile */ 590 static void 591 MainParseArgs(int argc, char **argv) 592 { 593 char c; 594 int arginc; 595 char *argvalue; 596 char *optscan; 597 Boolean inOption, dashDash = FALSE; 598 599 const char *optspecs = "BC:D:I:J:NST:V:WXd:ef:ij:km:nqrstv:w"; 600 /* Can't actually use getopt(3) because rescanning is not portable */ 601 602 rearg: 603 inOption = FALSE; 604 optscan = NULL; 605 while (argc > 1) { 606 const char *optspec; 607 if (!inOption) 608 optscan = argv[1]; 609 c = *optscan++; 610 arginc = 0; 611 if (inOption) { 612 if (c == '\0') { 613 ++argv; 614 --argc; 615 inOption = FALSE; 616 continue; 617 } 618 } else { 619 if (c != '-' || dashDash) 620 break; 621 inOption = TRUE; 622 c = *optscan++; 623 } 624 /* '-' found at some earlier point */ 625 optspec = strchr(optspecs, c); 626 if (c != '\0' && optspec != NULL && optspec[1] == ':') { 627 /* -<something> found, and <something> should have an arg */ 628 inOption = FALSE; 629 arginc = 1; 630 argvalue = optscan; 631 if (*argvalue == '\0') { 632 if (argc < 3) 633 goto noarg; 634 argvalue = argv[2]; 635 arginc = 2; 636 } 637 } else { 638 argvalue = NULL; 639 } 640 switch (c) { 641 case '\0': 642 arginc = 1; 643 inOption = FALSE; 644 break; 645 case '-': 646 dashDash = TRUE; 647 break; 648 default: 649 if (!MainParseArg(c, argvalue)) 650 goto noarg; 651 } 652 argv += arginc; 653 argc -= arginc; 654 } 655 656 oldVars = TRUE; 657 658 /* 659 * See if the rest of the arguments are variable assignments and 660 * perform them if so. Else take them to be targets and stuff them 661 * on the end of the "create" list. 662 */ 663 for (; argc > 1; ++argv, --argc) { 664 VarAssign var; 665 if (Parse_IsVar(argv[1], &var)) { 666 Parse_DoVar(&var, VAR_CMDLINE); 667 } else { 668 if (!*argv[1]) 669 Punt("illegal (null) argument."); 670 if (*argv[1] == '-' && !dashDash) 671 goto rearg; 672 Lst_Append(opts.create, bmake_strdup(argv[1])); 673 } 674 } 675 676 return; 677 noarg: 678 (void)fprintf(stderr, "%s: option requires an argument -- %c\n", 679 progname, c); 680 usage(); 681 } 682 683 /* Break a line of arguments into words and parse them. 684 * 685 * Used when a .MFLAGS or .MAKEFLAGS target is encountered during parsing and 686 * by main() when reading the MAKEFLAGS environment variable. */ 687 void 688 Main_ParseArgLine(const char *line) 689 { 690 Words words; 691 void *p1; 692 const char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 693 char *buf; 694 695 if (line == NULL) 696 return; 697 for (; *line == ' '; ++line) 698 continue; 699 if (!*line) 700 return; 701 702 #ifndef POSIX 703 { 704 /* 705 * $MAKE may simply be naming the make(1) binary 706 */ 707 char *cp; 708 709 if (!(cp = strrchr(line, '/'))) 710 cp = line; 711 if ((cp = strstr(cp, "make")) && 712 strcmp(cp, "make") == 0) 713 return; 714 } 715 #endif 716 buf = str_concat3(argv0, " ", line); 717 free(p1); 718 719 words = Str_Words(buf, TRUE); 720 if (words.words == NULL) { 721 Error("Unterminated quoted string [%s]", buf); 722 free(buf); 723 return; 724 } 725 free(buf); 726 MainParseArgs((int)words.len, words.words); 727 728 Words_Free(words); 729 } 730 731 Boolean 732 Main_SetObjdir(const char *fmt, ...) 733 { 734 struct stat sb; 735 char *path; 736 char buf[MAXPATHLEN + 1]; 737 char buf2[MAXPATHLEN + 1]; 738 Boolean rc = FALSE; 739 va_list ap; 740 741 va_start(ap, fmt); 742 vsnprintf(path = buf, MAXPATHLEN, fmt, ap); 743 va_end(ap); 744 745 if (path[0] != '/') { 746 snprintf(buf2, MAXPATHLEN, "%s/%s", curdir, path); 747 path = buf2; 748 } 749 750 /* look for the directory and try to chdir there */ 751 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 752 /* if not .CURDIR it must be writable */ 753 if ((strcmp(path, curdir) != 0 && access(path, W_OK) != 0) || 754 chdir(path)) { 755 (void)fprintf(stderr, "make warning: %s: %s.\n", 756 path, strerror(errno)); 757 } else { 758 snprintf(objdir, sizeof objdir, "%s", path); 759 Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 760 setenv("PWD", objdir, 1); 761 Dir_InitDot(); 762 purge_cached_realpaths(); 763 rc = TRUE; 764 if (opts.enterFlag && strcmp(objdir, curdir) != 0) 765 enterFlagObj = TRUE; 766 } 767 } 768 769 return rc; 770 } 771 772 static Boolean 773 Main_SetVarObjdir(const char *var, const char *suffix) 774 { 775 void *path_freeIt; 776 const char *path = Var_Value(var, VAR_CMDLINE, &path_freeIt); 777 const char *xpath; 778 char *xpath_freeIt; 779 780 if (path == NULL || path[0] == '\0') { 781 bmake_free(path_freeIt); 782 return FALSE; 783 } 784 785 /* expand variable substitutions */ 786 xpath = path; 787 xpath_freeIt = NULL; 788 if (strchr(path, '$') != 0) { 789 (void)Var_Subst(path, VAR_GLOBAL, VARE_WANTRES, &xpath_freeIt); 790 /* TODO: handle errors */ 791 xpath = xpath_freeIt; 792 } 793 794 (void)Main_SetObjdir("%s%s", xpath, suffix); 795 796 bmake_free(xpath_freeIt); 797 bmake_free(path_freeIt); 798 return TRUE; 799 } 800 801 /* Read and parse the makefile. 802 * Return TRUE if reading the makefile succeeded. */ 803 static int 804 ReadMakefileSucceeded(void *fname, void *unused) 805 { 806 return ReadMakefile(fname) == 0; 807 } 808 809 int 810 str2Lst_Append(StringList *lp, char *str, const char *sep) 811 { 812 char *cp; 813 int n; 814 815 if (!sep) 816 sep = " \t"; 817 818 for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { 819 Lst_Append(lp, cp); 820 n++; 821 } 822 return n; 823 } 824 825 #ifdef SIGINFO 826 /*ARGSUSED*/ 827 static void 828 siginfo(int signo MAKE_ATTR_UNUSED) 829 { 830 char dir[MAXPATHLEN]; 831 char str[2 * MAXPATHLEN]; 832 int len; 833 if (getcwd(dir, sizeof(dir)) == NULL) 834 return; 835 len = snprintf(str, sizeof(str), "%s: Working in: %s\n", progname, dir); 836 if (len > 0) 837 (void)write(STDERR_FILENO, str, (size_t)len); 838 } 839 #endif 840 841 /* 842 * Allow makefiles some control over the mode we run in. 843 */ 844 void 845 MakeMode(const char *mode) 846 { 847 char *mode_freeIt = NULL; 848 849 if (mode == NULL) { 850 (void)Var_Subst("${" MAKE_MODE ":tl}", 851 VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); 852 /* TODO: handle errors */ 853 mode = mode_freeIt; 854 } 855 856 if (mode[0] != '\0') { 857 if (strstr(mode, "compat")) { 858 opts.compatMake = TRUE; 859 forceJobs = FALSE; 860 } 861 #if USE_META 862 if (strstr(mode, "meta")) 863 meta_mode_init(mode); 864 #endif 865 } 866 867 free(mode_freeIt); 868 } 869 870 static void 871 PrintVar(const char *varname, Boolean expandVars) 872 { 873 if (strchr(varname, '$')) { 874 char *evalue; 875 (void)Var_Subst(varname, VAR_GLOBAL, VARE_WANTRES, &evalue); 876 /* TODO: handle errors */ 877 printf("%s\n", evalue); 878 bmake_free(evalue); 879 880 } else if (expandVars) { 881 char *expr = str_concat3("${", varname, "}"); 882 char *evalue; 883 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &evalue); 884 /* TODO: handle errors */ 885 free(expr); 886 printf("%s\n", evalue); 887 bmake_free(evalue); 888 889 } else { 890 void *freeIt; 891 const char *value = Var_Value(varname, VAR_GLOBAL, &freeIt); 892 printf("%s\n", value ? value : ""); 893 bmake_free(freeIt); 894 } 895 } 896 897 static void 898 doPrintVars(void) 899 { 900 StringListNode *ln; 901 Boolean expandVars; 902 903 if (opts.printVars == EXPAND_VARS) 904 expandVars = TRUE; 905 else if (opts.debugVflag) 906 expandVars = FALSE; 907 else 908 expandVars = getBoolean(".MAKE.EXPAND_VARIABLES", FALSE); 909 910 for (ln = opts.variables->first; ln != NULL; ln = ln->next) { 911 const char *varname = ln->datum; 912 PrintVar(varname, expandVars); 913 } 914 } 915 916 static Boolean 917 runTargets(void) 918 { 919 GNodeList *targs; /* target nodes to create -- passed to Make_Init */ 920 Boolean outOfDate; /* FALSE if all targets up to date */ 921 922 /* 923 * Have now read the entire graph and need to make a list of 924 * targets to create. If none was given on the command line, 925 * we consult the parsing module to find the main target(s) 926 * to create. 927 */ 928 if (Lst_IsEmpty(opts.create)) 929 targs = Parse_MainName(); 930 else 931 targs = Targ_FindList(opts.create); 932 933 if (!opts.compatMake) { 934 /* 935 * Initialize job module before traversing the graph 936 * now that any .BEGIN and .END targets have been read. 937 * This is done only if the -q flag wasn't given 938 * (to prevent the .BEGIN from being executed should 939 * it exist). 940 */ 941 if (!opts.queryFlag) { 942 Job_Init(); 943 jobsRunning = TRUE; 944 } 945 946 /* Traverse the graph, checking on all the targets */ 947 outOfDate = Make_Run(targs); 948 } else { 949 /* 950 * Compat_Init will take care of creating all the 951 * targets as well as initializing the module. 952 */ 953 Compat_Run(targs); 954 outOfDate = FALSE; 955 } 956 Lst_Free(targs); 957 return outOfDate; 958 } 959 960 /* 961 * Set up the .TARGETS variable to contain the list of targets to be 962 * created. If none specified, make the variable empty -- the parser 963 * will fill the thing in with the default or .MAIN target. 964 */ 965 static void 966 InitVarTargets(void) 967 { 968 StringListNode *ln; 969 970 if (Lst_IsEmpty(opts.create)) { 971 Var_Set(".TARGETS", "", VAR_GLOBAL); 972 return; 973 } 974 975 for (ln = opts.create->first; ln != NULL; ln = ln->next) { 976 char *name = ln->datum; 977 Var_Append(".TARGETS", name, VAR_GLOBAL); 978 } 979 } 980 981 static void 982 InitRandom(void) 983 { 984 struct timeval tv; 985 986 gettimeofday(&tv, NULL); 987 srandom((unsigned int)(tv.tv_sec + tv.tv_usec)); 988 } 989 990 static const char * 991 init_machine(const struct utsname *utsname) 992 { 993 #ifdef FORCE_MACHINE 994 const char *machine = FORCE_MACHINE; 995 #else 996 const char *machine = getenv("MACHINE"); 997 #endif 998 if (machine != NULL) 999 return machine; 1000 1001 #ifdef MAKE_NATIVE 1002 return utsname->machine; 1003 #else 1004 #ifdef MAKE_MACHINE 1005 return MAKE_MACHINE; 1006 #else 1007 return "unknown"; 1008 #endif 1009 #endif 1010 } 1011 1012 static const char * 1013 init_machine_arch(void) 1014 { 1015 const char *env = getenv("MACHINE_ARCH"); 1016 if (env != NULL) 1017 return env; 1018 1019 #if defined(MAKE_NATIVE) && defined(CTL_HW) 1020 { 1021 struct utsname utsname; 1022 static char machine_arch_buf[sizeof(utsname.machine)]; 1023 const int mib[2] = { CTL_HW, HW_MACHINE_ARCH }; 1024 size_t len = sizeof(machine_arch_buf); 1025 1026 if (sysctl(mib, __arraycount(mib), machine_arch_buf, 1027 &len, NULL, 0) < 0) { 1028 (void)fprintf(stderr, "%s: sysctl failed (%s).\n", progname, 1029 strerror(errno)); 1030 exit(2); 1031 } 1032 1033 return machine_arch_buf; 1034 } 1035 #else 1036 #ifndef MACHINE_ARCH 1037 #ifdef MAKE_MACHINE_ARCH 1038 return MAKE_MACHINE_ARCH; 1039 #else 1040 return "unknown"; 1041 #endif 1042 #else 1043 return MACHINE_ARCH; 1044 #endif 1045 #endif 1046 } 1047 1048 #ifndef NO_PWD_OVERRIDE 1049 /* 1050 * All this code is so that we know where we are when we start up 1051 * on a different machine with pmake. 1052 * 1053 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 1054 * since the value of curdir can vary depending on how we got 1055 * here. Ie sitting at a shell prompt (shell that provides $PWD) 1056 * or via subdir.mk in which case its likely a shell which does 1057 * not provide it. 1058 * 1059 * So, to stop it breaking this case only, we ignore PWD if 1060 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a variable expression. 1061 */ 1062 static void 1063 HandlePWD(const struct stat *curdir_st) 1064 { 1065 char *pwd; 1066 void *prefix_freeIt, *makeobjdir_freeIt; 1067 const char *makeobjdir; 1068 struct stat pwd_st; 1069 1070 if (ignorePWD || (pwd = getenv("PWD")) == NULL) 1071 return; 1072 1073 if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) { 1074 bmake_free(prefix_freeIt); 1075 return; 1076 } 1077 1078 makeobjdir = Var_Value("MAKEOBJDIR", VAR_CMDLINE, &makeobjdir_freeIt); 1079 if (makeobjdir != NULL && strchr(makeobjdir, '$') != NULL) 1080 goto ignore_pwd; 1081 1082 if (stat(pwd, &pwd_st) == 0 && 1083 curdir_st->st_ino == pwd_st.st_ino && 1084 curdir_st->st_dev == pwd_st.st_dev) 1085 (void)strncpy(curdir, pwd, MAXPATHLEN); 1086 1087 ignore_pwd: 1088 bmake_free(makeobjdir_freeIt); 1089 } 1090 #endif 1091 1092 /* 1093 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 1094 * MAKEOBJDIR is set in the environment, try only that value 1095 * and fall back to .CURDIR if it does not exist. 1096 * 1097 * Otherwise, try _PATH_OBJDIR.MACHINE-MACHINE_ARCH, _PATH_OBJDIR.MACHINE, 1098 * and * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 1099 * of these paths exist, just use .CURDIR. 1100 */ 1101 static void 1102 InitObjdir(const char *machine, const char *machine_arch) 1103 { 1104 Dir_InitDir(curdir); 1105 (void)Main_SetObjdir("%s", curdir); 1106 1107 if (!Main_SetVarObjdir("MAKEOBJDIRPREFIX", curdir) && 1108 !Main_SetVarObjdir("MAKEOBJDIR", "") && 1109 !Main_SetObjdir("%s.%s-%s", _PATH_OBJDIR, machine, machine_arch) && 1110 !Main_SetObjdir("%s.%s", _PATH_OBJDIR, machine) && 1111 !Main_SetObjdir("%s", _PATH_OBJDIR)) 1112 (void)Main_SetObjdir("%s%s", _PATH_OBJDIRPREFIX, curdir); 1113 } 1114 1115 /* get rid of resource limit on file descriptors */ 1116 static void 1117 UnlimitFiles(void) 1118 { 1119 #if defined(MAKE_NATIVE) || (defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)) 1120 struct rlimit rl; 1121 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 1122 rl.rlim_cur != rl.rlim_max) { 1123 rl.rlim_cur = rl.rlim_max; 1124 (void)setrlimit(RLIMIT_NOFILE, &rl); 1125 } 1126 #endif 1127 } 1128 1129 static void 1130 CmdOpts_Init(void) 1131 { 1132 opts.compatMake = FALSE; /* No compat mode */ 1133 opts.debug = 0; /* No debug verbosity, please. */ 1134 /* opts.debug_file has been initialized earlier */ 1135 opts.debugVflag = FALSE; 1136 opts.checkEnvFirst = FALSE; 1137 opts.makefiles = Lst_New(); 1138 opts.ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 1139 opts.maxJobs = DEFMAXLOCAL; /* Set default local max concurrency */ 1140 opts.keepgoing = FALSE; /* Stop on error */ 1141 opts.noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 1142 opts.noExecute = FALSE; /* Execute all commands */ 1143 opts.queryFlag = FALSE; /* This is not just a check-run */ 1144 opts.noBuiltins = FALSE; /* Read the built-in rules */ 1145 opts.beSilent = FALSE; /* Print commands as executed */ 1146 opts.touchFlag = FALSE; /* Actually update targets */ 1147 opts.printVars = 0; 1148 opts.variables = Lst_New(); 1149 opts.parseWarnFatal = FALSE; 1150 opts.enterFlag = FALSE; 1151 opts.varNoExportEnv = FALSE; 1152 opts.create = Lst_New(); 1153 } 1154 1155 /* Initialize MAKE and .MAKE to the path of the executable, so that it can be 1156 * found by execvp(3) and the shells, even after a chdir. 1157 * 1158 * If it's a relative path and contains a '/', resolve it to an absolute path. 1159 * Otherwise keep it as is, assuming it will be found in the PATH. */ 1160 static void 1161 InitVarMake(const char *argv0) 1162 { 1163 const char *make = argv0; 1164 1165 if (argv0[0] != '/' && strchr(argv0, '/') != NULL) { 1166 char pathbuf[MAXPATHLEN]; 1167 const char *abs = cached_realpath(argv0, pathbuf); 1168 struct stat st; 1169 if (abs != NULL && abs[0] == '/' && stat(make, &st) == 0) 1170 make = abs; 1171 } 1172 1173 Var_Set("MAKE", make, VAR_GLOBAL); 1174 Var_Set(".MAKE", make, VAR_GLOBAL); 1175 } 1176 1177 static void 1178 InitDefSysIncPath(char *syspath) 1179 { 1180 static char defsyspath[] = _PATH_DEFSYSPATH; 1181 char *start, *cp; 1182 1183 /* 1184 * If no user-supplied system path was given (through the -m option) 1185 * add the directories from the DEFSYSPATH (more than one may be given 1186 * as dir1:...:dirn) to the system include path. 1187 */ 1188 /* XXX: mismatch: the -m option sets sysIncPath, not syspath */ 1189 if (syspath == NULL || syspath[0] == '\0') 1190 syspath = defsyspath; 1191 else 1192 syspath = bmake_strdup(syspath); 1193 1194 for (start = syspath; *start != '\0'; start = cp) { 1195 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 1196 continue; 1197 if (*cp == ':') { 1198 *cp++ = '\0'; 1199 } 1200 /* look for magic parent directory search string */ 1201 if (strncmp(".../", start, 4) != 0) { 1202 (void)Dir_AddDir(defSysIncPath, start); 1203 } else { 1204 char *dir = Dir_FindHereOrAbove(curdir, start + 4); 1205 if (dir != NULL) { 1206 (void)Dir_AddDir(defSysIncPath, dir); 1207 free(dir); 1208 } 1209 } 1210 } 1211 1212 if (syspath != defsyspath) 1213 free(syspath); 1214 } 1215 1216 static void 1217 ReadBuiltinRules(void) 1218 { 1219 StringList *sysMkPath = Lst_New(); 1220 Dir_Expand(_PATH_DEFSYSMK, 1221 Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, 1222 sysMkPath); 1223 if (Lst_IsEmpty(sysMkPath)) 1224 Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); 1225 if (!Lst_ForEachUntil(sysMkPath, ReadMakefileSucceeded, NULL)) 1226 Fatal("%s: cannot open %s.", progname, 1227 (char *)sysMkPath->first->datum); 1228 /* XXX: sysMkPath is not freed */ 1229 } 1230 1231 static void 1232 InitMaxJobs(void) 1233 { 1234 char *value; 1235 int n; 1236 1237 if (forceJobs || opts.compatMake || 1238 !Var_Exists(".MAKE.JOBS", VAR_GLOBAL)) 1239 return; 1240 1241 (void)Var_Subst("${.MAKE.JOBS}", VAR_GLOBAL, VARE_WANTRES, &value); 1242 /* TODO: handle errors */ 1243 n = (int)strtol(value, NULL, 0); 1244 if (n < 1) { 1245 (void)fprintf(stderr, 1246 "%s: illegal value for .MAKE.JOBS " 1247 "-- must be positive integer!\n", 1248 progname); 1249 exit(1); 1250 } 1251 1252 if (n != opts.maxJobs) { 1253 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 1254 Var_Append(MAKEFLAGS, value, VAR_GLOBAL); 1255 } 1256 1257 opts.maxJobs = n; 1258 maxJobTokens = opts.maxJobs; 1259 forceJobs = TRUE; 1260 free(value); 1261 } 1262 1263 /* 1264 * For compatibility, look at the directories in the VPATH variable 1265 * and add them to the search path, if the variable is defined. The 1266 * variable's value is in the same format as the PATH environment 1267 * variable, i.e. <directory>:<directory>:<directory>... 1268 */ 1269 static void 1270 InitVpath(void) 1271 { 1272 char *vpath, savec, *path; 1273 if (!Var_Exists("VPATH", VAR_CMDLINE)) 1274 return; 1275 1276 (void)Var_Subst("${VPATH}", VAR_CMDLINE, VARE_WANTRES, &vpath); 1277 /* TODO: handle errors */ 1278 path = vpath; 1279 do { 1280 char *cp; 1281 /* skip to end of directory */ 1282 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 1283 continue; 1284 /* Save terminator character so know when to stop */ 1285 savec = *cp; 1286 *cp = '\0'; 1287 /* Add directory to search path */ 1288 (void)Dir_AddDir(dirSearchPath, path); 1289 *cp = savec; 1290 path = cp + 1; 1291 } while (savec == ':'); 1292 free(vpath); 1293 } 1294 1295 static void 1296 ReadMakefiles(void) 1297 { 1298 if (opts.makefiles->first != NULL) { 1299 StringListNode *ln; 1300 1301 for (ln = opts.makefiles->first; ln != NULL; ln = ln->next) { 1302 if (ReadMakefile(ln->datum) != 0) 1303 Fatal("%s: cannot open %s.", 1304 progname, (char *)ln->datum); 1305 } 1306 } else { 1307 char *p1; 1308 (void)Var_Subst("${" MAKEFILE_PREFERENCE "}", 1309 VAR_CMDLINE, VARE_WANTRES, &p1); 1310 /* TODO: handle errors */ 1311 (void)str2Lst_Append(opts.makefiles, p1, NULL); 1312 (void)Lst_ForEachUntil(opts.makefiles, 1313 ReadMakefileSucceeded, NULL); 1314 free(p1); 1315 } 1316 } 1317 1318 static void 1319 CleanUp(void) 1320 { 1321 #ifdef CLEANUP 1322 Lst_Destroy(opts.variables, free); 1323 Lst_Free(opts.makefiles); /* don't free, may be used in GNodes */ 1324 Lst_Destroy(opts.create, free); 1325 #endif 1326 1327 /* print the graph now it's been processed if the user requested it */ 1328 if (DEBUG(GRAPH2)) 1329 Targ_PrintGraph(2); 1330 1331 Trace_Log(MAKEEND, 0); 1332 1333 if (enterFlagObj) 1334 printf("%s: Leaving directory `%s'\n", progname, objdir); 1335 if (opts.enterFlag) 1336 printf("%s: Leaving directory `%s'\n", progname, curdir); 1337 1338 #ifdef USE_META 1339 meta_finish(); 1340 #endif 1341 Suff_End(); 1342 Targ_End(); 1343 Arch_End(); 1344 Var_End(); 1345 Parse_End(); 1346 Dir_End(); 1347 Job_End(); 1348 Trace_End(); 1349 } 1350 1351 /*- 1352 * main -- 1353 * The main function, for obvious reasons. Initializes variables 1354 * and a few modules, then parses the arguments give it in the 1355 * environment and on the command line. Reads the system makefile 1356 * followed by either Makefile, makefile or the file given by the 1357 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 1358 * flags it has received by then uses either the Make or the Compat 1359 * module to create the initial list of targets. 1360 * 1361 * Results: 1362 * If -q was given, exits -1 if anything was out-of-date. Else it exits 1363 * 0. 1364 * 1365 * Side Effects: 1366 * The program exits when done. Targets are created. etc. etc. etc. 1367 */ 1368 int 1369 main(int argc, char **argv) 1370 { 1371 Boolean outOfDate; /* FALSE if all targets up to date */ 1372 struct stat sa; 1373 const char *machine; 1374 const char *machine_arch; 1375 char *syspath = getenv("MAKESYSPATH"); 1376 struct utsname utsname; 1377 1378 /* default to writing debug to stderr */ 1379 opts.debug_file = stderr; 1380 1381 #ifdef SIGINFO 1382 (void)bmake_signal(SIGINFO, siginfo); 1383 #endif 1384 1385 InitRandom(); 1386 1387 if ((progname = strrchr(argv[0], '/')) != NULL) 1388 progname++; 1389 else 1390 progname = argv[0]; 1391 1392 UnlimitFiles(); 1393 1394 if (uname(&utsname) == -1) { 1395 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 1396 strerror(errno)); 1397 exit(2); 1398 } 1399 1400 /* 1401 * Get the name of this type of MACHINE from utsname 1402 * so we can share an executable for similar machines. 1403 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 1404 * 1405 * Note that both MACHINE and MACHINE_ARCH are decided at 1406 * run-time. 1407 */ 1408 machine = init_machine(&utsname); 1409 machine_arch = init_machine_arch(); 1410 1411 myPid = getpid(); /* remember this for vFork() */ 1412 1413 /* 1414 * Just in case MAKEOBJDIR wants us to do something tricky. 1415 */ 1416 Var_Init(); /* Initialize the lists of variables for 1417 * parsing arguments */ 1418 Var_Set(".MAKE.OS", utsname.sysname, VAR_GLOBAL); 1419 Var_Set("MACHINE", machine, VAR_GLOBAL); 1420 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 1421 #ifdef MAKE_VERSION 1422 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL); 1423 #endif 1424 Var_Set(".newline", "\n", VAR_GLOBAL); /* handy for :@ loops */ 1425 /* 1426 * This is the traditional preference for makefiles. 1427 */ 1428 #ifndef MAKEFILE_PREFERENCE_LIST 1429 # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" 1430 #endif 1431 Var_Set(MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, 1432 VAR_GLOBAL); 1433 Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); 1434 1435 CmdOpts_Init(); 1436 allPrecious = FALSE; /* Remove targets when interrupted */ 1437 deleteOnError = FALSE; /* Historical default behavior */ 1438 jobsRunning = FALSE; 1439 1440 maxJobTokens = opts.maxJobs; 1441 ignorePWD = FALSE; 1442 1443 /* 1444 * Initialize the parsing, directory and variable modules to prepare 1445 * for the reading of inclusion paths and variable settings on the 1446 * command line 1447 */ 1448 1449 /* 1450 * Initialize various variables. 1451 * MAKE also gets this name, for compatibility 1452 * .MAKEFLAGS gets set to the empty string just in case. 1453 * MFLAGS also gets initialized empty, for compatibility. 1454 */ 1455 Parse_Init(); 1456 InitVarMake(argv[0]); 1457 Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 1458 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL); 1459 Var_Set("MFLAGS", "", VAR_GLOBAL); 1460 Var_Set(".ALLTARGETS", "", VAR_GLOBAL); 1461 /* some makefiles need to know this */ 1462 Var_Set(MAKE_LEVEL ".ENV", MAKE_LEVEL_ENV, VAR_CMDLINE); 1463 1464 /* 1465 * Set some other useful macros 1466 */ 1467 { 1468 char tmp[64], *ep; 1469 1470 makelevel = ((ep = getenv(MAKE_LEVEL_ENV)) && *ep) ? atoi(ep) : 0; 1471 if (makelevel < 0) 1472 makelevel = 0; 1473 snprintf(tmp, sizeof(tmp), "%d", makelevel); 1474 Var_Set(MAKE_LEVEL, tmp, VAR_GLOBAL); 1475 snprintf(tmp, sizeof(tmp), "%u", myPid); 1476 Var_Set(".MAKE.PID", tmp, VAR_GLOBAL); 1477 snprintf(tmp, sizeof(tmp), "%u", getppid()); 1478 Var_Set(".MAKE.PPID", tmp, VAR_GLOBAL); 1479 } 1480 if (makelevel > 0) { 1481 char pn[1024]; 1482 snprintf(pn, sizeof(pn), "%s[%d]", progname, makelevel); 1483 progname = bmake_strdup(pn); 1484 } 1485 1486 #ifdef USE_META 1487 meta_init(); 1488 #endif 1489 Dir_Init(); 1490 1491 /* 1492 * First snag any flags out of the MAKE environment variable. 1493 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 1494 * in a different format). 1495 */ 1496 #ifdef POSIX 1497 { 1498 char *p1 = explode(getenv("MAKEFLAGS")); 1499 Main_ParseArgLine(p1); 1500 free(p1); 1501 } 1502 #else 1503 Main_ParseArgLine(getenv("MAKE")); 1504 #endif 1505 1506 /* 1507 * Find where we are (now). 1508 * We take care of PWD for the automounter below... 1509 */ 1510 if (getcwd(curdir, MAXPATHLEN) == NULL) { 1511 (void)fprintf(stderr, "%s: getcwd: %s.\n", 1512 progname, strerror(errno)); 1513 exit(2); 1514 } 1515 1516 MainParseArgs(argc, argv); 1517 1518 if (opts.enterFlag) 1519 printf("%s: Entering directory `%s'\n", progname, curdir); 1520 1521 /* 1522 * Verify that cwd is sane. 1523 */ 1524 if (stat(curdir, &sa) == -1) { 1525 (void)fprintf(stderr, "%s: %s: %s.\n", 1526 progname, curdir, strerror(errno)); 1527 exit(2); 1528 } 1529 1530 #ifndef NO_PWD_OVERRIDE 1531 HandlePWD(&sa); 1532 #endif 1533 Var_Set(".CURDIR", curdir, VAR_GLOBAL); 1534 1535 InitObjdir(machine, machine_arch); 1536 1537 /* 1538 * Initialize archive, target and suffix modules in preparation for 1539 * parsing the makefile(s) 1540 */ 1541 Arch_Init(); 1542 Targ_Init(); 1543 Suff_Init(); 1544 Trace_Init(tracefile); 1545 1546 DEFAULT = NULL; 1547 (void)time(&now); 1548 1549 Trace_Log(MAKESTART, NULL); 1550 1551 InitVarTargets(); 1552 1553 InitDefSysIncPath(syspath); 1554 1555 /* 1556 * Read in the built-in rules first, followed by the specified 1557 * makefiles, or the default makefile and Makefile, in that order, 1558 * if no makefiles were given on the command line. 1559 */ 1560 if (!opts.noBuiltins) 1561 ReadBuiltinRules(); 1562 ReadMakefiles(); 1563 1564 /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ 1565 if (!opts.noBuiltins || !opts.printVars) { 1566 /* ignore /dev/null and anything starting with "no" */ 1567 (void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", 1568 VAR_CMDLINE, VARE_WANTRES, &makeDependfile); 1569 if (makeDependfile[0] != '\0') { 1570 /* TODO: handle errors */ 1571 doing_depend = TRUE; 1572 (void)ReadMakefile(makeDependfile); 1573 doing_depend = FALSE; 1574 } 1575 } 1576 1577 if (enterFlagObj) 1578 printf("%s: Entering directory `%s'\n", progname, objdir); 1579 1580 MakeMode(NULL); 1581 1582 { 1583 void *freeIt; 1584 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), 1585 VAR_GLOBAL); 1586 bmake_free(freeIt); 1587 1588 } 1589 1590 InitMaxJobs(); 1591 1592 /* 1593 * Be compatible if user did not specify -j and did not explicitly 1594 * turned compatibility on 1595 */ 1596 if (!opts.compatMake && !forceJobs) { 1597 opts.compatMake = TRUE; 1598 } 1599 1600 if (!opts.compatMake) 1601 Job_ServerStart(maxJobTokens, jp_0, jp_1); 1602 DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", 1603 jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); 1604 1605 if (!opts.printVars) 1606 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 1607 1608 InitVpath(); 1609 1610 /* 1611 * Now that all search paths have been read for suffixes et al, it's 1612 * time to add the default search path to their lists... 1613 */ 1614 Suff_DoPaths(); 1615 1616 /* 1617 * Propagate attributes through :: dependency lists. 1618 */ 1619 Targ_Propagate(); 1620 1621 /* print the initial graph, if the user requested it */ 1622 if (DEBUG(GRAPH1)) 1623 Targ_PrintGraph(1); 1624 1625 /* print the values of any variables requested by the user */ 1626 if (opts.printVars) { 1627 doPrintVars(); 1628 outOfDate = FALSE; 1629 } else { 1630 outOfDate = runTargets(); 1631 } 1632 1633 CleanUp(); 1634 1635 if (DEBUG(LINT) && (errors > 0 || Parse_GetFatals() > 0)) 1636 return 2; /* Not 1 so -q can distinguish error */ 1637 return outOfDate ? 1 : 0; 1638 } 1639 1640 /* Open and parse the given makefile, with all its side effects. 1641 * 1642 * Results: 1643 * 0 if ok. -1 if couldn't open file. 1644 */ 1645 static int 1646 ReadMakefile(const char *fname) 1647 { 1648 int fd; 1649 char *name, *path = NULL; 1650 1651 if (!strcmp(fname, "-")) { 1652 Parse_File(NULL /*stdin*/, -1); 1653 Var_Set("MAKEFILE", "", VAR_INTERNAL); 1654 } else { 1655 /* if we've chdir'd, rebuild the path name */ 1656 if (strcmp(curdir, objdir) && *fname != '/') { 1657 path = str_concat3(curdir, "/", fname); 1658 fd = open(path, O_RDONLY); 1659 if (fd != -1) { 1660 fname = path; 1661 goto found; 1662 } 1663 free(path); 1664 1665 /* If curdir failed, try objdir (ala .depend) */ 1666 path = str_concat3(objdir, "/", fname); 1667 fd = open(path, O_RDONLY); 1668 if (fd != -1) { 1669 fname = path; 1670 goto found; 1671 } 1672 } else { 1673 fd = open(fname, O_RDONLY); 1674 if (fd != -1) 1675 goto found; 1676 } 1677 /* look in -I and system include directories. */ 1678 name = Dir_FindFile(fname, parseIncPath); 1679 if (!name) { 1680 SearchPath *sysInc = Lst_IsEmpty(sysIncPath) 1681 ? defSysIncPath : sysIncPath; 1682 name = Dir_FindFile(fname, sysInc); 1683 } 1684 if (!name || (fd = open(name, O_RDONLY)) == -1) { 1685 free(name); 1686 free(path); 1687 return -1; 1688 } 1689 fname = name; 1690 /* 1691 * set the MAKEFILE variable desired by System V fans -- the 1692 * placement of the setting here means it gets set to the last 1693 * makefile specified, as it is set by SysV make. 1694 */ 1695 found: 1696 if (!doing_depend) 1697 Var_Set("MAKEFILE", fname, VAR_INTERNAL); 1698 Parse_File(fname, fd); 1699 } 1700 free(path); 1701 return 0; 1702 } 1703 1704 1705 1706 /*- 1707 * Cmd_Exec -- 1708 * Execute the command in cmd, and return the output of that command 1709 * in a string. In the output, newlines are replaced with spaces. 1710 * 1711 * Results: 1712 * A string containing the output of the command, or the empty string. 1713 * *errfmt returns a format string describing the command failure, 1714 * if any, using a single %s conversion specification. 1715 * 1716 * Side Effects: 1717 * The string must be freed by the caller. 1718 */ 1719 char * 1720 Cmd_Exec(const char *cmd, const char **errfmt) 1721 { 1722 const char *args[4]; /* Args for invoking the shell */ 1723 int fds[2]; /* Pipe streams */ 1724 int cpid; /* Child PID */ 1725 int pid; /* PID from wait() */ 1726 WAIT_T status; /* command exit status */ 1727 Buffer buf; /* buffer to store the result */ 1728 ssize_t bytes_read; 1729 char *res; /* result */ 1730 size_t res_len; 1731 char *cp; 1732 int savederr; /* saved errno */ 1733 1734 *errfmt = NULL; 1735 1736 if (!shellName) 1737 Shell_Init(); 1738 /* 1739 * Set up arguments for shell 1740 */ 1741 args[0] = shellName; 1742 args[1] = "-c"; 1743 args[2] = cmd; 1744 args[3] = NULL; 1745 1746 /* 1747 * Open a pipe for fetching its output 1748 */ 1749 if (pipe(fds) == -1) { 1750 *errfmt = "Couldn't create pipe for \"%s\""; 1751 goto bad; 1752 } 1753 1754 /* 1755 * Fork 1756 */ 1757 switch (cpid = vFork()) { 1758 case 0: 1759 /* 1760 * Close input side of pipe 1761 */ 1762 (void)close(fds[0]); 1763 1764 /* 1765 * Duplicate the output stream to the shell's output, then 1766 * shut the extra thing down. Note we don't fetch the error 1767 * stream...why not? Why? 1768 */ 1769 (void)dup2(fds[1], 1); 1770 (void)close(fds[1]); 1771 1772 Var_ExportVars(); 1773 1774 (void)execv(shellPath, UNCONST(args)); 1775 _exit(1); 1776 /*NOTREACHED*/ 1777 1778 case -1: 1779 *errfmt = "Couldn't exec \"%s\""; 1780 goto bad; 1781 1782 default: 1783 /* 1784 * No need for the writing half 1785 */ 1786 (void)close(fds[1]); 1787 1788 savederr = 0; 1789 Buf_Init(&buf, 0); 1790 1791 do { 1792 char result[BUFSIZ]; 1793 bytes_read = read(fds[0], result, sizeof(result)); 1794 if (bytes_read > 0) 1795 Buf_AddBytes(&buf, result, (size_t)bytes_read); 1796 } 1797 while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); 1798 if (bytes_read == -1) 1799 savederr = errno; 1800 1801 /* 1802 * Close the input side of the pipe. 1803 */ 1804 (void)close(fds[0]); 1805 1806 /* 1807 * Wait for the process to exit. 1808 */ 1809 while(((pid = waitpid(cpid, &status, 0)) != cpid) && (pid >= 0)) { 1810 JobReapChild(pid, status, FALSE); 1811 continue; 1812 } 1813 res_len = Buf_Len(&buf); 1814 res = Buf_Destroy(&buf, FALSE); 1815 1816 if (savederr != 0) 1817 *errfmt = "Couldn't read shell's output for \"%s\""; 1818 1819 if (WIFSIGNALED(status)) 1820 *errfmt = "\"%s\" exited on a signal"; 1821 else if (WEXITSTATUS(status) != 0) 1822 *errfmt = "\"%s\" returned non-zero status"; 1823 1824 /* Convert newlines to spaces. A final newline is just stripped */ 1825 if (res_len > 0 && res[res_len - 1] == '\n') 1826 res[res_len - 1] = '\0'; 1827 for (cp = res; *cp != '\0'; cp++) 1828 if (*cp == '\n') 1829 *cp = ' '; 1830 break; 1831 } 1832 return res; 1833 bad: 1834 return bmake_strdup(""); 1835 } 1836 1837 /* Print a printf-style error message. 1838 * 1839 * This error message has no consequences, in particular it does not affect 1840 * the exit status. */ 1841 void 1842 Error(const char *fmt, ...) 1843 { 1844 va_list ap; 1845 FILE *err_file; 1846 1847 err_file = opts.debug_file; 1848 if (err_file == stdout) 1849 err_file = stderr; 1850 (void)fflush(stdout); 1851 for (;;) { 1852 va_start(ap, fmt); 1853 fprintf(err_file, "%s: ", progname); 1854 (void)vfprintf(err_file, fmt, ap); 1855 va_end(ap); 1856 (void)fprintf(err_file, "\n"); 1857 (void)fflush(err_file); 1858 if (err_file == stderr) 1859 break; 1860 err_file = stderr; 1861 } 1862 errors++; 1863 } 1864 1865 /* Produce a Fatal error message, then exit immediately. 1866 * 1867 * If jobs are running, wait for them to finish. */ 1868 void 1869 Fatal(const char *fmt, ...) 1870 { 1871 va_list ap; 1872 1873 va_start(ap, fmt); 1874 if (jobsRunning) 1875 Job_Wait(); 1876 1877 (void)fflush(stdout); 1878 (void)vfprintf(stderr, fmt, ap); 1879 va_end(ap); 1880 (void)fprintf(stderr, "\n"); 1881 (void)fflush(stderr); 1882 1883 PrintOnError(NULL, NULL); 1884 1885 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1886 Targ_PrintGraph(2); 1887 Trace_Log(MAKEERROR, 0); 1888 exit(2); /* Not 1 so -q can distinguish error */ 1889 } 1890 1891 /* Major exception once jobs are being created. 1892 * Kills all jobs, prints a message and exits. */ 1893 void 1894 Punt(const char *fmt, ...) 1895 { 1896 va_list ap; 1897 1898 va_start(ap, fmt); 1899 (void)fflush(stdout); 1900 (void)fprintf(stderr, "%s: ", progname); 1901 (void)vfprintf(stderr, fmt, ap); 1902 va_end(ap); 1903 (void)fprintf(stderr, "\n"); 1904 (void)fflush(stderr); 1905 1906 PrintOnError(NULL, NULL); 1907 1908 DieHorribly(); 1909 } 1910 1911 /* Exit without giving a message. */ 1912 void 1913 DieHorribly(void) 1914 { 1915 if (jobsRunning) 1916 Job_AbortAll(); 1917 if (DEBUG(GRAPH2)) 1918 Targ_PrintGraph(2); 1919 Trace_Log(MAKEERROR, 0); 1920 exit(2); /* Not 1, so -q can distinguish error */ 1921 } 1922 1923 /* Called when aborting due to errors in child shell to signal abnormal exit. 1924 * The program exits. 1925 * Errors is the number of errors encountered in Make_Make. */ 1926 void 1927 Finish(int errs) 1928 { 1929 if (dieQuietly(NULL, -1)) 1930 exit(2); 1931 Fatal("%d error%s", errs, errs == 1 ? "" : "s"); 1932 } 1933 1934 /* 1935 * eunlink -- 1936 * Remove a file carefully, avoiding directories. 1937 */ 1938 int 1939 eunlink(const char *file) 1940 { 1941 struct stat st; 1942 1943 if (lstat(file, &st) == -1) 1944 return -1; 1945 1946 if (S_ISDIR(st.st_mode)) { 1947 errno = EISDIR; 1948 return -1; 1949 } 1950 return unlink(file); 1951 } 1952 1953 static void 1954 write_all(int fd, const void *data, size_t n) 1955 { 1956 const char *mem = data; 1957 1958 while (n > 0) { 1959 ssize_t written = write(fd, mem, n); 1960 if (written == -1 && errno == EAGAIN) 1961 continue; 1962 if (written == -1) 1963 break; 1964 mem += written; 1965 n -= (size_t)written; 1966 } 1967 } 1968 1969 /* 1970 * execDie -- 1971 * Print why exec failed, avoiding stdio. 1972 */ 1973 void MAKE_ATTR_DEAD 1974 execDie(const char *af, const char *av) 1975 { 1976 Buffer buf; 1977 1978 Buf_Init(&buf, 0); 1979 Buf_AddStr(&buf, progname); 1980 Buf_AddStr(&buf, ": "); 1981 Buf_AddStr(&buf, af); 1982 Buf_AddStr(&buf, "("); 1983 Buf_AddStr(&buf, av); 1984 Buf_AddStr(&buf, ") failed ("); 1985 Buf_AddStr(&buf, strerror(errno)); 1986 Buf_AddStr(&buf, ")\n"); 1987 1988 write_all(STDERR_FILENO, Buf_GetAll(&buf, NULL), Buf_Len(&buf)); 1989 1990 Buf_Destroy(&buf, TRUE); 1991 _exit(1); 1992 } 1993 1994 /* 1995 * usage -- 1996 * exit with usage message 1997 */ 1998 static void 1999 usage(void) 2000 { 2001 char *p; 2002 if ((p = strchr(progname, '[')) != NULL) 2003 *p = '\0'; 2004 2005 (void)fprintf(stderr, 2006 "usage: %s [-BeikNnqrstWwX] \n" 2007 " [-C directory] [-D variable] [-d flags] [-f makefile]\n" 2008 " [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" 2009 " [-V variable] [-v variable] [variable=value] [target ...]\n", 2010 progname); 2011 exit(2); 2012 } 2013 2014 /* 2015 * realpath(3) can get expensive, cache results... 2016 */ 2017 static GNode *cached_realpaths = NULL; 2018 2019 static GNode * 2020 get_cached_realpaths(void) 2021 { 2022 2023 if (!cached_realpaths) { 2024 cached_realpaths = Targ_NewGN("Realpath"); 2025 #ifndef DEBUG_REALPATH_CACHE 2026 cached_realpaths->flags = INTERNAL; 2027 #endif 2028 } 2029 2030 return cached_realpaths; 2031 } 2032 2033 /* purge any relative paths */ 2034 static void 2035 purge_cached_realpaths(void) 2036 { 2037 GNode *cache = get_cached_realpaths(); 2038 HashEntry *he, *nhe; 2039 HashIter hi; 2040 2041 HashIter_Init(&hi, &cache->context); 2042 he = HashIter_Next(&hi); 2043 while (he != NULL) { 2044 nhe = HashIter_Next(&hi); 2045 if (he->key[0] != '/') { 2046 if (DEBUG(DIR)) 2047 fprintf(stderr, "cached_realpath: purging %s\n", he->key); 2048 HashTable_DeleteEntry(&cache->context, he); 2049 } 2050 he = nhe; 2051 } 2052 } 2053 2054 char * 2055 cached_realpath(const char *pathname, char *resolved) 2056 { 2057 GNode *cache; 2058 const char *rp; 2059 void *freeIt; 2060 2061 if (!pathname || !pathname[0]) 2062 return NULL; 2063 2064 cache = get_cached_realpaths(); 2065 2066 if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) { 2067 /* a hit */ 2068 strlcpy(resolved, rp, MAXPATHLEN); 2069 } else if ((rp = realpath(pathname, resolved)) != NULL) { 2070 Var_Set(pathname, rp, cache); 2071 } /* else should we negative-cache? */ 2072 2073 bmake_free(freeIt); 2074 return rp ? resolved : NULL; 2075 } 2076 2077 /* 2078 * Return true if we should die without noise. 2079 * For example our failing child was a sub-make 2080 * or failure happend elsewhere. 2081 */ 2082 int 2083 dieQuietly(GNode *gn, int bf) 2084 { 2085 static int quietly = -1; 2086 2087 if (quietly < 0) { 2088 if (DEBUG(JOB) || !getBoolean(".MAKE.DIE_QUIETLY", TRUE)) 2089 quietly = 0; 2090 else if (bf >= 0) 2091 quietly = bf; 2092 else 2093 quietly = gn != NULL ? ((gn->type & (OP_MAKE)) != 0) : 0; 2094 } 2095 return quietly; 2096 } 2097 2098 static void 2099 SetErrorVars(GNode *gn) 2100 { 2101 StringListNode *ln; 2102 2103 /* 2104 * We can print this even if there is no .ERROR target. 2105 */ 2106 Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); 2107 Var_Delete(".ERROR_CMD", VAR_GLOBAL); 2108 2109 for (ln = gn->commands->first; ln != NULL; ln = ln->next) { 2110 const char *cmd = ln->datum; 2111 2112 if (cmd == NULL) 2113 break; 2114 Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); 2115 } 2116 } 2117 2118 void 2119 PrintOnError(GNode *gn, const char *s) 2120 { 2121 static GNode *en = NULL; 2122 const char *expr; 2123 char *cp; 2124 2125 if (DEBUG(HASH)) { 2126 Targ_Stats(); 2127 Var_Stats(); 2128 } 2129 2130 /* we generally want to keep quiet if a sub-make died */ 2131 if (dieQuietly(gn, -1)) 2132 return; 2133 2134 if (s) 2135 printf("%s", s); 2136 2137 printf("\n%s: stopped in %s\n", progname, curdir); 2138 2139 if (en) 2140 return; /* we've been here! */ 2141 if (gn) 2142 SetErrorVars(gn); 2143 expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; 2144 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); 2145 /* TODO: handle errors */ 2146 printf("%s", cp); 2147 free(cp); 2148 fflush(stdout); 2149 2150 /* 2151 * Finally, see if there is a .ERROR target, and run it if so. 2152 */ 2153 en = Targ_FindNode(".ERROR"); 2154 if (en) { 2155 en->type |= OP_SPECIAL; 2156 Compat_Make(en, en); 2157 } 2158 } 2159 2160 void 2161 Main_ExportMAKEFLAGS(Boolean first) 2162 { 2163 static Boolean once = TRUE; 2164 const char *expr; 2165 char *s; 2166 2167 if (once != first) 2168 return; 2169 once = FALSE; 2170 2171 expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; 2172 (void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); 2173 /* TODO: handle errors */ 2174 if (s[0] != '\0') { 2175 #ifdef POSIX 2176 setenv("MAKEFLAGS", s, 1); 2177 #else 2178 setenv("MAKE", s, 1); 2179 #endif 2180 } 2181 } 2182 2183 char * 2184 getTmpdir(void) 2185 { 2186 static char *tmpdir = NULL; 2187 2188 if (!tmpdir) { 2189 struct stat st; 2190 2191 /* 2192 * Honor $TMPDIR but only if it is valid. 2193 * Ensure it ends with /. 2194 */ 2195 (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, 2196 VARE_WANTRES, &tmpdir); 2197 /* TODO: handle errors */ 2198 if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { 2199 free(tmpdir); 2200 tmpdir = bmake_strdup(_PATH_TMP); 2201 } 2202 } 2203 return tmpdir; 2204 } 2205 2206 /* 2207 * Create and open a temp file using "pattern". 2208 * If out_fname is provided, set it to a copy of the filename created. 2209 * Otherwise unlink the file once open. 2210 */ 2211 int 2212 mkTempFile(const char *pattern, char **out_fname) 2213 { 2214 static char *tmpdir = NULL; 2215 char tfile[MAXPATHLEN]; 2216 int fd; 2217 2218 if (pattern != NULL) 2219 pattern = TMPPAT; 2220 if (tmpdir == NULL) 2221 tmpdir = getTmpdir(); 2222 if (pattern[0] == '/') { 2223 snprintf(tfile, sizeof(tfile), "%s", pattern); 2224 } else { 2225 snprintf(tfile, sizeof(tfile), "%s%s", tmpdir, pattern); 2226 } 2227 if ((fd = mkstemp(tfile)) < 0) 2228 Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); 2229 if (out_fname) { 2230 *out_fname = bmake_strdup(tfile); 2231 } else { 2232 unlink(tfile); /* we just want the descriptor */ 2233 } 2234 return fd; 2235 } 2236 2237 /* 2238 * Convert a string representation of a boolean. 2239 * Anything that looks like "No", "False", "Off", "0" etc, 2240 * is FALSE, otherwise TRUE. 2241 */ 2242 Boolean 2243 s2Boolean(const char *s, Boolean bf) 2244 { 2245 switch(s[0]) { 2246 case '\0': /* not set - the default wins */ 2247 break; 2248 case '0': 2249 case 'F': 2250 case 'f': 2251 case 'N': 2252 case 'n': 2253 return FALSE; 2254 case 'O': 2255 case 'o': 2256 return s[1] != 'F' && s[1] != 'f'; 2257 default: 2258 return TRUE; 2259 } 2260 return bf; 2261 } 2262 2263 /* 2264 * Return a Boolean based on a variable. 2265 * 2266 * If the knob is not set, return the fallback. 2267 * If set, anything that looks or smells like "No", "False", "Off", "0", etc. 2268 * is FALSE, otherwise TRUE. 2269 */ 2270 Boolean 2271 getBoolean(const char *varname, Boolean fallback) 2272 { 2273 char *expr = str_concat3("${", varname, ":U}"); 2274 char *value; 2275 Boolean res; 2276 2277 (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); 2278 /* TODO: handle errors */ 2279 res = s2Boolean(value, fallback); 2280 free(value); 2281 free(expr); 2282 return res; 2283 } 2284