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