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