Ninja
ninja.cc
Go to the documentation of this file.
00001 // Copyright 2011 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include <errno.h>
00016 #include <limits.h>
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 
00021 #ifdef _WIN32
00022 #include "getopt.h"
00023 #include <direct.h>
00024 #include <windows.h>
00025 #else
00026 #include <getopt.h>
00027 #include <unistd.h>
00028 #endif
00029 
00030 #include "browse.h"
00031 #include "build.h"
00032 #include "build_log.h"
00033 #include "deps_log.h"
00034 #include "clean.h"
00035 #include "disk_interface.h"
00036 #include "explain.h"
00037 #include "graph.h"
00038 #include "graphviz.h"
00039 #include "manifest_parser.h"
00040 #include "metrics.h"
00041 #include "state.h"
00042 #include "util.h"
00043 #include "version.h"
00044 
00045 #ifdef _MSC_VER
00046 // Defined in msvc_helper_main-win32.cc.
00047 int MSVCHelperMain(int argc, char** argv);
00048 
00049 // Defined in minidump-win32.cc.
00050 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
00051 #endif
00052 
00053 namespace {
00054 
00055 struct Tool;
00056 
00057 /// Command-line options.
00058 struct Options {
00059   /// Build file to load.
00060   const char* input_file;
00061 
00062   /// Directory to change into before running.
00063   const char* working_dir;
00064 
00065   /// Tool to run rather than building.
00066   const Tool* tool;
00067 };
00068 
00069 /// The Ninja main() loads up a series of data structures; various tools need
00070 /// to poke into these, so store them as fields on an object.
00071 struct NinjaMain {
00072   NinjaMain(const char* ninja_command, const BuildConfig& config) :
00073       ninja_command_(ninja_command), config_(config) {}
00074 
00075   /// Command line used to run Ninja.
00076   const char* ninja_command_;
00077 
00078   /// Build configuration set from flags (e.g. parallelism).
00079   const BuildConfig& config_;
00080 
00081   /// Loaded state (rules, nodes).
00082   State state_;
00083 
00084   /// Functions for accesssing the disk.
00085   RealDiskInterface disk_interface_;
00086 
00087   /// The build directory, used for storing the build log etc.
00088   string build_dir_;
00089 
00090   BuildLog build_log_;
00091   DepsLog deps_log_;
00092 
00093   /// The type of functions that are the entry points to tools (subcommands).
00094   typedef int (NinjaMain::*ToolFunc)(int, char**);
00095 
00096   /// Get the Node for a given command-line path, handling features like
00097   /// spell correction.
00098   Node* CollectTarget(const char* cpath, string* err);
00099 
00100   /// CollectTarget for all command-line arguments, filling in \a targets.
00101   bool CollectTargetsFromArgs(int argc, char* argv[],
00102                               vector<Node*>* targets, string* err);
00103 
00104   // The various subcommands, run via "-t XXX".
00105   int ToolGraph(int argc, char* argv[]);
00106   int ToolQuery(int argc, char* argv[]);
00107   int ToolBrowse(int argc, char* argv[]);
00108   int ToolMSVC(int argc, char* argv[]);
00109   int ToolTargets(int argc, char* argv[]);
00110   int ToolCommands(int argc, char* argv[]);
00111   int ToolClean(int argc, char* argv[]);
00112   int ToolCompilationDatabase(int argc, char* argv[]);
00113   int ToolUrtle(int argc, char** argv);
00114 
00115   /// Open the build log.
00116   /// @return false on error.
00117   bool OpenBuildLog();
00118 
00119   /// Open the deps log: load it, then open for writing.
00120   /// @return false on error.
00121   bool OpenDepsLog();
00122 
00123   /// Ensure the build directory exists, creating it if necessary.
00124   /// @return false on error.
00125   bool EnsureBuildDirExists();
00126 
00127   /// Rebuild the manifest, if necessary.
00128   /// Fills in \a err on error.
00129   /// @return true if the manifest was rebuilt.
00130   bool RebuildManifest(const char* input_file, string* err);
00131 
00132   /// Build the targets listed on the command line.
00133   /// @return an exit code.
00134   int RunBuild(int argc, char** argv);
00135 
00136   /// Dump the output requested by '-d stats'.
00137   void DumpMetrics();
00138 };
00139 
00140 /// Subtools, accessible via "-t foo".
00141 struct Tool {
00142   /// Short name of the tool.
00143   const char* name;
00144 
00145   /// Description (shown in "-t list").
00146   const char* desc;
00147 
00148   /// When to run the tool.
00149   enum {
00150     /// Run after parsing the command-line flags (as early as possible).
00151     RUN_AFTER_FLAGS,
00152 
00153     /// Run after loading build.ninja.
00154     RUN_AFTER_LOAD,
00155 
00156     /// Run after loading the build/deps logs.
00157     RUN_AFTER_LOGS,
00158   } when;
00159 
00160   /// Implementation of the tool.
00161   NinjaMain::ToolFunc func;
00162 };
00163 
00164 /// Print usage information.
00165 void Usage(const BuildConfig& config) {
00166   fprintf(stderr,
00167 "usage: ninja [options] [targets...]\n"
00168 "\n"
00169 "if targets are unspecified, builds the 'default' target (see manual).\n"
00170 "\n"
00171 "options:\n"
00172 "  --version  print ninja version (\"%s\")\n"
00173 "\n"
00174 "  -C DIR   change to DIR before doing anything else\n"
00175 "  -f FILE  specify input build file [default=build.ninja]\n"
00176 "\n"
00177 "  -j N     run N jobs in parallel [default=%d, derived from CPUs available]\n"
00178 "  -l N     do not start new jobs if the load average is greater than N\n"
00179 #ifdef _WIN32
00180 "           (not yet implemented on Windows)\n"
00181 #endif
00182 "  -k N     keep going until N jobs fail [default=1]\n"
00183 "  -n       dry run (don't run commands but act like they succeeded)\n"
00184 "  -v       show all command lines while building\n"
00185 "\n"
00186 "  -d MODE  enable debugging (use -d list to list modes)\n"
00187 "  -t TOOL  run a subtool (use -t list to list subtools)\n"
00188 "    terminates toplevel options; further flags are passed to the tool\n",
00189           kNinjaVersion, config.parallelism);
00190 }
00191 
00192 /// Choose a default value for the -j (parallelism) flag.
00193 int GuessParallelism() {
00194   switch (int processors = GetProcessorCount()) {
00195   case 0:
00196   case 1:
00197     return 2;
00198   case 2:
00199     return 3;
00200   default:
00201     return processors + 2;
00202   }
00203 }
00204 
00205 /// An implementation of ManifestParser::FileReader that actually reads
00206 /// the file.
00207 struct RealFileReader : public ManifestParser::FileReader {
00208   virtual bool ReadFile(const string& path, string* content, string* err) {
00209     return ::ReadFile(path, content, err) == 0;
00210   }
00211 };
00212 
00213 /// Rebuild the build manifest, if necessary.
00214 /// Returns true if the manifest was rebuilt.
00215 bool NinjaMain::RebuildManifest(const char* input_file, string* err) {
00216   string path = input_file;
00217   if (!CanonicalizePath(&path, err))
00218     return false;
00219   Node* node = state_.LookupNode(path);
00220   if (!node)
00221     return false;
00222 
00223   Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
00224   if (!builder.AddTarget(node, err))
00225     return false;
00226 
00227   if (builder.AlreadyUpToDate())
00228     return false;  // Not an error, but we didn't rebuild.
00229   if (!builder.Build(err))
00230     return false;
00231 
00232   // The manifest was only rebuilt if it is now dirty (it may have been cleaned
00233   // by a restat).
00234   return node->dirty();
00235 }
00236 
00237 Node* NinjaMain::CollectTarget(const char* cpath, string* err) {
00238   string path = cpath;
00239   if (!CanonicalizePath(&path, err))
00240     return NULL;
00241 
00242   // Special syntax: "foo.cc^" means "the first output of foo.cc".
00243   bool first_dependent = false;
00244   if (!path.empty() && path[path.size() - 1] == '^') {
00245     path.resize(path.size() - 1);
00246     first_dependent = true;
00247   }
00248 
00249   Node* node = state_.LookupNode(path);
00250   if (node) {
00251     if (first_dependent) {
00252       if (node->out_edges().empty()) {
00253         *err = "'" + path + "' has no out edge";
00254         return NULL;
00255       }
00256       Edge* edge = node->out_edges()[0];
00257       if (edge->outputs_.empty()) {
00258         edge->Dump();
00259         Fatal("edge has no outputs");
00260       }
00261       node = edge->outputs_[0];
00262     }
00263     return node;
00264   } else {
00265     *err = "unknown target '" + path + "'";
00266 
00267     if (path == "clean") {
00268       *err += ", did you mean 'ninja -t clean'?";
00269     } else if (path == "help") {
00270       *err += ", did you mean 'ninja -h'?";
00271     } else {
00272       Node* suggestion = state_.SpellcheckNode(path);
00273       if (suggestion) {
00274         *err += ", did you mean '" + suggestion->path() + "'?";
00275       }
00276     }
00277     return NULL;
00278   }
00279 }
00280 
00281 bool NinjaMain::CollectTargetsFromArgs(int argc, char* argv[],
00282                                        vector<Node*>* targets, string* err) {
00283   if (argc == 0) {
00284     *targets = state_.DefaultNodes(err);
00285     return err->empty();
00286   }
00287 
00288   for (int i = 0; i < argc; ++i) {
00289     Node* node = CollectTarget(argv[i], err);
00290     if (node == NULL)
00291       return false;
00292     targets->push_back(node);
00293   }
00294   return true;
00295 }
00296 
00297 int NinjaMain::ToolGraph(int argc, char* argv[]) {
00298   vector<Node*> nodes;
00299   string err;
00300   if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
00301     Error("%s", err.c_str());
00302     return 1;
00303   }
00304 
00305   GraphViz graph;
00306   graph.Start();
00307   for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
00308     graph.AddTarget(*n);
00309   graph.Finish();
00310 
00311   return 0;
00312 }
00313 
00314 int NinjaMain::ToolQuery(int argc, char* argv[]) {
00315   if (argc == 0) {
00316     Error("expected a target to query");
00317     return 1;
00318   }
00319 
00320   for (int i = 0; i < argc; ++i) {
00321     string err;
00322     Node* node = CollectTarget(argv[i], &err);
00323     if (!node) {
00324       Error("%s", err.c_str());
00325       return 1;
00326     }
00327 
00328     printf("%s:\n", node->path().c_str());
00329     if (Edge* edge = node->in_edge()) {
00330       printf("  input: %s\n", edge->rule_->name().c_str());
00331       for (int in = 0; in < (int)edge->inputs_.size(); in++) {
00332         const char* label = "";
00333         if (edge->is_implicit(in))
00334           label = "| ";
00335         else if (edge->is_order_only(in))
00336           label = "|| ";
00337         printf("    %s%s\n", label, edge->inputs_[in]->path().c_str());
00338       }
00339     }
00340     printf("  outputs:\n");
00341     for (vector<Edge*>::const_iterator edge = node->out_edges().begin();
00342          edge != node->out_edges().end(); ++edge) {
00343       for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
00344            out != (*edge)->outputs_.end(); ++out) {
00345         printf("    %s\n", (*out)->path().c_str());
00346       }
00347     }
00348   }
00349   return 0;
00350 }
00351 
00352 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
00353 int NinjaMain::ToolBrowse(int argc, char* argv[]) {
00354   if (argc < 1) {
00355     Error("expected a target to browse");
00356     return 1;
00357   }
00358   RunBrowsePython(&state_, ninja_command_, argv[0]);
00359   // If we get here, the browse failed.
00360   return 1;
00361 }
00362 #endif  // _WIN32
00363 
00364 #if defined(_MSC_VER)
00365 int NinjaMain::ToolMSVC(int argc, char* argv[]) {
00366   // Reset getopt: push one argument onto the front of argv, reset optind.
00367   argc++;
00368   argv--;
00369   optind = 0;
00370   return MSVCHelperMain(argc, argv);
00371 }
00372 #endif
00373 
00374 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) {
00375   for (vector<Node*>::const_iterator n = nodes.begin();
00376        n != nodes.end();
00377        ++n) {
00378     for (int i = 0; i < indent; ++i)
00379       printf("  ");
00380     const char* target = (*n)->path().c_str();
00381     if ((*n)->in_edge()) {
00382       printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
00383       if (depth > 1 || depth <= 0)
00384         ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
00385     } else {
00386       printf("%s\n", target);
00387     }
00388   }
00389   return 0;
00390 }
00391 
00392 int ToolTargetsSourceList(State* state) {
00393   for (vector<Edge*>::iterator e = state->edges_.begin();
00394        e != state->edges_.end(); ++e) {
00395     for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
00396          inps != (*e)->inputs_.end(); ++inps) {
00397       if (!(*inps)->in_edge())
00398         printf("%s\n", (*inps)->path().c_str());
00399     }
00400   }
00401   return 0;
00402 }
00403 
00404 int ToolTargetsList(State* state, const string& rule_name) {
00405   set<string> rules;
00406 
00407   // Gather the outputs.
00408   for (vector<Edge*>::iterator e = state->edges_.begin();
00409        e != state->edges_.end(); ++e) {
00410     if ((*e)->rule_->name() == rule_name) {
00411       for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
00412            out_node != (*e)->outputs_.end(); ++out_node) {
00413         rules.insert((*out_node)->path());
00414       }
00415     }
00416   }
00417 
00418   // Print them.
00419   for (set<string>::const_iterator i = rules.begin();
00420        i != rules.end(); ++i) {
00421     printf("%s\n", (*i).c_str());
00422   }
00423 
00424   return 0;
00425 }
00426 
00427 int ToolTargetsList(State* state) {
00428   for (vector<Edge*>::iterator e = state->edges_.begin();
00429        e != state->edges_.end(); ++e) {
00430     for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
00431          out_node != (*e)->outputs_.end(); ++out_node) {
00432       printf("%s: %s\n",
00433              (*out_node)->path().c_str(),
00434              (*e)->rule_->name().c_str());
00435     }
00436   }
00437   return 0;
00438 }
00439 
00440 int NinjaMain::ToolTargets(int argc, char* argv[]) {
00441   int depth = 1;
00442   if (argc >= 1) {
00443     string mode = argv[0];
00444     if (mode == "rule") {
00445       string rule;
00446       if (argc > 1)
00447         rule = argv[1];
00448       if (rule.empty())
00449         return ToolTargetsSourceList(&state_);
00450       else
00451         return ToolTargetsList(&state_, rule);
00452     } else if (mode == "depth") {
00453       if (argc > 1)
00454         depth = atoi(argv[1]);
00455     } else if (mode == "all") {
00456       return ToolTargetsList(&state_);
00457     } else {
00458       const char* suggestion =
00459           SpellcheckString(mode.c_str(), "rule", "depth", "all", NULL);
00460       if (suggestion) {
00461         Error("unknown target tool mode '%s', did you mean '%s'?",
00462               mode.c_str(), suggestion);
00463       } else {
00464         Error("unknown target tool mode '%s'", mode.c_str());
00465       }
00466       return 1;
00467     }
00468   }
00469 
00470   string err;
00471   vector<Node*> root_nodes = state_.RootNodes(&err);
00472   if (err.empty()) {
00473     return ToolTargetsList(root_nodes, depth, 0);
00474   } else {
00475     Error("%s", err.c_str());
00476     return 1;
00477   }
00478 }
00479 
00480 void PrintCommands(Edge* edge, set<Edge*>* seen) {
00481   if (!edge)
00482     return;
00483   if (!seen->insert(edge).second)
00484     return;
00485 
00486   for (vector<Node*>::iterator in = edge->inputs_.begin();
00487        in != edge->inputs_.end(); ++in)
00488     PrintCommands((*in)->in_edge(), seen);
00489 
00490   if (!edge->is_phony())
00491     puts(edge->EvaluateCommand().c_str());
00492 }
00493 
00494 int NinjaMain::ToolCommands(int argc, char* argv[]) {
00495   vector<Node*> nodes;
00496   string err;
00497   if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
00498     Error("%s", err.c_str());
00499     return 1;
00500   }
00501 
00502   set<Edge*> seen;
00503   for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
00504     PrintCommands((*in)->in_edge(), &seen);
00505 
00506   return 0;
00507 }
00508 
00509 int NinjaMain::ToolClean(int argc, char* argv[]) {
00510   // The clean tool uses getopt, and expects argv[0] to contain the name of
00511   // the tool, i.e. "clean".
00512   argc++;
00513   argv--;
00514 
00515   bool generator = false;
00516   bool clean_rules = false;
00517 
00518   optind = 1;
00519   int opt;
00520   while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) {
00521     switch (opt) {
00522     case 'g':
00523       generator = true;
00524       break;
00525     case 'r':
00526       clean_rules = true;
00527       break;
00528     case 'h':
00529     default:
00530       printf("usage: ninja -t clean [options] [targets]\n"
00531 "\n"
00532 "options:\n"
00533 "  -g     also clean files marked as ninja generator output\n"
00534 "  -r     interpret targets as a list of rules to clean instead\n"
00535              );
00536     return 1;
00537     }
00538   }
00539   argv += optind;
00540   argc -= optind;
00541 
00542   if (clean_rules && argc == 0) {
00543     Error("expected a rule to clean");
00544     return 1;
00545   }
00546 
00547   Cleaner cleaner(&state_, config_);
00548   if (argc >= 1) {
00549     if (clean_rules)
00550       return cleaner.CleanRules(argc, argv);
00551     else
00552       return cleaner.CleanTargets(argc, argv);
00553   } else {
00554     return cleaner.CleanAll(generator);
00555   }
00556 }
00557 
00558 void EncodeJSONString(const char *str) {
00559   while (*str) {
00560     if (*str == '"' || *str == '\\')
00561       putchar('\\');
00562     putchar(*str);
00563     str++;
00564   }
00565 }
00566 
00567 int NinjaMain::ToolCompilationDatabase(int argc, char* argv[]) {
00568   bool first = true;
00569   vector<char> cwd;
00570 
00571   do {
00572     cwd.resize(cwd.size() + 1024);
00573     errno = 0;
00574   } while (!getcwd(&cwd[0], cwd.size()) && errno == ERANGE);
00575   if (errno != 0 && errno != ERANGE) {
00576     Error("cannot determine working directory: %s", strerror(errno));
00577     return 1;
00578   }
00579 
00580   putchar('[');
00581   for (vector<Edge*>::iterator e = state_.edges_.begin();
00582        e != state_.edges_.end(); ++e) {
00583     for (int i = 0; i != argc; ++i) {
00584       if ((*e)->rule_->name() == argv[i]) {
00585         if (!first)
00586           putchar(',');
00587 
00588         printf("\n  {\n    \"directory\": \"");
00589         EncodeJSONString(&cwd[0]);
00590         printf("\",\n    \"command\": \"");
00591         EncodeJSONString((*e)->EvaluateCommand().c_str());
00592         printf("\",\n    \"file\": \"");
00593         EncodeJSONString((*e)->inputs_[0]->path().c_str());
00594         printf("\"\n  }");
00595 
00596         first = false;
00597       }
00598     }
00599   }
00600 
00601   puts("\n]");
00602   return 0;
00603 }
00604 
00605 int NinjaMain::ToolUrtle(int argc, char** argv) {
00606   // RLE encoded.
00607   const char* urtle =
00608 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 "
00609 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<"
00610 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5"
00611 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\""
00612 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e"
00613 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c"
00614 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?"
00615 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2"
00616 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P"
00617 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
00618   int count = 0;
00619   for (const char* p = urtle; *p; p++) {
00620     if ('0' <= *p && *p <= '9') {
00621       count = count*10 + *p - '0';
00622     } else {
00623       for (int i = 0; i < std::max(count, 1); ++i)
00624         printf("%c", *p);
00625       count = 0;
00626     }
00627   }
00628   return 0;
00629 }
00630 
00631 /// Find the function to execute for \a tool_name and return it via \a func.
00632 /// Returns a Tool, or NULL if Ninja should exit.
00633 const Tool* ChooseTool(const string& tool_name) {
00634   static const Tool kTools[] = {
00635 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
00636     { "browse", "browse dependency graph in a web browser",
00637       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
00638 #endif
00639 #if defined(_MSC_VER)
00640     { "msvc", "build helper for MSVC cl.exe (EXPERIMENTAL)",
00641       Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
00642 #endif
00643     { "clean", "clean built files",
00644       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean },
00645     { "commands", "list all commands required to rebuild given targets",
00646       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
00647     { "graph", "output graphviz dot file for targets",
00648       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
00649     { "query", "show inputs/outputs for a path",
00650       Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
00651     { "targets",  "list targets by their rule or depth in the DAG",
00652       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
00653     { "compdb",  "dump JSON compilation database to stdout",
00654       Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
00655     { "urtle", NULL,
00656       Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
00657     { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
00658   };
00659 
00660   if (tool_name == "list") {
00661     printf("ninja subtools:\n");
00662     for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
00663       if (tool->desc)
00664         printf("%10s  %s\n", tool->name, tool->desc);
00665     }
00666     return NULL;
00667   }
00668 
00669   for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
00670     if (tool->name == tool_name)
00671       return tool;
00672   }
00673 
00674   vector<const char*> words;
00675   for (const Tool* tool = &kTools[0]; tool->name; ++tool)
00676     words.push_back(tool->name);
00677   const char* suggestion = SpellcheckStringV(tool_name, words);
00678   if (suggestion) {
00679     Fatal("unknown tool '%s', did you mean '%s'?",
00680           tool_name.c_str(), suggestion);
00681   } else {
00682     Fatal("unknown tool '%s'", tool_name.c_str());
00683   }
00684   return NULL;  // Not reached.
00685 }
00686 
00687 /// Enable a debugging mode.  Returns false if Ninja should exit instead
00688 /// of continuing.
00689 bool DebugEnable(const string& name) {
00690   if (name == "list") {
00691     printf("debugging modes:\n"
00692 "  stats    print operation counts/timing info\n"
00693 "  explain  explain what caused a command to execute\n"
00694 "multiple modes can be enabled via -d FOO -d BAR\n");
00695     return false;
00696   } else if (name == "stats") {
00697     g_metrics = new Metrics;
00698     return true;
00699   } else if (name == "explain") {
00700     g_explaining = true;
00701     return true;
00702   } else {
00703     const char* suggestion =
00704         SpellcheckString(name.c_str(), "stats", "explain", NULL);
00705     if (suggestion) {
00706       Error("unknown debug setting '%s', did you mean '%s'?",
00707             name.c_str(), suggestion);
00708     } else {
00709       Error("unknown debug setting '%s'", name.c_str());
00710     }
00711     return false;
00712   }
00713 }
00714 
00715 bool NinjaMain::OpenBuildLog() {
00716   string log_path = ".ninja_log";
00717   if (!build_dir_.empty())
00718     log_path = build_dir_ + "/" + log_path;
00719 
00720   string err;
00721   if (!build_log_.Load(log_path, &err)) {
00722     Error("loading build log %s: %s", log_path.c_str(), err.c_str());
00723     return false;
00724   }
00725   if (!err.empty()) {
00726     // Hack: Load() can return a warning via err by returning true.
00727     Warning("%s", err.c_str());
00728     err.clear();
00729   }
00730 
00731   if (!config_.dry_run) {
00732     if (!build_log_.OpenForWrite(log_path, &err)) {
00733       Error("opening build log: %s", err.c_str());
00734       return false;
00735     }
00736   }
00737 
00738   return true;
00739 }
00740 
00741 /// Open the deps log: load it, then open for writing.
00742 /// @return false on error.
00743 bool NinjaMain::OpenDepsLog() {
00744   string path = ".ninja_deps";
00745   if (!build_dir_.empty())
00746     path = build_dir_ + "/" + path;
00747 
00748   string err;
00749   if (!deps_log_.Load(path, &state_, &err)) {
00750     Error("loading deps log %s: %s", path.c_str(), err.c_str());
00751     return false;
00752   }
00753   if (!err.empty()) {
00754     // Hack: Load() can return a warning via err by returning true.
00755     Warning("%s", err.c_str());
00756     err.clear();
00757   }
00758 
00759   if (!config_.dry_run) {
00760     if (!deps_log_.OpenForWrite(path, &err)) {
00761       Error("opening deps log: %s", err.c_str());
00762       return false;
00763     }
00764   }
00765 
00766   return true;
00767 }
00768 
00769 void NinjaMain::DumpMetrics() {
00770   g_metrics->Report();
00771 
00772   printf("\n");
00773   int count = (int)state_.paths_.size();
00774   int buckets = (int)state_.paths_.bucket_count();
00775   printf("path->node hash load %.2f (%d entries / %d buckets)\n",
00776          count / (double) buckets, count, buckets);
00777 }
00778 
00779 bool NinjaMain::EnsureBuildDirExists() {
00780   build_dir_ = state_.bindings_.LookupVariable("builddir");
00781   if (!build_dir_.empty() && !config_.dry_run) {
00782     if (!disk_interface_.MakeDirs(build_dir_ + "/.") && errno != EEXIST) {
00783       Error("creating build directory %s: %s",
00784             build_dir_.c_str(), strerror(errno));
00785       return false;
00786     }
00787   }
00788   return true;
00789 }
00790 
00791 int NinjaMain::RunBuild(int argc, char** argv) {
00792   string err;
00793   vector<Node*> targets;
00794   if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
00795     Error("%s", err.c_str());
00796     return 1;
00797   }
00798 
00799   Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
00800   for (size_t i = 0; i < targets.size(); ++i) {
00801     if (!builder.AddTarget(targets[i], &err)) {
00802       if (!err.empty()) {
00803         Error("%s", err.c_str());
00804         return 1;
00805       } else {
00806         // Added a target that is already up-to-date; not really
00807         // an error.
00808       }
00809     }
00810   }
00811 
00812   if (builder.AlreadyUpToDate()) {
00813     printf("ninja: no work to do.\n");
00814     return 0;
00815   }
00816 
00817   if (!builder.Build(&err)) {
00818     printf("ninja: build stopped: %s.\n", err.c_str());
00819     if (err.find("interrupted by user") != string::npos) {
00820       return 2;
00821     }
00822     return 1;
00823   }
00824 
00825   return 0;
00826 }
00827 
00828 #ifdef _MSC_VER
00829 
00830 /// This handler processes fatal crashes that you can't catch
00831 /// Test example: C++ exception in a stack-unwind-block
00832 /// Real-world example: ninja launched a compiler to process a tricky
00833 /// C++ input file. The compiler got itself into a state where it
00834 /// generated 3 GB of output and caused ninja to crash.
00835 void TerminateHandler() {
00836   CreateWin32MiniDump(NULL);
00837   Fatal("terminate handler called");
00838 }
00839 
00840 /// On Windows, we want to prevent error dialogs in case of exceptions.
00841 /// This function handles the exception, and writes a minidump.
00842 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
00843   Error("exception: 0x%X", code);  // e.g. EXCEPTION_ACCESS_VIOLATION
00844   fflush(stderr);
00845   CreateWin32MiniDump(ep);
00846   return EXCEPTION_EXECUTE_HANDLER;
00847 }
00848 
00849 #endif  // _MSC_VER
00850 
00851 /// Parse argv for command-line options.
00852 /// Returns an exit code, or -1 if Ninja should continue.
00853 int ReadFlags(int* argc, char*** argv,
00854               Options* options, BuildConfig* config) {
00855   config->parallelism = GuessParallelism();
00856 
00857   enum { OPT_VERSION = 1 };
00858   const option kLongOptions[] = {
00859     { "help", no_argument, NULL, 'h' },
00860     { "version", no_argument, NULL, OPT_VERSION },
00861     { NULL, 0, NULL, 0 }
00862   };
00863 
00864   int opt;
00865   while (!options->tool &&
00866          (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vC:h", kLongOptions,
00867                             NULL)) != -1) {
00868     switch (opt) {
00869       case 'd':
00870         if (!DebugEnable(optarg))
00871           return 1;
00872         break;
00873       case 'f':
00874         options->input_file = optarg;
00875         break;
00876       case 'j': {
00877         char* end;
00878         int value = strtol(optarg, &end, 10);
00879         if (*end != 0 || value <= 0)
00880           Fatal("invalid -j parameter");
00881         config->parallelism = value;
00882         break;
00883       }
00884       case 'k': {
00885         char* end;
00886         int value = strtol(optarg, &end, 10);
00887         if (*end != 0)
00888           Fatal("-k parameter not numeric; did you mean -k 0?");
00889 
00890         // We want to go until N jobs fail, which means we should allow
00891         // N failures and then stop.  For N <= 0, INT_MAX is close enough
00892         // to infinite for most sane builds.
00893         config->failures_allowed = value > 0 ? value : INT_MAX;
00894         break;
00895       }
00896       case 'l': {
00897         char* end;
00898         double value = strtod(optarg, &end);
00899         if (end == optarg)
00900           Fatal("-l parameter not numeric: did you mean -l 0.0?");
00901         config->max_load_average = value;
00902         break;
00903       }
00904       case 'n':
00905         config->dry_run = true;
00906         break;
00907       case 't':
00908         options->tool = ChooseTool(optarg);
00909         if (!options->tool)
00910           return 0;
00911         break;
00912       case 'v':
00913         config->verbosity = BuildConfig::VERBOSE;
00914         break;
00915       case 'C':
00916         options->working_dir = optarg;
00917         break;
00918       case OPT_VERSION:
00919         printf("%s\n", kNinjaVersion);
00920         return 0;
00921       case 'h':
00922       default:
00923         Usage(*config);
00924         return 1;
00925     }
00926   }
00927   *argv += optind;
00928   *argc -= optind;
00929 
00930   return -1;
00931 }
00932 
00933 int real_main(int argc, char** argv) {
00934   BuildConfig config;
00935   Options options = {};
00936   options.input_file = "build.ninja";
00937 
00938   setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
00939 
00940   int exit_code = ReadFlags(&argc, &argv, &options, &config);
00941   if (exit_code >= 0)
00942     return exit_code;
00943 
00944   if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
00945     // None of the RUN_AFTER_FLAGS actually use a NinjaMain, but it's needed
00946     // by other tools.
00947     NinjaMain ninja(argv[0], config);
00948     return (ninja.*options.tool->func)(argc, argv);
00949   }
00950 
00951   if (options.working_dir) {
00952     // The formatting of this string, complete with funny quotes, is
00953     // so Emacs can properly identify that the cwd has changed for
00954     // subsequent commands.
00955     // Don't print this if a tool is being used, so that tool output
00956     // can be piped into a file without this string showing up.
00957     if (!options.tool)
00958       printf("ninja: Entering directory `%s'\n", options.working_dir);
00959     if (chdir(options.working_dir) < 0) {
00960       Fatal("chdir to '%s' - %s", options.working_dir, strerror(errno));
00961     }
00962   }
00963 
00964   // The build can take up to 2 passes: one to rebuild the manifest, then
00965   // another to build the desired target.
00966   for (int cycle = 0; cycle < 2; ++cycle) {
00967     NinjaMain ninja(argv[0], config);
00968 
00969     RealFileReader file_reader;
00970     ManifestParser parser(&ninja.state_, &file_reader);
00971     string err;
00972     if (!parser.Load(options.input_file, &err)) {
00973       Error("%s", err.c_str());
00974       return 1;
00975     }
00976 
00977     if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
00978       return (ninja.*options.tool->func)(argc, argv);
00979 
00980     if (!ninja.EnsureBuildDirExists())
00981       return 1;
00982 
00983     if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog())
00984       return 1;
00985 
00986     if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
00987       return (ninja.*options.tool->func)(argc, argv);
00988 
00989     // The first time through, attempt to rebuild the manifest before
00990     // building anything else.
00991     if (cycle == 0) {
00992       if (ninja.RebuildManifest(options.input_file, &err)) {
00993         // Start the build over with the new manifest.
00994         continue;
00995       } else if (!err.empty()) {
00996         Error("rebuilding '%s': %s", options.input_file, err.c_str());
00997         return 1;
00998       }
00999     }
01000 
01001     int result = ninja.RunBuild(argc, argv);
01002     if (g_metrics)
01003       ninja.DumpMetrics();
01004     return result;
01005   }
01006 
01007   return 1;  // Shouldn't be reached.
01008 }
01009 
01010 }  // anonymous namespace
01011 
01012 int main(int argc, char** argv) {
01013 #if !defined(NINJA_BOOTSTRAP) && defined(_MSC_VER)
01014   // Set a handler to catch crashes not caught by the __try..__except
01015   // block (e.g. an exception in a stack-unwind-block).
01016   set_terminate(TerminateHandler);
01017   __try {
01018     // Running inside __try ... __except suppresses any Windows error
01019     // dialogs for errors such as bad_alloc.
01020     return real_main(argc, argv);
01021   }
01022   __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
01023     // Common error situations return exitCode=1. 2 was chosen to
01024     // indicate a more serious problem.
01025     return 2;
01026   }
01027 #else
01028   return real_main(argc, argv);
01029 #endif
01030 }