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