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