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