github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/src/ninja.cc (about)

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