github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/src/ninja.cc (about) 1 // Copyright 2011 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <errno.h> 16 #include <limits.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <cstdlib> 21 22 #ifdef _WIN32 23 #include "getopt.h" 24 #include <direct.h> 25 #include <windows.h> 26 #elif defined(_AIX) 27 #include "getopt.h" 28 #include <unistd.h> 29 #else 30 #include <getopt.h> 31 #include <unistd.h> 32 #endif 33 34 #include "browse.h" 35 #include "build.h" 36 #include "build_log.h" 37 #include "deps_log.h" 38 #include "clean.h" 39 #include "debug_flags.h" 40 #include "depfile_parser.h" 41 #include "disk_interface.h" 42 #include "graph.h" 43 #include "graphviz.h" 44 #include "json.h" 45 #include "manifest_parser.h" 46 #include "metrics.h" 47 #include "missing_deps.h" 48 #include "state.h" 49 #include "status.h" 50 #include "util.h" 51 #include "version.h" 52 53 using namespace std; 54 55 #ifdef _MSC_VER 56 // Defined in msvc_helper_main-win32.cc. 57 int MSVCHelperMain(int argc, char** argv); 58 59 // Defined in minidump-win32.cc. 60 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep); 61 #endif 62 63 namespace { 64 65 struct Tool; 66 67 /// Command-line options. 68 struct Options { 69 /// Build file to load. 70 const char* input_file; 71 72 /// Directory to change into before running. 73 const char* working_dir; 74 75 /// Tool to run rather than building. 76 const Tool* tool; 77 78 /// Whether duplicate rules for one target should warn or print an error. 79 bool dupe_edges_should_err; 80 81 /// Whether phony cycles should warn or print an error. 82 bool phony_cycle_should_err; 83 }; 84 85 /// The Ninja main() loads up a series of data structures; various tools need 86 /// to poke into these, so store them as fields on an object. 87 struct NinjaMain : public BuildLogUser { 88 NinjaMain(const char* ninja_command, const BuildConfig& config) : 89 ninja_command_(ninja_command), config_(config), 90 start_time_millis_(GetTimeMillis()) {} 91 92 /// Command line used to run Ninja. 93 const char* ninja_command_; 94 95 /// Build configuration set from flags (e.g. parallelism). 96 const BuildConfig& config_; 97 98 /// Loaded state (rules, nodes). 99 State state_; 100 101 /// Functions for accessing the disk. 102 RealDiskInterface disk_interface_; 103 104 /// The build directory, used for storing the build log etc. 105 string build_dir_; 106 107 BuildLog build_log_; 108 DepsLog deps_log_; 109 110 /// The type of functions that are the entry points to tools (subcommands). 111 typedef int (NinjaMain::*ToolFunc)(const Options*, int, char**); 112 113 /// Get the Node for a given command-line path, handling features like 114 /// spell correction. 115 Node* CollectTarget(const char* cpath, string* err); 116 117 /// CollectTarget for all command-line arguments, filling in \a targets. 118 bool CollectTargetsFromArgs(int argc, char* argv[], 119 vector<Node*>* targets, string* err); 120 121 // The various subcommands, run via "-t XXX". 122 int ToolGraph(const Options* options, int argc, char* argv[]); 123 int ToolQuery(const Options* options, int argc, char* argv[]); 124 int ToolDeps(const Options* options, int argc, char* argv[]); 125 int ToolMissingDeps(const Options* options, int argc, char* argv[]); 126 int ToolBrowse(const Options* options, int argc, char* argv[]); 127 int ToolMSVC(const Options* options, int argc, char* argv[]); 128 int ToolTargets(const Options* options, int argc, char* argv[]); 129 int ToolCommands(const Options* options, int argc, char* argv[]); 130 int ToolClean(const Options* options, int argc, char* argv[]); 131 int ToolCleanDead(const Options* options, int argc, char* argv[]); 132 int ToolCompilationDatabase(const Options* options, int argc, char* argv[]); 133 int ToolRecompact(const Options* options, int argc, char* argv[]); 134 int ToolRestat(const Options* options, int argc, char* argv[]); 135 int ToolUrtle(const Options* options, int argc, char** argv); 136 int ToolRules(const Options* options, int argc, char* argv[]); 137 int ToolWinCodePage(const Options* options, int argc, char* argv[]); 138 139 /// Open the build log. 140 /// @return false on error. 141 bool OpenBuildLog(bool recompact_only = false); 142 143 /// Open the deps log: load it, then open for writing. 144 /// @return false on error. 145 bool OpenDepsLog(bool recompact_only = false); 146 147 /// Ensure the build directory exists, creating it if necessary. 148 /// @return false on error. 149 bool EnsureBuildDirExists(); 150 151 /// Rebuild the manifest, if necessary. 152 /// Fills in \a err on error. 153 /// @return true if the manifest was rebuilt. 154 bool RebuildManifest(const char* input_file, string* err, Status* status); 155 156 /// Build the targets listed on the command line. 157 /// @return an exit code. 158 int RunBuild(int argc, char** argv, Status* status); 159 160 /// Dump the output requested by '-d stats'. 161 void DumpMetrics(); 162 163 virtual bool IsPathDead(StringPiece s) const { 164 Node* n = state_.LookupNode(s); 165 if (n && n->in_edge()) 166 return false; 167 // Just checking n isn't enough: If an old output is both in the build log 168 // and in the deps log, it will have a Node object in state_. (It will also 169 // have an in edge if one of its inputs is another output that's in the deps 170 // log, but having a deps edge product an output that's input to another deps 171 // edge is rare, and the first recompaction will delete all old outputs from 172 // the deps log, and then a second recompaction will clear the build log, 173 // which seems good enough for this corner case.) 174 // Do keep entries around for files which still exist on disk, for 175 // generators that want to use this information. 176 string err; 177 TimeStamp mtime = disk_interface_.Stat(s.AsString(), &err); 178 if (mtime == -1) 179 Error("%s", err.c_str()); // Log and ignore Stat() errors. 180 return mtime == 0; 181 } 182 183 int64_t start_time_millis_; 184 }; 185 186 /// Subtools, accessible via "-t foo". 187 struct Tool { 188 /// Short name of the tool. 189 const char* name; 190 191 /// Description (shown in "-t list"). 192 const char* desc; 193 194 /// When to run the tool. 195 enum { 196 /// Run after parsing the command-line flags and potentially changing 197 /// the current working directory (as early as possible). 198 RUN_AFTER_FLAGS, 199 200 /// Run after loading build.ninja. 201 RUN_AFTER_LOAD, 202 203 /// Run after loading the build/deps logs. 204 RUN_AFTER_LOGS, 205 } when; 206 207 /// Implementation of the tool. 208 NinjaMain::ToolFunc func; 209 }; 210 211 /// Print usage information. 212 void Usage(const BuildConfig& config) { 213 fprintf(stderr, 214 "usage: ninja [options] [targets...]\n" 215 "\n" 216 "if targets are unspecified, builds the 'default' target (see manual).\n" 217 "\n" 218 "options:\n" 219 " --version print ninja version (\"%s\")\n" 220 " -v, --verbose show all command lines while building\n" 221 " --quiet don't show progress status, just command output\n" 222 "\n" 223 " -C DIR change to DIR before doing anything else\n" 224 " -f FILE specify input build file [default=build.ninja]\n" 225 "\n" 226 " -j N run N jobs in parallel (0 means infinity) [default=%d on this system]\n" 227 " -k N keep going until N jobs fail (0 means infinity) [default=1]\n" 228 " -l N do not start new jobs if the load average is greater than N\n" 229 " -n dry run (don't run commands but act like they succeeded)\n" 230 "\n" 231 " -d MODE enable debugging (use '-d list' to list modes)\n" 232 " -t TOOL run a subtool (use '-t list' to list subtools)\n" 233 " terminates toplevel options; further flags are passed to the tool\n" 234 " -w FLAG adjust warnings (use '-w list' to list warnings)\n", 235 kNinjaVersion, config.parallelism); 236 } 237 238 /// Choose a default value for the -j (parallelism) flag. 239 int GuessParallelism() { 240 switch (int processors = GetProcessorCount()) { 241 case 0: 242 case 1: 243 return 2; 244 case 2: 245 return 3; 246 default: 247 return processors + 2; 248 } 249 } 250 251 /// Rebuild the build manifest, if necessary. 252 /// Returns true if the manifest was rebuilt. 253 bool NinjaMain::RebuildManifest(const char* input_file, string* err, 254 Status* status) { 255 string path = input_file; 256 if (path.empty()) { 257 *err = "empty path"; 258 return false; 259 } 260 uint64_t slash_bits; // Unused because this path is only used for lookup. 261 CanonicalizePath(&path, &slash_bits); 262 Node* node = state_.LookupNode(path); 263 if (!node) 264 return false; 265 266 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_, 267 status, start_time_millis_); 268 if (!builder.AddTarget(node, err)) 269 return false; 270 271 if (builder.AlreadyUpToDate()) 272 return false; // Not an error, but we didn't rebuild. 273 274 if (!builder.Build(err)) 275 return false; 276 277 // The manifest was only rebuilt if it is now dirty (it may have been cleaned 278 // by a restat). 279 if (!node->dirty()) { 280 // Reset the state to prevent problems like 281 // https://github.com/ninja-build/ninja/issues/874 282 state_.Reset(); 283 return false; 284 } 285 286 return true; 287 } 288 289 Node* NinjaMain::CollectTarget(const char* cpath, string* err) { 290 string path = cpath; 291 if (path.empty()) { 292 *err = "empty path"; 293 return NULL; 294 } 295 uint64_t slash_bits; 296 CanonicalizePath(&path, &slash_bits); 297 298 // Special syntax: "foo.cc^" means "the first output of foo.cc". 299 bool first_dependent = false; 300 if (!path.empty() && path[path.size() - 1] == '^') { 301 path.resize(path.size() - 1); 302 first_dependent = true; 303 } 304 305 Node* node = state_.LookupNode(path); 306 if (node) { 307 if (first_dependent) { 308 if (node->out_edges().empty()) { 309 Node* rev_deps = deps_log_.GetFirstReverseDepsNode(node); 310 if (!rev_deps) { 311 *err = "'" + path + "' has no out edge"; 312 return NULL; 313 } 314 node = rev_deps; 315 } else { 316 Edge* edge = node->out_edges()[0]; 317 if (edge->outputs_.empty()) { 318 edge->Dump(); 319 Fatal("edge has no outputs"); 320 } 321 node = edge->outputs_[0]; 322 } 323 } 324 return node; 325 } else { 326 *err = 327 "unknown target '" + Node::PathDecanonicalized(path, slash_bits) + "'"; 328 if (path == "clean") { 329 *err += ", did you mean 'ninja -t clean'?"; 330 } else if (path == "help") { 331 *err += ", did you mean 'ninja -h'?"; 332 } else { 333 Node* suggestion = state_.SpellcheckNode(path); 334 if (suggestion) { 335 *err += ", did you mean '" + suggestion->path() + "'?"; 336 } 337 } 338 return NULL; 339 } 340 } 341 342 bool NinjaMain::CollectTargetsFromArgs(int argc, char* argv[], 343 vector<Node*>* targets, string* err) { 344 if (argc == 0) { 345 *targets = state_.DefaultNodes(err); 346 return err->empty(); 347 } 348 349 for (int i = 0; i < argc; ++i) { 350 Node* node = CollectTarget(argv[i], err); 351 if (node == NULL) 352 return false; 353 targets->push_back(node); 354 } 355 return true; 356 } 357 358 int NinjaMain::ToolGraph(const Options* options, int argc, char* argv[]) { 359 vector<Node*> nodes; 360 string err; 361 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 362 Error("%s", err.c_str()); 363 return 1; 364 } 365 366 GraphViz graph(&state_, &disk_interface_); 367 graph.Start(); 368 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n) 369 graph.AddTarget(*n); 370 graph.Finish(); 371 372 return 0; 373 } 374 375 int NinjaMain::ToolQuery(const Options* options, int argc, char* argv[]) { 376 if (argc == 0) { 377 Error("expected a target to query"); 378 return 1; 379 } 380 381 DyndepLoader dyndep_loader(&state_, &disk_interface_); 382 383 for (int i = 0; i < argc; ++i) { 384 string err; 385 Node* node = CollectTarget(argv[i], &err); 386 if (!node) { 387 Error("%s", err.c_str()); 388 return 1; 389 } 390 391 printf("%s:\n", node->path().c_str()); 392 if (Edge* edge = node->in_edge()) { 393 if (edge->dyndep_ && edge->dyndep_->dyndep_pending()) { 394 if (!dyndep_loader.LoadDyndeps(edge->dyndep_, &err)) { 395 Warning("%s\n", err.c_str()); 396 } 397 } 398 printf(" input: %s\n", edge->rule_->name().c_str()); 399 for (int in = 0; in < (int)edge->inputs_.size(); in++) { 400 const char* label = ""; 401 if (edge->is_implicit(in)) 402 label = "| "; 403 else if (edge->is_order_only(in)) 404 label = "|| "; 405 printf(" %s%s\n", label, edge->inputs_[in]->path().c_str()); 406 } 407 if (!edge->validations_.empty()) { 408 printf(" validations:\n"); 409 for (std::vector<Node*>::iterator validation = edge->validations_.begin(); 410 validation != edge->validations_.end(); ++validation) { 411 printf(" %s\n", (*validation)->path().c_str()); 412 } 413 } 414 } 415 printf(" outputs:\n"); 416 for (vector<Edge*>::const_iterator edge = node->out_edges().begin(); 417 edge != node->out_edges().end(); ++edge) { 418 for (vector<Node*>::iterator out = (*edge)->outputs_.begin(); 419 out != (*edge)->outputs_.end(); ++out) { 420 printf(" %s\n", (*out)->path().c_str()); 421 } 422 } 423 const std::vector<Edge*> validation_edges = node->validation_out_edges(); 424 if (!validation_edges.empty()) { 425 printf(" validation for:\n"); 426 for (std::vector<Edge*>::const_iterator edge = validation_edges.begin(); 427 edge != validation_edges.end(); ++edge) { 428 for (vector<Node*>::iterator out = (*edge)->outputs_.begin(); 429 out != (*edge)->outputs_.end(); ++out) { 430 printf(" %s\n", (*out)->path().c_str()); 431 } 432 } 433 } 434 } 435 return 0; 436 } 437 438 #if defined(NINJA_HAVE_BROWSE) 439 int NinjaMain::ToolBrowse(const Options* options, int argc, char* argv[]) { 440 RunBrowsePython(&state_, ninja_command_, options->input_file, argc, argv); 441 // If we get here, the browse failed. 442 return 1; 443 } 444 #else 445 int NinjaMain::ToolBrowse(const Options*, int, char**) { 446 Fatal("browse tool not supported on this platform"); 447 return 1; 448 } 449 #endif 450 451 #if defined(_MSC_VER) 452 int NinjaMain::ToolMSVC(const Options* options, int argc, char* argv[]) { 453 // Reset getopt: push one argument onto the front of argv, reset optind. 454 argc++; 455 argv--; 456 optind = 0; 457 return MSVCHelperMain(argc, argv); 458 } 459 #endif 460 461 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) { 462 for (vector<Node*>::const_iterator n = nodes.begin(); 463 n != nodes.end(); 464 ++n) { 465 for (int i = 0; i < indent; ++i) 466 printf(" "); 467 const char* target = (*n)->path().c_str(); 468 if ((*n)->in_edge()) { 469 printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str()); 470 if (depth > 1 || depth <= 0) 471 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1); 472 } else { 473 printf("%s\n", target); 474 } 475 } 476 return 0; 477 } 478 479 int ToolTargetsSourceList(State* state) { 480 for (vector<Edge*>::iterator e = state->edges_.begin(); 481 e != state->edges_.end(); ++e) { 482 for (vector<Node*>::iterator inps = (*e)->inputs_.begin(); 483 inps != (*e)->inputs_.end(); ++inps) { 484 if (!(*inps)->in_edge()) 485 printf("%s\n", (*inps)->path().c_str()); 486 } 487 } 488 return 0; 489 } 490 491 int ToolTargetsList(State* state, const string& rule_name) { 492 set<string> rules; 493 494 // Gather the outputs. 495 for (vector<Edge*>::iterator e = state->edges_.begin(); 496 e != state->edges_.end(); ++e) { 497 if ((*e)->rule_->name() == rule_name) { 498 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 499 out_node != (*e)->outputs_.end(); ++out_node) { 500 rules.insert((*out_node)->path()); 501 } 502 } 503 } 504 505 // Print them. 506 for (set<string>::const_iterator i = rules.begin(); 507 i != rules.end(); ++i) { 508 printf("%s\n", (*i).c_str()); 509 } 510 511 return 0; 512 } 513 514 int ToolTargetsList(State* state) { 515 for (vector<Edge*>::iterator e = state->edges_.begin(); 516 e != state->edges_.end(); ++e) { 517 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); 518 out_node != (*e)->outputs_.end(); ++out_node) { 519 printf("%s: %s\n", 520 (*out_node)->path().c_str(), 521 (*e)->rule_->name().c_str()); 522 } 523 } 524 return 0; 525 } 526 527 int NinjaMain::ToolDeps(const Options* options, int argc, char** argv) { 528 vector<Node*> nodes; 529 if (argc == 0) { 530 for (vector<Node*>::const_iterator ni = deps_log_.nodes().begin(); 531 ni != deps_log_.nodes().end(); ++ni) { 532 if (deps_log_.IsDepsEntryLiveFor(*ni)) 533 nodes.push_back(*ni); 534 } 535 } else { 536 string err; 537 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 538 Error("%s", err.c_str()); 539 return 1; 540 } 541 } 542 543 RealDiskInterface disk_interface; 544 for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end(); 545 it != end; ++it) { 546 DepsLog::Deps* deps = deps_log_.GetDeps(*it); 547 if (!deps) { 548 printf("%s: deps not found\n", (*it)->path().c_str()); 549 continue; 550 } 551 552 string err; 553 TimeStamp mtime = disk_interface.Stat((*it)->path(), &err); 554 if (mtime == -1) 555 Error("%s", err.c_str()); // Log and ignore Stat() errors; 556 printf("%s: #deps %d, deps mtime %" PRId64 " (%s)\n", 557 (*it)->path().c_str(), deps->node_count, deps->mtime, 558 (!mtime || mtime > deps->mtime ? "STALE":"VALID")); 559 for (int i = 0; i < deps->node_count; ++i) 560 printf(" %s\n", deps->nodes[i]->path().c_str()); 561 printf("\n"); 562 } 563 564 return 0; 565 } 566 567 int NinjaMain::ToolMissingDeps(const Options* options, int argc, char** argv) { 568 vector<Node*> nodes; 569 string err; 570 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 571 Error("%s", err.c_str()); 572 return 1; 573 } 574 RealDiskInterface disk_interface; 575 MissingDependencyPrinter printer; 576 MissingDependencyScanner scanner(&printer, &deps_log_, &state_, 577 &disk_interface); 578 for (vector<Node*>::iterator it = nodes.begin(); it != nodes.end(); ++it) { 579 scanner.ProcessNode(*it); 580 } 581 scanner.PrintStats(); 582 if (scanner.HadMissingDeps()) 583 return 3; 584 return 0; 585 } 586 587 int NinjaMain::ToolTargets(const Options* options, int argc, char* argv[]) { 588 int depth = 1; 589 if (argc >= 1) { 590 string mode = argv[0]; 591 if (mode == "rule") { 592 string rule; 593 if (argc > 1) 594 rule = argv[1]; 595 if (rule.empty()) 596 return ToolTargetsSourceList(&state_); 597 else 598 return ToolTargetsList(&state_, rule); 599 } else if (mode == "depth") { 600 if (argc > 1) 601 depth = atoi(argv[1]); 602 } else if (mode == "all") { 603 return ToolTargetsList(&state_); 604 } else { 605 const char* suggestion = 606 SpellcheckString(mode.c_str(), "rule", "depth", "all", NULL); 607 if (suggestion) { 608 Error("unknown target tool mode '%s', did you mean '%s'?", 609 mode.c_str(), suggestion); 610 } else { 611 Error("unknown target tool mode '%s'", mode.c_str()); 612 } 613 return 1; 614 } 615 } 616 617 string err; 618 vector<Node*> root_nodes = state_.RootNodes(&err); 619 if (err.empty()) { 620 return ToolTargetsList(root_nodes, depth, 0); 621 } else { 622 Error("%s", err.c_str()); 623 return 1; 624 } 625 } 626 627 int NinjaMain::ToolRules(const Options* options, int argc, char* argv[]) { 628 // Parse options. 629 630 // The rules tool uses getopt, and expects argv[0] to contain the name of 631 // the tool, i.e. "rules". 632 argc++; 633 argv--; 634 635 bool print_description = false; 636 637 optind = 1; 638 int opt; 639 while ((opt = getopt(argc, argv, const_cast<char*>("hd"))) != -1) { 640 switch (opt) { 641 case 'd': 642 print_description = true; 643 break; 644 case 'h': 645 default: 646 printf("usage: ninja -t rules [options]\n" 647 "\n" 648 "options:\n" 649 " -d also print the description of the rule\n" 650 " -h print this message\n" 651 ); 652 return 1; 653 } 654 } 655 argv += optind; 656 argc -= optind; 657 658 // Print rules 659 660 typedef map<string, const Rule*> Rules; 661 const Rules& rules = state_.bindings_.GetRules(); 662 for (Rules::const_iterator i = rules.begin(); i != rules.end(); ++i) { 663 printf("%s", i->first.c_str()); 664 if (print_description) { 665 const Rule* rule = i->second; 666 const EvalString* description = rule->GetBinding("description"); 667 if (description != NULL) { 668 printf(": %s", description->Unparse().c_str()); 669 } 670 } 671 printf("\n"); 672 } 673 return 0; 674 } 675 676 #ifdef _WIN32 677 int NinjaMain::ToolWinCodePage(const Options* options, int argc, char* argv[]) { 678 if (argc != 0) { 679 printf("usage: ninja -t wincodepage\n"); 680 return 1; 681 } 682 printf("Build file encoding: %s\n", GetACP() == CP_UTF8? "UTF-8" : "ANSI"); 683 return 0; 684 } 685 #endif 686 687 enum PrintCommandMode { PCM_Single, PCM_All }; 688 void PrintCommands(Edge* edge, EdgeSet* seen, PrintCommandMode mode) { 689 if (!edge) 690 return; 691 if (!seen->insert(edge).second) 692 return; 693 694 if (mode == PCM_All) { 695 for (vector<Node*>::iterator in = edge->inputs_.begin(); 696 in != edge->inputs_.end(); ++in) 697 PrintCommands((*in)->in_edge(), seen, mode); 698 } 699 700 if (!edge->is_phony()) 701 puts(edge->EvaluateCommand().c_str()); 702 } 703 704 int NinjaMain::ToolCommands(const Options* options, int argc, char* argv[]) { 705 // The clean tool uses getopt, and expects argv[0] to contain the name of 706 // the tool, i.e. "commands". 707 ++argc; 708 --argv; 709 710 PrintCommandMode mode = PCM_All; 711 712 optind = 1; 713 int opt; 714 while ((opt = getopt(argc, argv, const_cast<char*>("hs"))) != -1) { 715 switch (opt) { 716 case 's': 717 mode = PCM_Single; 718 break; 719 case 'h': 720 default: 721 printf("usage: ninja -t commands [options] [targets]\n" 722 "\n" 723 "options:\n" 724 " -s only print the final command to build [target], not the whole chain\n" 725 ); 726 return 1; 727 } 728 } 729 argv += optind; 730 argc -= optind; 731 732 vector<Node*> nodes; 733 string err; 734 if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) { 735 Error("%s", err.c_str()); 736 return 1; 737 } 738 739 EdgeSet seen; 740 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in) 741 PrintCommands((*in)->in_edge(), &seen, mode); 742 743 return 0; 744 } 745 746 int NinjaMain::ToolClean(const Options* options, int argc, char* argv[]) { 747 // The clean tool uses getopt, and expects argv[0] to contain the name of 748 // the tool, i.e. "clean". 749 argc++; 750 argv--; 751 752 bool generator = false; 753 bool clean_rules = false; 754 755 optind = 1; 756 int opt; 757 while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) { 758 switch (opt) { 759 case 'g': 760 generator = true; 761 break; 762 case 'r': 763 clean_rules = true; 764 break; 765 case 'h': 766 default: 767 printf("usage: ninja -t clean [options] [targets]\n" 768 "\n" 769 "options:\n" 770 " -g also clean files marked as ninja generator output\n" 771 " -r interpret targets as a list of rules to clean instead\n" 772 ); 773 return 1; 774 } 775 } 776 argv += optind; 777 argc -= optind; 778 779 if (clean_rules && argc == 0) { 780 Error("expected a rule to clean"); 781 return 1; 782 } 783 784 Cleaner cleaner(&state_, config_, &disk_interface_); 785 if (argc >= 1) { 786 if (clean_rules) 787 return cleaner.CleanRules(argc, argv); 788 else 789 return cleaner.CleanTargets(argc, argv); 790 } else { 791 return cleaner.CleanAll(generator); 792 } 793 } 794 795 int NinjaMain::ToolCleanDead(const Options* options, int argc, char* argv[]) { 796 Cleaner cleaner(&state_, config_, &disk_interface_); 797 return cleaner.CleanDead(build_log_.entries()); 798 } 799 800 enum EvaluateCommandMode { 801 ECM_NORMAL, 802 ECM_EXPAND_RSPFILE 803 }; 804 std::string EvaluateCommandWithRspfile(const Edge* edge, 805 const EvaluateCommandMode mode) { 806 string command = edge->EvaluateCommand(); 807 if (mode == ECM_NORMAL) 808 return command; 809 810 string rspfile = edge->GetUnescapedRspfile(); 811 if (rspfile.empty()) 812 return command; 813 814 size_t index = command.find(rspfile); 815 if (index == 0 || index == string::npos || command[index - 1] != '@') 816 return command; 817 818 string rspfile_content = edge->GetBinding("rspfile_content"); 819 size_t newline_index = 0; 820 while ((newline_index = rspfile_content.find('\n', newline_index)) != 821 string::npos) { 822 rspfile_content.replace(newline_index, 1, 1, ' '); 823 ++newline_index; 824 } 825 command.replace(index - 1, rspfile.length() + 1, rspfile_content); 826 return command; 827 } 828 829 void printCompdb(const char* const directory, const Edge* const edge, 830 const EvaluateCommandMode eval_mode) { 831 printf("\n {\n \"directory\": \""); 832 PrintJSONString(directory); 833 printf("\",\n \"command\": \""); 834 PrintJSONString(EvaluateCommandWithRspfile(edge, eval_mode)); 835 printf("\",\n \"file\": \""); 836 PrintJSONString(edge->inputs_[0]->path()); 837 printf("\",\n \"output\": \""); 838 PrintJSONString(edge->outputs_[0]->path()); 839 printf("\"\n }"); 840 } 841 842 int NinjaMain::ToolCompilationDatabase(const Options* options, int argc, 843 char* argv[]) { 844 // The compdb tool uses getopt, and expects argv[0] to contain the name of 845 // the tool, i.e. "compdb". 846 argc++; 847 argv--; 848 849 EvaluateCommandMode eval_mode = ECM_NORMAL; 850 851 optind = 1; 852 int opt; 853 while ((opt = getopt(argc, argv, const_cast<char*>("hx"))) != -1) { 854 switch(opt) { 855 case 'x': 856 eval_mode = ECM_EXPAND_RSPFILE; 857 break; 858 859 case 'h': 860 default: 861 printf( 862 "usage: ninja -t compdb [options] [rules]\n" 863 "\n" 864 "options:\n" 865 " -x expand @rspfile style response file invocations\n" 866 ); 867 return 1; 868 } 869 } 870 argv += optind; 871 argc -= optind; 872 873 bool first = true; 874 vector<char> cwd; 875 char* success = NULL; 876 877 do { 878 cwd.resize(cwd.size() + 1024); 879 errno = 0; 880 success = getcwd(&cwd[0], cwd.size()); 881 } while (!success && errno == ERANGE); 882 if (!success) { 883 Error("cannot determine working directory: %s", strerror(errno)); 884 return 1; 885 } 886 887 putchar('['); 888 for (vector<Edge*>::iterator e = state_.edges_.begin(); 889 e != state_.edges_.end(); ++e) { 890 if ((*e)->inputs_.empty()) 891 continue; 892 if (argc == 0) { 893 if (!first) { 894 putchar(','); 895 } 896 printCompdb(&cwd[0], *e, eval_mode); 897 first = false; 898 } else { 899 for (int i = 0; i != argc; ++i) { 900 if ((*e)->rule_->name() == argv[i]) { 901 if (!first) { 902 putchar(','); 903 } 904 printCompdb(&cwd[0], *e, eval_mode); 905 first = false; 906 } 907 } 908 } 909 } 910 911 puts("\n]"); 912 return 0; 913 } 914 915 int NinjaMain::ToolRecompact(const Options* options, int argc, char* argv[]) { 916 if (!EnsureBuildDirExists()) 917 return 1; 918 919 if (!OpenBuildLog(/*recompact_only=*/true) || 920 !OpenDepsLog(/*recompact_only=*/true)) 921 return 1; 922 923 return 0; 924 } 925 926 int NinjaMain::ToolRestat(const Options* options, int argc, char* argv[]) { 927 // The restat tool uses getopt, and expects argv[0] to contain the name of the 928 // tool, i.e. "restat" 929 argc++; 930 argv--; 931 932 optind = 1; 933 int opt; 934 while ((opt = getopt(argc, argv, const_cast<char*>("h"))) != -1) { 935 switch (opt) { 936 case 'h': 937 default: 938 printf("usage: ninja -t restat [outputs]\n"); 939 return 1; 940 } 941 } 942 argv += optind; 943 argc -= optind; 944 945 if (!EnsureBuildDirExists()) 946 return 1; 947 948 string log_path = ".ninja_log"; 949 if (!build_dir_.empty()) 950 log_path = build_dir_ + "/" + log_path; 951 952 string err; 953 const LoadStatus status = build_log_.Load(log_path, &err); 954 if (status == LOAD_ERROR) { 955 Error("loading build log %s: %s", log_path.c_str(), err.c_str()); 956 return EXIT_FAILURE; 957 } 958 if (status == LOAD_NOT_FOUND) { 959 // Nothing to restat, ignore this 960 return EXIT_SUCCESS; 961 } 962 if (!err.empty()) { 963 // Hack: Load() can return a warning via err by returning LOAD_SUCCESS. 964 Warning("%s", err.c_str()); 965 err.clear(); 966 } 967 968 bool success = build_log_.Restat(log_path, disk_interface_, argc, argv, &err); 969 if (!success) { 970 Error("failed recompaction: %s", err.c_str()); 971 return EXIT_FAILURE; 972 } 973 974 if (!config_.dry_run) { 975 if (!build_log_.OpenForWrite(log_path, *this, &err)) { 976 Error("opening build log: %s", err.c_str()); 977 return EXIT_FAILURE; 978 } 979 } 980 981 return EXIT_SUCCESS; 982 } 983 984 int NinjaMain::ToolUrtle(const Options* options, int argc, char** argv) { 985 // RLE encoded. 986 const char* urtle = 987 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 " 988 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<" 989 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5" 990 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\"" 991 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e" 992 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c" 993 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?" 994 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2" 995 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P" 996 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n"; 997 int count = 0; 998 for (const char* p = urtle; *p; p++) { 999 if ('0' <= *p && *p <= '9') { 1000 count = count*10 + *p - '0'; 1001 } else { 1002 for (int i = 0; i < max(count, 1); ++i) 1003 printf("%c", *p); 1004 count = 0; 1005 } 1006 } 1007 return 0; 1008 } 1009 1010 /// Find the function to execute for \a tool_name and return it via \a func. 1011 /// Returns a Tool, or NULL if Ninja should exit. 1012 const Tool* ChooseTool(const string& tool_name) { 1013 static const Tool kTools[] = { 1014 { "browse", "browse dependency graph in a web browser", 1015 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse }, 1016 #if defined(_MSC_VER) 1017 { "msvc", "build helper for MSVC cl.exe (EXPERIMENTAL)", 1018 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC }, 1019 #endif 1020 { "clean", "clean built files", 1021 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean }, 1022 { "commands", "list all commands required to rebuild given targets", 1023 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands }, 1024 { "deps", "show dependencies stored in the deps log", 1025 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps }, 1026 { "missingdeps", "check deps log dependencies on generated files", 1027 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolMissingDeps }, 1028 { "graph", "output graphviz dot file for targets", 1029 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph }, 1030 { "query", "show inputs/outputs for a path", 1031 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery }, 1032 { "targets", "list targets by their rule or depth in the DAG", 1033 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets }, 1034 { "compdb", "dump JSON compilation database to stdout", 1035 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase }, 1036 { "recompact", "recompacts ninja-internal data structures", 1037 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact }, 1038 { "restat", "restats all outputs in the build log", 1039 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolRestat }, 1040 { "rules", "list all rules", 1041 Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRules }, 1042 { "cleandead", "clean built files that are no longer produced by the manifest", 1043 Tool::RUN_AFTER_LOGS, &NinjaMain::ToolCleanDead }, 1044 { "urtle", NULL, 1045 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle }, 1046 #ifdef _WIN32 1047 { "wincodepage", "print the Windows code page used by ninja", 1048 Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolWinCodePage }, 1049 #endif 1050 { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL } 1051 }; 1052 1053 if (tool_name == "list") { 1054 printf("ninja subtools:\n"); 1055 for (const Tool* tool = &kTools[0]; tool->name; ++tool) { 1056 if (tool->desc) 1057 printf("%11s %s\n", tool->name, tool->desc); 1058 } 1059 return NULL; 1060 } 1061 1062 for (const Tool* tool = &kTools[0]; tool->name; ++tool) { 1063 if (tool->name == tool_name) 1064 return tool; 1065 } 1066 1067 vector<const char*> words; 1068 for (const Tool* tool = &kTools[0]; tool->name; ++tool) 1069 words.push_back(tool->name); 1070 const char* suggestion = SpellcheckStringV(tool_name, words); 1071 if (suggestion) { 1072 Fatal("unknown tool '%s', did you mean '%s'?", 1073 tool_name.c_str(), suggestion); 1074 } else { 1075 Fatal("unknown tool '%s'", tool_name.c_str()); 1076 } 1077 return NULL; // Not reached. 1078 } 1079 1080 /// Enable a debugging mode. Returns false if Ninja should exit instead 1081 /// of continuing. 1082 bool DebugEnable(const string& name) { 1083 if (name == "list") { 1084 printf("debugging modes:\n" 1085 " stats print operation counts/timing info\n" 1086 " explain explain what caused a command to execute\n" 1087 " keepdepfile don't delete depfiles after they're read by ninja\n" 1088 " keeprsp don't delete @response files on success\n" 1089 #ifdef _WIN32 1090 " nostatcache don't batch stat() calls per directory and cache them\n" 1091 #endif 1092 "multiple modes can be enabled via -d FOO -d BAR\n"); 1093 return false; 1094 } else if (name == "stats") { 1095 g_metrics = new Metrics; 1096 return true; 1097 } else if (name == "explain") { 1098 g_explaining = true; 1099 return true; 1100 } else if (name == "keepdepfile") { 1101 g_keep_depfile = true; 1102 return true; 1103 } else if (name == "keeprsp") { 1104 g_keep_rsp = true; 1105 return true; 1106 } else if (name == "nostatcache") { 1107 g_experimental_statcache = false; 1108 return true; 1109 } else { 1110 const char* suggestion = 1111 SpellcheckString(name.c_str(), 1112 "stats", "explain", "keepdepfile", "keeprsp", 1113 "nostatcache", NULL); 1114 if (suggestion) { 1115 Error("unknown debug setting '%s', did you mean '%s'?", 1116 name.c_str(), suggestion); 1117 } else { 1118 Error("unknown debug setting '%s'", name.c_str()); 1119 } 1120 return false; 1121 } 1122 } 1123 1124 /// Set a warning flag. Returns false if Ninja should exit instead of 1125 /// continuing. 1126 bool WarningEnable(const string& name, Options* options) { 1127 if (name == "list") { 1128 printf("warning flags:\n" 1129 " phonycycle={err,warn} phony build statement references itself\n" 1130 ); 1131 return false; 1132 } else if (name == "dupbuild=err") { 1133 options->dupe_edges_should_err = true; 1134 return true; 1135 } else if (name == "dupbuild=warn") { 1136 options->dupe_edges_should_err = false; 1137 return true; 1138 } else if (name == "phonycycle=err") { 1139 options->phony_cycle_should_err = true; 1140 return true; 1141 } else if (name == "phonycycle=warn") { 1142 options->phony_cycle_should_err = false; 1143 return true; 1144 } else if (name == "depfilemulti=err" || 1145 name == "depfilemulti=warn") { 1146 Warning("deprecated warning 'depfilemulti'"); 1147 return true; 1148 } else { 1149 const char* suggestion = 1150 SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn", 1151 "phonycycle=err", "phonycycle=warn", NULL); 1152 if (suggestion) { 1153 Error("unknown warning flag '%s', did you mean '%s'?", 1154 name.c_str(), suggestion); 1155 } else { 1156 Error("unknown warning flag '%s'", name.c_str()); 1157 } 1158 return false; 1159 } 1160 } 1161 1162 bool NinjaMain::OpenBuildLog(bool recompact_only) { 1163 string log_path = ".ninja_log"; 1164 if (!build_dir_.empty()) 1165 log_path = build_dir_ + "/" + log_path; 1166 1167 string err; 1168 const LoadStatus status = build_log_.Load(log_path, &err); 1169 if (status == LOAD_ERROR) { 1170 Error("loading build log %s: %s", log_path.c_str(), err.c_str()); 1171 return false; 1172 } 1173 if (!err.empty()) { 1174 // Hack: Load() can return a warning via err by returning LOAD_SUCCESS. 1175 Warning("%s", err.c_str()); 1176 err.clear(); 1177 } 1178 1179 if (recompact_only) { 1180 if (status == LOAD_NOT_FOUND) { 1181 return true; 1182 } 1183 bool success = build_log_.Recompact(log_path, *this, &err); 1184 if (!success) 1185 Error("failed recompaction: %s", err.c_str()); 1186 return success; 1187 } 1188 1189 if (!config_.dry_run) { 1190 if (!build_log_.OpenForWrite(log_path, *this, &err)) { 1191 Error("opening build log: %s", err.c_str()); 1192 return false; 1193 } 1194 } 1195 1196 return true; 1197 } 1198 1199 /// Open the deps log: load it, then open for writing. 1200 /// @return false on error. 1201 bool NinjaMain::OpenDepsLog(bool recompact_only) { 1202 string path = ".ninja_deps"; 1203 if (!build_dir_.empty()) 1204 path = build_dir_ + "/" + path; 1205 1206 string err; 1207 const LoadStatus status = deps_log_.Load(path, &state_, &err); 1208 if (status == LOAD_ERROR) { 1209 Error("loading deps log %s: %s", path.c_str(), err.c_str()); 1210 return false; 1211 } 1212 if (!err.empty()) { 1213 // Hack: Load() can return a warning via err by returning LOAD_SUCCESS. 1214 Warning("%s", err.c_str()); 1215 err.clear(); 1216 } 1217 1218 if (recompact_only) { 1219 if (status == LOAD_NOT_FOUND) { 1220 return true; 1221 } 1222 bool success = deps_log_.Recompact(path, &err); 1223 if (!success) 1224 Error("failed recompaction: %s", err.c_str()); 1225 return success; 1226 } 1227 1228 if (!config_.dry_run) { 1229 if (!deps_log_.OpenForWrite(path, &err)) { 1230 Error("opening deps log: %s", err.c_str()); 1231 return false; 1232 } 1233 } 1234 1235 return true; 1236 } 1237 1238 void NinjaMain::DumpMetrics() { 1239 g_metrics->Report(); 1240 1241 printf("\n"); 1242 int count = (int)state_.paths_.size(); 1243 int buckets = (int)state_.paths_.bucket_count(); 1244 printf("path->node hash load %.2f (%d entries / %d buckets)\n", 1245 count / (double) buckets, count, buckets); 1246 } 1247 1248 bool NinjaMain::EnsureBuildDirExists() { 1249 build_dir_ = state_.bindings_.LookupVariable("builddir"); 1250 if (!build_dir_.empty() && !config_.dry_run) { 1251 if (!disk_interface_.MakeDirs(build_dir_ + "/.") && errno != EEXIST) { 1252 Error("creating build directory %s: %s", 1253 build_dir_.c_str(), strerror(errno)); 1254 return false; 1255 } 1256 } 1257 return true; 1258 } 1259 1260 int NinjaMain::RunBuild(int argc, char** argv, Status* status) { 1261 string err; 1262 vector<Node*> targets; 1263 if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) { 1264 status->Error("%s", err.c_str()); 1265 return 1; 1266 } 1267 1268 disk_interface_.AllowStatCache(g_experimental_statcache); 1269 1270 Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_, 1271 status, start_time_millis_); 1272 for (size_t i = 0; i < targets.size(); ++i) { 1273 if (!builder.AddTarget(targets[i], &err)) { 1274 if (!err.empty()) { 1275 status->Error("%s", err.c_str()); 1276 return 1; 1277 } else { 1278 // Added a target that is already up-to-date; not really 1279 // an error. 1280 } 1281 } 1282 } 1283 1284 // Make sure restat rules do not see stale timestamps. 1285 disk_interface_.AllowStatCache(false); 1286 1287 if (builder.AlreadyUpToDate()) { 1288 status->Info("no work to do."); 1289 return 0; 1290 } 1291 1292 if (!builder.Build(&err)) { 1293 status->Info("build stopped: %s.", err.c_str()); 1294 if (err.find("interrupted by user") != string::npos) { 1295 return 2; 1296 } 1297 return 1; 1298 } 1299 1300 return 0; 1301 } 1302 1303 #ifdef _MSC_VER 1304 1305 /// This handler processes fatal crashes that you can't catch 1306 /// Test example: C++ exception in a stack-unwind-block 1307 /// Real-world example: ninja launched a compiler to process a tricky 1308 /// C++ input file. The compiler got itself into a state where it 1309 /// generated 3 GB of output and caused ninja to crash. 1310 void TerminateHandler() { 1311 CreateWin32MiniDump(NULL); 1312 Fatal("terminate handler called"); 1313 } 1314 1315 /// On Windows, we want to prevent error dialogs in case of exceptions. 1316 /// This function handles the exception, and writes a minidump. 1317 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { 1318 Error("exception: 0x%X", code); // e.g. EXCEPTION_ACCESS_VIOLATION 1319 fflush(stderr); 1320 CreateWin32MiniDump(ep); 1321 return EXCEPTION_EXECUTE_HANDLER; 1322 } 1323 1324 #endif // _MSC_VER 1325 1326 /// Parse argv for command-line options. 1327 /// Returns an exit code, or -1 if Ninja should continue. 1328 int ReadFlags(int* argc, char*** argv, 1329 Options* options, BuildConfig* config) { 1330 config->parallelism = GuessParallelism(); 1331 1332 enum { OPT_VERSION = 1, OPT_QUIET = 2 }; 1333 const option kLongOptions[] = { 1334 { "help", no_argument, NULL, 'h' }, 1335 { "version", no_argument, NULL, OPT_VERSION }, 1336 { "verbose", no_argument, NULL, 'v' }, 1337 { "quiet", no_argument, NULL, OPT_QUIET }, 1338 { NULL, 0, NULL, 0 } 1339 }; 1340 1341 int opt; 1342 while (!options->tool && 1343 (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:h", kLongOptions, 1344 NULL)) != -1) { 1345 switch (opt) { 1346 case 'd': 1347 if (!DebugEnable(optarg)) 1348 return 1; 1349 break; 1350 case 'f': 1351 options->input_file = optarg; 1352 break; 1353 case 'j': { 1354 char* end; 1355 int value = strtol(optarg, &end, 10); 1356 if (*end != 0 || value < 0) 1357 Fatal("invalid -j parameter"); 1358 1359 // We want to run N jobs in parallel. For N = 0, INT_MAX 1360 // is close enough to infinite for most sane builds. 1361 config->parallelism = value > 0 ? value : INT_MAX; 1362 break; 1363 } 1364 case 'k': { 1365 char* end; 1366 int value = strtol(optarg, &end, 10); 1367 if (*end != 0) 1368 Fatal("-k parameter not numeric; did you mean -k 0?"); 1369 1370 // We want to go until N jobs fail, which means we should allow 1371 // N failures and then stop. For N <= 0, INT_MAX is close enough 1372 // to infinite for most sane builds. 1373 config->failures_allowed = value > 0 ? value : INT_MAX; 1374 break; 1375 } 1376 case 'l': { 1377 char* end; 1378 double value = strtod(optarg, &end); 1379 if (end == optarg) 1380 Fatal("-l parameter not numeric: did you mean -l 0.0?"); 1381 config->max_load_average = value; 1382 break; 1383 } 1384 case 'n': 1385 config->dry_run = true; 1386 break; 1387 case 't': 1388 options->tool = ChooseTool(optarg); 1389 if (!options->tool) 1390 return 0; 1391 break; 1392 case 'v': 1393 config->verbosity = BuildConfig::VERBOSE; 1394 break; 1395 case OPT_QUIET: 1396 config->verbosity = BuildConfig::NO_STATUS_UPDATE; 1397 break; 1398 case 'w': 1399 if (!WarningEnable(optarg, options)) 1400 return 1; 1401 break; 1402 case 'C': 1403 options->working_dir = optarg; 1404 break; 1405 case OPT_VERSION: 1406 printf("%s\n", kNinjaVersion); 1407 return 0; 1408 case 'h': 1409 default: 1410 Usage(*config); 1411 return 1; 1412 } 1413 } 1414 *argv += optind; 1415 *argc -= optind; 1416 1417 return -1; 1418 } 1419 1420 NORETURN void real_main(int argc, char** argv) { 1421 // Use exit() instead of return in this function to avoid potentially 1422 // expensive cleanup when destructing NinjaMain. 1423 BuildConfig config; 1424 Options options = {}; 1425 options.input_file = "build.ninja"; 1426 options.dupe_edges_should_err = true; 1427 1428 setvbuf(stdout, NULL, _IOLBF, BUFSIZ); 1429 const char* ninja_command = argv[0]; 1430 1431 int exit_code = ReadFlags(&argc, &argv, &options, &config); 1432 if (exit_code >= 0) 1433 exit(exit_code); 1434 1435 Status* status = new StatusPrinter(config); 1436 1437 if (options.working_dir) { 1438 // The formatting of this string, complete with funny quotes, is 1439 // so Emacs can properly identify that the cwd has changed for 1440 // subsequent commands. 1441 // Don't print this if a tool is being used, so that tool output 1442 // can be piped into a file without this string showing up. 1443 if (!options.tool && config.verbosity != BuildConfig::NO_STATUS_UPDATE) 1444 status->Info("Entering directory `%s'", options.working_dir); 1445 if (chdir(options.working_dir) < 0) { 1446 Fatal("chdir to '%s' - %s", options.working_dir, strerror(errno)); 1447 } 1448 } 1449 1450 if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) { 1451 // None of the RUN_AFTER_FLAGS actually use a NinjaMain, but it's needed 1452 // by other tools. 1453 NinjaMain ninja(ninja_command, config); 1454 exit((ninja.*options.tool->func)(&options, argc, argv)); 1455 } 1456 1457 #ifdef WIN32 1458 // It'd be nice to use line buffering but MSDN says: "For some systems, 1459 // [_IOLBF] provides line buffering. However, for Win32, the behavior is the 1460 // same as _IOFBF - Full Buffering." 1461 // Buffering used to be disabled in the LinePrinter constructor but that 1462 // now disables it too early and breaks -t deps performance (see issue #2018) 1463 // so we disable it here instead, but only when not running a tool. 1464 if (!options.tool) 1465 setvbuf(stdout, NULL, _IONBF, 0); 1466 #endif 1467 1468 // Limit number of rebuilds, to prevent infinite loops. 1469 const int kCycleLimit = 100; 1470 for (int cycle = 1; cycle <= kCycleLimit; ++cycle) { 1471 NinjaMain ninja(ninja_command, config); 1472 1473 ManifestParserOptions parser_opts; 1474 if (options.dupe_edges_should_err) { 1475 parser_opts.dupe_edge_action_ = kDupeEdgeActionError; 1476 } 1477 if (options.phony_cycle_should_err) { 1478 parser_opts.phony_cycle_action_ = kPhonyCycleActionError; 1479 } 1480 ManifestParser parser(&ninja.state_, &ninja.disk_interface_, parser_opts); 1481 string err; 1482 if (!parser.Load(options.input_file, &err)) { 1483 status->Error("%s", err.c_str()); 1484 exit(1); 1485 } 1486 1487 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD) 1488 exit((ninja.*options.tool->func)(&options, argc, argv)); 1489 1490 if (!ninja.EnsureBuildDirExists()) 1491 exit(1); 1492 1493 if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog()) 1494 exit(1); 1495 1496 if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS) 1497 exit((ninja.*options.tool->func)(&options, argc, argv)); 1498 1499 // Attempt to rebuild the manifest before building anything else 1500 if (ninja.RebuildManifest(options.input_file, &err, status)) { 1501 // In dry_run mode the regeneration will succeed without changing the 1502 // manifest forever. Better to return immediately. 1503 if (config.dry_run) 1504 exit(0); 1505 // Start the build over with the new manifest. 1506 continue; 1507 } else if (!err.empty()) { 1508 status->Error("rebuilding '%s': %s", options.input_file, err.c_str()); 1509 exit(1); 1510 } 1511 1512 int result = ninja.RunBuild(argc, argv, status); 1513 if (g_metrics) 1514 ninja.DumpMetrics(); 1515 exit(result); 1516 } 1517 1518 status->Error("manifest '%s' still dirty after %d tries", 1519 options.input_file, kCycleLimit); 1520 exit(1); 1521 } 1522 1523 } // anonymous namespace 1524 1525 int main(int argc, char** argv) { 1526 #if defined(_MSC_VER) 1527 // Set a handler to catch crashes not caught by the __try..__except 1528 // block (e.g. an exception in a stack-unwind-block). 1529 std::set_terminate(TerminateHandler); 1530 __try { 1531 // Running inside __try ... __except suppresses any Windows error 1532 // dialogs for errors such as bad_alloc. 1533 real_main(argc, argv); 1534 } 1535 __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) { 1536 // Common error situations return exitCode=1. 2 was chosen to 1537 // indicate a more serious problem. 1538 return 2; 1539 } 1540 #else 1541 real_main(argc, argv); 1542 #endif 1543 }