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