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 #ifdef _WIN32
22 #include "getopt.h"
23 #include <direct.h>
24 #include <windows.h>
25 #else
26 #include <getopt.h>
27 #include <unistd.h>
28 #endif
29 
30 #include "browse.h"
31 #include "build.h"
32 #include "build_log.h"
33 #include "deps_log.h"
34 #include "clean.h"
35 #include "debug_flags.h"
36 #include "disk_interface.h"
37 #include "graph.h"
38 #include "graphviz.h"
39 #include "manifest_parser.h"
40 #include "metrics.h"
41 #include "state.h"
42 #include "util.h"
43 #include "version.h"
44 
45 #ifdef _MSC_VER
46 // Defined in msvc_helper_main-win32.cc.
47 int MSVCHelperMain(int argc, char** argv);
48 
49 // Defined in minidump-win32.cc.
50 void CreateWin32MiniDump(_EXCEPTION_POINTERS* pep);
51 #endif
52 
53 namespace {
54 
55 struct Tool;
56 
57 /// Command-line options.
58 struct Options {
59  /// Build file to load.
60  const char* input_file;
61 
62  /// Directory to change into before running.
63  const char* working_dir;
64 
65  /// Tool to run rather than building.
66  const Tool* tool;
67 
68  /// Whether duplicate rules for one target should warn or print an error.
69  bool dupe_edges_should_err;
70 };
71 
72 /// The Ninja main() loads up a series of data structures; various tools need
73 /// to poke into these, so store them as fields on an object.
74 struct NinjaMain : public BuildLogUser {
75  NinjaMain(const char* ninja_command, const BuildConfig& config) :
76  ninja_command_(ninja_command), config_(config) {}
77 
78  /// Command line used to run Ninja.
79  const char* ninja_command_;
80 
81  /// Build configuration set from flags (e.g. parallelism).
82  const BuildConfig& config_;
83 
84  /// Loaded state (rules, nodes).
85  State state_;
86 
87  /// Functions for accesssing the disk.
88  RealDiskInterface disk_interface_;
89 
90  /// The build directory, used for storing the build log etc.
91  string build_dir_;
92 
93  BuildLog build_log_;
94  DepsLog deps_log_;
95 
96  /// The type of functions that are the entry points to tools (subcommands).
97  typedef int (NinjaMain::*ToolFunc)(int, char**);
98 
99  /// Get the Node for a given command-line path, handling features like
100  /// spell correction.
101  Node* CollectTarget(const char* cpath, string* err);
102 
103  /// CollectTarget for all command-line arguments, filling in \a targets.
104  bool CollectTargetsFromArgs(int argc, char* argv[],
105  vector<Node*>* targets, string* err);
106 
107  // The various subcommands, run via "-t XXX".
108  int ToolGraph(int argc, char* argv[]);
109  int ToolQuery(int argc, char* argv[]);
110  int ToolDeps(int argc, char* argv[]);
111  int ToolBrowse(int argc, char* argv[]);
112  int ToolMSVC(int argc, char* argv[]);
113  int ToolTargets(int argc, char* argv[]);
114  int ToolCommands(int argc, char* argv[]);
115  int ToolClean(int argc, char* argv[]);
116  int ToolCompilationDatabase(int argc, char* argv[]);
117  int ToolRecompact(int argc, char* argv[]);
118  int ToolUrtle(int argc, char** argv);
119 
120  /// Open the build log.
121  /// @return false on error.
122  bool OpenBuildLog(bool recompact_only = false);
123 
124  /// Open the deps log: load it, then open for writing.
125  /// @return false on error.
126  bool OpenDepsLog(bool recompact_only = false);
127 
128  /// Ensure the build directory exists, creating it if necessary.
129  /// @return false on error.
130  bool EnsureBuildDirExists();
131 
132  /// Rebuild the manifest, if necessary.
133  /// Fills in \a err on error.
134  /// @return true if the manifest was rebuilt.
135  bool RebuildManifest(const char* input_file, string* err);
136 
137  /// Build the targets listed on the command line.
138  /// @return an exit code.
139  int RunBuild(int argc, char** argv);
140 
141  /// Dump the output requested by '-d stats'.
142  void DumpMetrics();
143 
144  virtual bool IsPathDead(StringPiece s) const {
145  Node* n = state_.LookupNode(s);
146  if (!n || !n->in_edge())
147  return false;
148  // Just checking n isn't enough: If an old output is both in the build log
149  // and in the deps log, it will have a Node object in state_. (It will also
150  // have an in edge if one of its inputs is another output that's in the deps
151  // log, but having a deps edge product an output thats input to another deps
152  // edge is rare, and the first recompaction will delete all old outputs from
153  // the deps log, and then a second recompaction will clear the build log,
154  // which seems good enough for this corner case.)
155  // Do keep entries around for files which still exist on disk, for
156  // generators that want to use this information.
157  string err;
158  TimeStamp mtime = disk_interface_.Stat(s.AsString(), &err);
159  if (mtime == -1)
160  Error("%s", err.c_str()); // Log and ignore Stat() errors.
161  return mtime == 0;
162  }
163 };
164 
165 /// Subtools, accessible via "-t foo".
166 struct Tool {
167  /// Short name of the tool.
168  const char* name;
169 
170  /// Description (shown in "-t list").
171  const char* desc;
172 
173  /// When to run the tool.
174  enum {
175  /// Run after parsing the command-line flags and potentially changing
176  /// the current working directory (as early as possible).
177  RUN_AFTER_FLAGS,
178 
179  /// Run after loading build.ninja.
180  RUN_AFTER_LOAD,
181 
182  /// Run after loading the build/deps logs.
183  RUN_AFTER_LOGS,
184  } when;
185 
186  /// Implementation of the tool.
187  NinjaMain::ToolFunc func;
188 };
189 
190 /// Print usage information.
191 void Usage(const BuildConfig& config) {
192  fprintf(stderr,
193 "usage: ninja [options] [targets...]\n"
194 "\n"
195 "if targets are unspecified, builds the 'default' target (see manual).\n"
196 "\n"
197 "options:\n"
198 " --version print ninja version (\"%s\")\n"
199 "\n"
200 " -C DIR change to DIR before doing anything else\n"
201 " -f FILE specify input build file [default=build.ninja]\n"
202 "\n"
203 " -j N run N jobs in parallel [default=%d, derived from CPUs available]\n"
204 " -k N keep going until N jobs fail [default=1]\n"
205 " -l N do not start new jobs if the load average is greater than N\n"
206 " -n dry run (don't run commands but act like they succeeded)\n"
207 " -v show all command lines while building\n"
208 "\n"
209 " -d MODE enable debugging (use -d list to list modes)\n"
210 " -t TOOL run a subtool (use -t list to list subtools)\n"
211 " terminates toplevel options; further flags are passed to the tool\n"
212 " -w FLAG adjust warnings (use -w list to list warnings)\n",
213  kNinjaVersion, config.parallelism);
214 }
215 
216 /// Choose a default value for the -j (parallelism) flag.
217 int GuessParallelism() {
218  switch (int processors = GetProcessorCount()) {
219  case 0:
220  case 1:
221  return 2;
222  case 2:
223  return 3;
224  default:
225  return processors + 2;
226  }
227 }
228 
229 /// An implementation of ManifestParser::FileReader that actually reads
230 /// the file.
231 struct RealFileReader : public ManifestParser::FileReader {
232  virtual bool ReadFile(const string& path, string* content, string* err) {
233  return ::ReadFile(path, content, err) == 0;
234  }
235 };
236 
237 /// Rebuild the build manifest, if necessary.
238 /// Returns true if the manifest was rebuilt.
239 bool NinjaMain::RebuildManifest(const char* input_file, string* err) {
240  string path = input_file;
241  unsigned int slash_bits; // Unused because this path is only used for lookup.
242  if (!CanonicalizePath(&path, &slash_bits, err))
243  return false;
244  Node* node = state_.LookupNode(path);
245  if (!node)
246  return false;
247 
248  Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
249  if (!builder.AddTarget(node, err))
250  return false;
251 
252  if (builder.AlreadyUpToDate())
253  return false; // Not an error, but we didn't rebuild.
254 
255  // Even if the manifest was cleaned by a restat rule, claim that it was
256  // rebuilt. Not doing so can lead to crashes, see
257  // https://github.com/martine/ninja/issues/874
258  return builder.Build(err);
259 }
260 
261 Node* NinjaMain::CollectTarget(const char* cpath, string* err) {
262  string path = cpath;
263  unsigned int slash_bits; // Unused because this path is only used for lookup.
264  if (!CanonicalizePath(&path, &slash_bits, err))
265  return NULL;
266 
267  // Special syntax: "foo.cc^" means "the first output of foo.cc".
268  bool first_dependent = false;
269  if (!path.empty() && path[path.size() - 1] == '^') {
270  path.resize(path.size() - 1);
271  first_dependent = true;
272  }
273 
274  Node* node = state_.LookupNode(path);
275  if (node) {
276  if (first_dependent) {
277  if (node->out_edges().empty()) {
278  *err = "'" + path + "' has no out edge";
279  return NULL;
280  }
281  Edge* edge = node->out_edges()[0];
282  if (edge->outputs_.empty()) {
283  edge->Dump();
284  Fatal("edge has no outputs");
285  }
286  node = edge->outputs_[0];
287  }
288  return node;
289  } else {
290  *err = "unknown target '" + path + "'";
291 
292  if (path == "clean") {
293  *err += ", did you mean 'ninja -t clean'?";
294  } else if (path == "help") {
295  *err += ", did you mean 'ninja -h'?";
296  } else {
297  Node* suggestion = state_.SpellcheckNode(path);
298  if (suggestion) {
299  *err += ", did you mean '" + suggestion->path() + "'?";
300  }
301  }
302  return NULL;
303  }
304 }
305 
306 bool NinjaMain::CollectTargetsFromArgs(int argc, char* argv[],
307  vector<Node*>* targets, string* err) {
308  if (argc == 0) {
309  *targets = state_.DefaultNodes(err);
310  return err->empty();
311  }
312 
313  for (int i = 0; i < argc; ++i) {
314  Node* node = CollectTarget(argv[i], err);
315  if (node == NULL)
316  return false;
317  targets->push_back(node);
318  }
319  return true;
320 }
321 
322 int NinjaMain::ToolGraph(int argc, char* argv[]) {
323  vector<Node*> nodes;
324  string err;
325  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
326  Error("%s", err.c_str());
327  return 1;
328  }
329 
330  GraphViz graph;
331  graph.Start();
332  for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
333  graph.AddTarget(*n);
334  graph.Finish();
335 
336  return 0;
337 }
338 
339 int NinjaMain::ToolQuery(int argc, char* argv[]) {
340  if (argc == 0) {
341  Error("expected a target to query");
342  return 1;
343  }
344 
345  for (int i = 0; i < argc; ++i) {
346  string err;
347  Node* node = CollectTarget(argv[i], &err);
348  if (!node) {
349  Error("%s", err.c_str());
350  return 1;
351  }
352 
353  printf("%s:\n", node->path().c_str());
354  if (Edge* edge = node->in_edge()) {
355  printf(" input: %s\n", edge->rule_->name().c_str());
356  for (int in = 0; in < (int)edge->inputs_.size(); in++) {
357  const char* label = "";
358  if (edge->is_implicit(in))
359  label = "| ";
360  else if (edge->is_order_only(in))
361  label = "|| ";
362  printf(" %s%s\n", label, edge->inputs_[in]->path().c_str());
363  }
364  }
365  printf(" outputs:\n");
366  for (vector<Edge*>::const_iterator edge = node->out_edges().begin();
367  edge != node->out_edges().end(); ++edge) {
368  for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
369  out != (*edge)->outputs_.end(); ++out) {
370  printf(" %s\n", (*out)->path().c_str());
371  }
372  }
373  }
374  return 0;
375 }
376 
377 #if defined(NINJA_HAVE_BROWSE)
378 int NinjaMain::ToolBrowse(int argc, char* argv[]) {
379  if (argc < 1) {
380  Error("expected a target to browse");
381  return 1;
382  }
383  RunBrowsePython(&state_, ninja_command_, argv[0]);
384  // If we get here, the browse failed.
385  return 1;
386 }
387 #endif // _WIN32
388 
389 #if defined(_MSC_VER)
390 int NinjaMain::ToolMSVC(int argc, char* argv[]) {
391  // Reset getopt: push one argument onto the front of argv, reset optind.
392  argc++;
393  argv--;
394  optind = 0;
395  return MSVCHelperMain(argc, argv);
396 }
397 #endif
398 
399 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) {
400  for (vector<Node*>::const_iterator n = nodes.begin();
401  n != nodes.end();
402  ++n) {
403  for (int i = 0; i < indent; ++i)
404  printf(" ");
405  const char* target = (*n)->path().c_str();
406  if ((*n)->in_edge()) {
407  printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
408  if (depth > 1 || depth <= 0)
409  ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
410  } else {
411  printf("%s\n", target);
412  }
413  }
414  return 0;
415 }
416 
417 int ToolTargetsSourceList(State* state) {
418  for (vector<Edge*>::iterator e = state->edges_.begin();
419  e != state->edges_.end(); ++e) {
420  for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
421  inps != (*e)->inputs_.end(); ++inps) {
422  if (!(*inps)->in_edge())
423  printf("%s\n", (*inps)->path().c_str());
424  }
425  }
426  return 0;
427 }
428 
429 int ToolTargetsList(State* state, const string& rule_name) {
430  set<string> rules;
431 
432  // Gather the outputs.
433  for (vector<Edge*>::iterator e = state->edges_.begin();
434  e != state->edges_.end(); ++e) {
435  if ((*e)->rule_->name() == rule_name) {
436  for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
437  out_node != (*e)->outputs_.end(); ++out_node) {
438  rules.insert((*out_node)->path());
439  }
440  }
441  }
442 
443  // Print them.
444  for (set<string>::const_iterator i = rules.begin();
445  i != rules.end(); ++i) {
446  printf("%s\n", (*i).c_str());
447  }
448 
449  return 0;
450 }
451 
452 int ToolTargetsList(State* state) {
453  for (vector<Edge*>::iterator e = state->edges_.begin();
454  e != state->edges_.end(); ++e) {
455  for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
456  out_node != (*e)->outputs_.end(); ++out_node) {
457  printf("%s: %s\n",
458  (*out_node)->path().c_str(),
459  (*e)->rule_->name().c_str());
460  }
461  }
462  return 0;
463 }
464 
465 int NinjaMain::ToolDeps(int argc, char** argv) {
466  vector<Node*> nodes;
467  if (argc == 0) {
468  for (vector<Node*>::const_iterator ni = deps_log_.nodes().begin();
469  ni != deps_log_.nodes().end(); ++ni) {
470  if (deps_log_.IsDepsEntryLiveFor(*ni))
471  nodes.push_back(*ni);
472  }
473  } else {
474  string err;
475  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
476  Error("%s", err.c_str());
477  return 1;
478  }
479  }
480 
481  RealDiskInterface disk_interface;
482  for (vector<Node*>::iterator it = nodes.begin(), end = nodes.end();
483  it != end; ++it) {
484  DepsLog::Deps* deps = deps_log_.GetDeps(*it);
485  if (!deps) {
486  printf("%s: deps not found\n", (*it)->path().c_str());
487  continue;
488  }
489 
490  string err;
491  TimeStamp mtime = disk_interface.Stat((*it)->path(), &err);
492  if (mtime == -1)
493  Error("%s", err.c_str()); // Log and ignore Stat() errors;
494  printf("%s: #deps %d, deps mtime %d (%s)\n",
495  (*it)->path().c_str(), deps->node_count, deps->mtime,
496  (!mtime || mtime > deps->mtime ? "STALE":"VALID"));
497  for (int i = 0; i < deps->node_count; ++i)
498  printf(" %s\n", deps->nodes[i]->path().c_str());
499  printf("\n");
500  }
501 
502  return 0;
503 }
504 
505 int NinjaMain::ToolTargets(int argc, char* argv[]) {
506  int depth = 1;
507  if (argc >= 1) {
508  string mode = argv[0];
509  if (mode == "rule") {
510  string rule;
511  if (argc > 1)
512  rule = argv[1];
513  if (rule.empty())
514  return ToolTargetsSourceList(&state_);
515  else
516  return ToolTargetsList(&state_, rule);
517  } else if (mode == "depth") {
518  if (argc > 1)
519  depth = atoi(argv[1]);
520  } else if (mode == "all") {
521  return ToolTargetsList(&state_);
522  } else {
523  const char* suggestion =
524  SpellcheckString(mode.c_str(), "rule", "depth", "all", NULL);
525  if (suggestion) {
526  Error("unknown target tool mode '%s', did you mean '%s'?",
527  mode.c_str(), suggestion);
528  } else {
529  Error("unknown target tool mode '%s'", mode.c_str());
530  }
531  return 1;
532  }
533  }
534 
535  string err;
536  vector<Node*> root_nodes = state_.RootNodes(&err);
537  if (err.empty()) {
538  return ToolTargetsList(root_nodes, depth, 0);
539  } else {
540  Error("%s", err.c_str());
541  return 1;
542  }
543 }
544 
545 void PrintCommands(Edge* edge, set<Edge*>* seen) {
546  if (!edge)
547  return;
548  if (!seen->insert(edge).second)
549  return;
550 
551  for (vector<Node*>::iterator in = edge->inputs_.begin();
552  in != edge->inputs_.end(); ++in)
553  PrintCommands((*in)->in_edge(), seen);
554 
555  if (!edge->is_phony())
556  puts(edge->EvaluateCommand().c_str());
557 }
558 
559 int NinjaMain::ToolCommands(int argc, char* argv[]) {
560  vector<Node*> nodes;
561  string err;
562  if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
563  Error("%s", err.c_str());
564  return 1;
565  }
566 
567  set<Edge*> seen;
568  for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
569  PrintCommands((*in)->in_edge(), &seen);
570 
571  return 0;
572 }
573 
574 int NinjaMain::ToolClean(int argc, char* argv[]) {
575  // The clean tool uses getopt, and expects argv[0] to contain the name of
576  // the tool, i.e. "clean".
577  argc++;
578  argv--;
579 
580  bool generator = false;
581  bool clean_rules = false;
582 
583  optind = 1;
584  int opt;
585  while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) {
586  switch (opt) {
587  case 'g':
588  generator = true;
589  break;
590  case 'r':
591  clean_rules = true;
592  break;
593  case 'h':
594  default:
595  printf("usage: ninja -t clean [options] [targets]\n"
596 "\n"
597 "options:\n"
598 " -g also clean files marked as ninja generator output\n"
599 " -r interpret targets as a list of rules to clean instead\n"
600  );
601  return 1;
602  }
603  }
604  argv += optind;
605  argc -= optind;
606 
607  if (clean_rules && argc == 0) {
608  Error("expected a rule to clean");
609  return 1;
610  }
611 
612  Cleaner cleaner(&state_, config_);
613  if (argc >= 1) {
614  if (clean_rules)
615  return cleaner.CleanRules(argc, argv);
616  else
617  return cleaner.CleanTargets(argc, argv);
618  } else {
619  return cleaner.CleanAll(generator);
620  }
621 }
622 
623 void EncodeJSONString(const char *str) {
624  while (*str) {
625  if (*str == '"' || *str == '\\')
626  putchar('\\');
627  putchar(*str);
628  str++;
629  }
630 }
631 
632 int NinjaMain::ToolCompilationDatabase(int argc, char* argv[]) {
633  bool first = true;
634  vector<char> cwd;
635 
636  do {
637  cwd.resize(cwd.size() + 1024);
638  errno = 0;
639  } while (!getcwd(&cwd[0], cwd.size()) && errno == ERANGE);
640  if (errno != 0 && errno != ERANGE) {
641  Error("cannot determine working directory: %s", strerror(errno));
642  return 1;
643  }
644 
645  putchar('[');
646  for (vector<Edge*>::iterator e = state_.edges_.begin();
647  e != state_.edges_.end(); ++e) {
648  if ((*e)->inputs_.empty())
649  continue;
650  for (int i = 0; i != argc; ++i) {
651  if ((*e)->rule_->name() == argv[i]) {
652  if (!first)
653  putchar(',');
654 
655  printf("\n {\n \"directory\": \"");
656  EncodeJSONString(&cwd[0]);
657  printf("\",\n \"command\": \"");
658  EncodeJSONString((*e)->EvaluateCommand().c_str());
659  printf("\",\n \"file\": \"");
660  EncodeJSONString((*e)->inputs_[0]->path().c_str());
661  printf("\"\n }");
662 
663  first = false;
664  }
665  }
666  }
667 
668  puts("\n]");
669  return 0;
670 }
671 
672 int NinjaMain::ToolRecompact(int argc, char* argv[]) {
673  if (!EnsureBuildDirExists())
674  return 1;
675 
676  if (!OpenBuildLog(/*recompact_only=*/true) ||
677  !OpenDepsLog(/*recompact_only=*/true))
678  return 1;
679 
680  return 0;
681 }
682 
683 int NinjaMain::ToolUrtle(int argc, char** argv) {
684  // RLE encoded.
685  const char* urtle =
686 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 "
687 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<"
688 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5"
689 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\""
690 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e"
691 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c"
692 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?"
693 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2"
694 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P"
695 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n";
696  int count = 0;
697  for (const char* p = urtle; *p; p++) {
698  if ('0' <= *p && *p <= '9') {
699  count = count*10 + *p - '0';
700  } else {
701  for (int i = 0; i < std::max(count, 1); ++i)
702  printf("%c", *p);
703  count = 0;
704  }
705  }
706  return 0;
707 }
708 
709 /// Find the function to execute for \a tool_name and return it via \a func.
710 /// Returns a Tool, or NULL if Ninja should exit.
711 const Tool* ChooseTool(const string& tool_name) {
712  static const Tool kTools[] = {
713 #if defined(NINJA_HAVE_BROWSE)
714  { "browse", "browse dependency graph in a web browser",
715  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolBrowse },
716 #endif
717 #if defined(_MSC_VER)
718  { "msvc", "build helper for MSVC cl.exe (EXPERIMENTAL)",
719  Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolMSVC },
720 #endif
721  { "clean", "clean built files",
722  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolClean },
723  { "commands", "list all commands required to rebuild given targets",
724  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCommands },
725  { "deps", "show dependencies stored in the deps log",
726  Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
727  { "graph", "output graphviz dot file for targets",
728  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
729  { "query", "show inputs/outputs for a path",
730  Tool::RUN_AFTER_LOGS, &NinjaMain::ToolQuery },
731  { "targets", "list targets by their rule or depth in the DAG",
732  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolTargets },
733  { "compdb", "dump JSON compilation database to stdout",
734  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolCompilationDatabase },
735  { "recompact", "recompacts ninja-internal data structures",
736  Tool::RUN_AFTER_LOAD, &NinjaMain::ToolRecompact },
737  { "urtle", NULL,
738  Tool::RUN_AFTER_FLAGS, &NinjaMain::ToolUrtle },
739  { NULL, NULL, Tool::RUN_AFTER_FLAGS, NULL }
740  };
741 
742  if (tool_name == "list") {
743  printf("ninja subtools:\n");
744  for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
745  if (tool->desc)
746  printf("%10s %s\n", tool->name, tool->desc);
747  }
748  return NULL;
749  }
750 
751  for (const Tool* tool = &kTools[0]; tool->name; ++tool) {
752  if (tool->name == tool_name)
753  return tool;
754  }
755 
756  vector<const char*> words;
757  for (const Tool* tool = &kTools[0]; tool->name; ++tool)
758  words.push_back(tool->name);
759  const char* suggestion = SpellcheckStringV(tool_name, words);
760  if (suggestion) {
761  Fatal("unknown tool '%s', did you mean '%s'?",
762  tool_name.c_str(), suggestion);
763  } else {
764  Fatal("unknown tool '%s'", tool_name.c_str());
765  }
766  return NULL; // Not reached.
767 }
768 
769 /// Enable a debugging mode. Returns false if Ninja should exit instead
770 /// of continuing.
771 bool DebugEnable(const string& name) {
772  if (name == "list") {
773  printf("debugging modes:\n"
774 " stats print operation counts/timing info\n"
775 " explain explain what caused a command to execute\n"
776 " keeprsp don't delete @response files on success\n"
777 #ifdef _WIN32
778 " nostatcache don't batch stat() calls per directory and cache them\n"
779 #endif
780 "multiple modes can be enabled via -d FOO -d BAR\n");
781  return false;
782  } else if (name == "stats") {
783  g_metrics = new Metrics;
784  return true;
785  } else if (name == "explain") {
786  g_explaining = true;
787  return true;
788  } else if (name == "keeprsp") {
789  g_keep_rsp = true;
790  return true;
791  } else if (name == "nostatcache") {
792  g_experimental_statcache = false;
793  return true;
794  } else {
795  const char* suggestion =
796  SpellcheckString(name.c_str(), "stats", "explain", "keeprsp",
797  "nostatcache", NULL);
798  if (suggestion) {
799  Error("unknown debug setting '%s', did you mean '%s'?",
800  name.c_str(), suggestion);
801  } else {
802  Error("unknown debug setting '%s'", name.c_str());
803  }
804  return false;
805  }
806 }
807 
808 /// Set a warning flag. Returns false if Ninja should exit instead of
809 /// continuing.
810 bool WarningEnable(const string& name, Options* options) {
811  if (name == "list") {
812  printf("warning flags:\n"
813 " dupbuild={err,warn} multiple build lines for one target\n");
814  return false;
815  } else if (name == "dupbuild=err") {
816  options->dupe_edges_should_err = true;
817  return true;
818  } else if (name == "dupbuild=warn") {
819  options->dupe_edges_should_err = false;
820  return true;
821  } else {
822  const char* suggestion =
823  SpellcheckString(name.c_str(), "dupbuild=err", "dupbuild=warn", NULL);
824  if (suggestion) {
825  Error("unknown warning flag '%s', did you mean '%s'?",
826  name.c_str(), suggestion);
827  } else {
828  Error("unknown warning flag '%s'", name.c_str());
829  }
830  return false;
831  }
832 }
833 
834 bool NinjaMain::OpenBuildLog(bool recompact_only) {
835  string log_path = ".ninja_log";
836  if (!build_dir_.empty())
837  log_path = build_dir_ + "/" + log_path;
838 
839  string err;
840  if (!build_log_.Load(log_path, &err)) {
841  Error("loading build log %s: %s", log_path.c_str(), err.c_str());
842  return false;
843  }
844  if (!err.empty()) {
845  // Hack: Load() can return a warning via err by returning true.
846  Warning("%s", err.c_str());
847  err.clear();
848  }
849 
850  if (recompact_only) {
851  bool success = build_log_.Recompact(log_path, *this, &err);
852  if (!success)
853  Error("failed recompaction: %s", err.c_str());
854  return success;
855  }
856 
857  if (!config_.dry_run) {
858  if (!build_log_.OpenForWrite(log_path, *this, &err)) {
859  Error("opening build log: %s", err.c_str());
860  return false;
861  }
862  }
863 
864  return true;
865 }
866 
867 /// Open the deps log: load it, then open for writing.
868 /// @return false on error.
869 bool NinjaMain::OpenDepsLog(bool recompact_only) {
870  string path = ".ninja_deps";
871  if (!build_dir_.empty())
872  path = build_dir_ + "/" + path;
873 
874  string err;
875  if (!deps_log_.Load(path, &state_, &err)) {
876  Error("loading deps log %s: %s", path.c_str(), err.c_str());
877  return false;
878  }
879  if (!err.empty()) {
880  // Hack: Load() can return a warning via err by returning true.
881  Warning("%s", err.c_str());
882  err.clear();
883  }
884 
885  if (recompact_only) {
886  bool success = deps_log_.Recompact(path, &err);
887  if (!success)
888  Error("failed recompaction: %s", err.c_str());
889  return success;
890  }
891 
892  if (!config_.dry_run) {
893  if (!deps_log_.OpenForWrite(path, &err)) {
894  Error("opening deps log: %s", err.c_str());
895  return false;
896  }
897  }
898 
899  return true;
900 }
901 
902 void NinjaMain::DumpMetrics() {
903  g_metrics->Report();
904 
905  printf("\n");
906  int count = (int)state_.paths_.size();
907  int buckets = (int)state_.paths_.bucket_count();
908  printf("path->node hash load %.2f (%d entries / %d buckets)\n",
909  count / (double) buckets, count, buckets);
910 }
911 
912 bool NinjaMain::EnsureBuildDirExists() {
913  build_dir_ = state_.bindings_.LookupVariable("builddir");
914  if (!build_dir_.empty() && !config_.dry_run) {
915  if (!disk_interface_.MakeDirs(build_dir_ + "/.") && errno != EEXIST) {
916  Error("creating build directory %s: %s",
917  build_dir_.c_str(), strerror(errno));
918  return false;
919  }
920  }
921  return true;
922 }
923 
924 int NinjaMain::RunBuild(int argc, char** argv) {
925  string err;
926  vector<Node*> targets;
927  if (!CollectTargetsFromArgs(argc, argv, &targets, &err)) {
928  Error("%s", err.c_str());
929  return 1;
930  }
931 
932  disk_interface_.AllowStatCache(g_experimental_statcache);
933 
934  Builder builder(&state_, config_, &build_log_, &deps_log_, &disk_interface_);
935  for (size_t i = 0; i < targets.size(); ++i) {
936  if (!builder.AddTarget(targets[i], &err)) {
937  if (!err.empty()) {
938  Error("%s", err.c_str());
939  return 1;
940  } else {
941  // Added a target that is already up-to-date; not really
942  // an error.
943  }
944  }
945  }
946 
947  // Make sure restat rules do not see stale timestamps.
948  disk_interface_.AllowStatCache(false);
949 
950  if (builder.AlreadyUpToDate()) {
951  printf("ninja: no work to do.\n");
952  return 0;
953  }
954 
955  if (!builder.Build(&err)) {
956  printf("ninja: build stopped: %s.\n", err.c_str());
957  if (err.find("interrupted by user") != string::npos) {
958  return 2;
959  }
960  return 1;
961  }
962 
963  return 0;
964 }
965 
966 #ifdef _MSC_VER
967 
968 /// This handler processes fatal crashes that you can't catch
969 /// Test example: C++ exception in a stack-unwind-block
970 /// Real-world example: ninja launched a compiler to process a tricky
971 /// C++ input file. The compiler got itself into a state where it
972 /// generated 3 GB of output and caused ninja to crash.
973 void TerminateHandler() {
974  CreateWin32MiniDump(NULL);
975  Fatal("terminate handler called");
976 }
977 
978 /// On Windows, we want to prevent error dialogs in case of exceptions.
979 /// This function handles the exception, and writes a minidump.
980 int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
981  Error("exception: 0x%X", code); // e.g. EXCEPTION_ACCESS_VIOLATION
982  fflush(stderr);
983  CreateWin32MiniDump(ep);
984  return EXCEPTION_EXECUTE_HANDLER;
985 }
986 
987 #endif // _MSC_VER
988 
989 /// Parse argv for command-line options.
990 /// Returns an exit code, or -1 if Ninja should continue.
991 int ReadFlags(int* argc, char*** argv,
992  Options* options, BuildConfig* config) {
993  config->parallelism = GuessParallelism();
994 
995  enum { OPT_VERSION = 1 };
996  const option kLongOptions[] = {
997  { "help", no_argument, NULL, 'h' },
998  { "version", no_argument, NULL, OPT_VERSION },
999  { NULL, 0, NULL, 0 }
1000  };
1001 
1002  int opt;
1003  while (!options->tool &&
1004  (opt = getopt_long(*argc, *argv, "d:f:j:k:l:nt:vw:C:h", kLongOptions,
1005  NULL)) != -1) {
1006  switch (opt) {
1007  case 'd':
1008  if (!DebugEnable(optarg))
1009  return 1;
1010  break;
1011  case 'f':
1012  options->input_file = optarg;
1013  break;
1014  case 'j': {
1015  char* end;
1016  int value = strtol(optarg, &end, 10);
1017  if (*end != 0 || value <= 0)
1018  Fatal("invalid -j parameter");
1019  config->parallelism = value;
1020  break;
1021  }
1022  case 'k': {
1023  char* end;
1024  int value = strtol(optarg, &end, 10);
1025  if (*end != 0)
1026  Fatal("-k parameter not numeric; did you mean -k 0?");
1027 
1028  // We want to go until N jobs fail, which means we should allow
1029  // N failures and then stop. For N <= 0, INT_MAX is close enough
1030  // to infinite for most sane builds.
1031  config->failures_allowed = value > 0 ? value : INT_MAX;
1032  break;
1033  }
1034  case 'l': {
1035  char* end;
1036  double value = strtod(optarg, &end);
1037  if (end == optarg)
1038  Fatal("-l parameter not numeric: did you mean -l 0.0?");
1039  config->max_load_average = value;
1040  break;
1041  }
1042  case 'n':
1043  config->dry_run = true;
1044  break;
1045  case 't':
1046  options->tool = ChooseTool(optarg);
1047  if (!options->tool)
1048  return 0;
1049  break;
1050  case 'v':
1051  config->verbosity = BuildConfig::VERBOSE;
1052  break;
1053  case 'w':
1054  if (!WarningEnable(optarg, options))
1055  return 1;
1056  break;
1057  case 'C':
1058  options->working_dir = optarg;
1059  break;
1060  case OPT_VERSION:
1061  printf("%s\n", kNinjaVersion);
1062  return 0;
1063  case 'h':
1064  default:
1065  Usage(*config);
1066  return 1;
1067  }
1068  }
1069  *argv += optind;
1070  *argc -= optind;
1071 
1072  return -1;
1073 }
1074 
1075 int real_main(int argc, char** argv) {
1076  BuildConfig config;
1077  Options options = {};
1078  options.input_file = "build.ninja";
1079 
1080  setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1081  const char* ninja_command = argv[0];
1082 
1083  int exit_code = ReadFlags(&argc, &argv, &options, &config);
1084  if (exit_code >= 0)
1085  return exit_code;
1086 
1087  if (options.working_dir) {
1088  // The formatting of this string, complete with funny quotes, is
1089  // so Emacs can properly identify that the cwd has changed for
1090  // subsequent commands.
1091  // Don't print this if a tool is being used, so that tool output
1092  // can be piped into a file without this string showing up.
1093  if (!options.tool)
1094  printf("ninja: Entering directory `%s'\n", options.working_dir);
1095  if (chdir(options.working_dir) < 0) {
1096  Fatal("chdir to '%s' - %s", options.working_dir, strerror(errno));
1097  }
1098  }
1099 
1100  if (options.tool && options.tool->when == Tool::RUN_AFTER_FLAGS) {
1101  // None of the RUN_AFTER_FLAGS actually use a NinjaMain, but it's needed
1102  // by other tools.
1103  NinjaMain ninja(ninja_command, config);
1104  return (ninja.*options.tool->func)(argc, argv);
1105  }
1106 
1107  // Limit number of rebuilds, to prevent infinite loops.
1108  const int kCycleLimit = 100;
1109  for (int cycle = 1; cycle <= kCycleLimit; ++cycle) {
1110  NinjaMain ninja(ninja_command, config);
1111 
1112  RealFileReader file_reader;
1113  ManifestParser parser(&ninja.state_, &file_reader,
1114  options.dupe_edges_should_err);
1115  string err;
1116  if (!parser.Load(options.input_file, &err)) {
1117  Error("%s", err.c_str());
1118  return 1;
1119  }
1120 
1121  if (options.tool && options.tool->when == Tool::RUN_AFTER_LOAD)
1122  return (ninja.*options.tool->func)(argc, argv);
1123 
1124  if (!ninja.EnsureBuildDirExists())
1125  return 1;
1126 
1127  if (!ninja.OpenBuildLog() || !ninja.OpenDepsLog())
1128  return 1;
1129 
1130  if (options.tool && options.tool->when == Tool::RUN_AFTER_LOGS)
1131  return (ninja.*options.tool->func)(argc, argv);
1132 
1133  // Attempt to rebuild the manifest before building anything else
1134  if (ninja.RebuildManifest(options.input_file, &err)) {
1135  // Start the build over with the new manifest.
1136  continue;
1137  } else if (!err.empty()) {
1138  Error("rebuilding '%s': %s", options.input_file, err.c_str());
1139  return 1;
1140  }
1141 
1142  int result = ninja.RunBuild(argc, argv);
1143  if (g_metrics)
1144  ninja.DumpMetrics();
1145  return result;
1146  }
1147 
1148  Error("manifest '%s' still dirty after %d tries\n",
1149  options.input_file, kCycleLimit);
1150  return 1;
1151 }
1152 
1153 } // anonymous namespace
1154 
1155 int main(int argc, char** argv) {
1156 #if defined(_MSC_VER)
1157  // Set a handler to catch crashes not caught by the __try..__except
1158  // block (e.g. an exception in a stack-unwind-block).
1159  set_terminate(TerminateHandler);
1160  __try {
1161  // Running inside __try ... __except suppresses any Windows error
1162  // dialogs for errors such as bad_alloc.
1163  return real_main(argc, argv);
1164  }
1165  __except(ExceptionFilter(GetExceptionCode(), GetExceptionInformation())) {
1166  // Common error situations return exitCode=1. 2 was chosen to
1167  // indicate a more serious problem.
1168  return 2;
1169  }
1170 #else
1171  return real_main(argc, argv);
1172 #endif
1173 }
#define no_argument
Definition: getopt.h:7
bool is_phony() const
Definition: graph.cc:342
void Report()
Print a summary report to stdout.
Definition: metrics.cc:101
virtual bool ReadFile(const string &path, string *content, string *err)=0
Verbosity verbosity
Definition: build.h:130
const char * SpellcheckString(const char *text,...)
Like SpellcheckStringV, but takes a NULL-terminated list.
Definition: util.cc:434
vector< Edge * > edges_
All the edges of the graph.
Definition: state.h:124
double max_load_average
The maximum load average we must not exceed.
Definition: build.h:136
int MSVCHelperMain(int argc, char **argv)
StringPiece represents a slice of a string whose memory is managed externally.
Definition: string_piece.h:27
virtual TimeStamp Stat(const string &path, string *err) const
stat() a file, returning the mtime, or 0 if missing and -1 on other errors.
Information about a node in the dependency graph: the file, whether it's dirty, mtime, etc.
Definition: graph.h:35
Edge * in_edge() const
Definition: graph.h:83
Node ** nodes
Definition: deps_log.h:83
string AsString() const
Convert the slice into a full-fledged std::string, copying the data into a new string.
Definition: string_piece.h:45
bool CanonicalizePath(string *path, unsigned int *slash_bits, string *err)
Canonicalize a path like "foo/../bar.h" into just "bar.h".
Definition: util.cc:91
void Dump(const char *prefix="") const
Definition: graph.cc:321
Metrics * g_metrics
Definition: metrics.cc:31
int TimeStamp
Definition: timestamp.h:22
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:124
const char * kNinjaVersion
The version number of the current Ninja release.
Definition: version.cc:21
Store a log of every command ran for every build.
Definition: build_log.h:42
bool g_explaining
Definition: debug_flags.cc:15
string EvaluateCommand(bool incl_rsp_file=false)
Expand all variables in a command and return it as a string.
Definition: graph.cc:292
bool is_order_only(size_t index)
Definition: graph.h:175
virtual bool IsPathDead(StringPiece s) const =0
Return if a given output no longer part of the build manifest.
void RunBrowsePython(State *state, const char *ninja_command, const char *initial_target)
Run in "browse" mode, which execs a Python webserver.
Definition: browse.cc:23
vector< Node * > inputs_
Definition: graph.h:150
As build commands run they can output extra dependency information (e.g.
Definition: deps_log.h:66
Parses .ninja files.
Implementation of DiskInterface that actually hits the disk.
int parallelism
Definition: build.h:132
int failures_allowed
Definition: build.h:133
bool is_implicit(size_t index)
Definition: graph.h:171
int getopt_long(int argc, char **argv, const char *shortopts, const GETOPT_LONG_OPTION_T *longopts, int *longind)
int node_count
Definition: deps_log.h:82
void Finish()
Definition: graphviz.cc:78
void Start()
Definition: graphviz.cc:71
int getopt(int argc, char **argv, char *optstring)
char * optarg
int ReadFile(const string &path, string *contents, string *err)
Read a file to a string (in text mode: with CRLF conversion on Windows).
Definition: util.cc:343
int main(int argc, char **argv)
Definition: ninja.cc:1155
const string & path() const
Definition: graph.h:73
bool g_experimental_statcache
Definition: debug_flags.cc:19
int optind
Builder wraps the build process: starting commands, updating status.
Definition: build.h:140
void Fatal(const char *msg,...)
Log a fatal message and exit.
Definition: util.cc:55
const char * SpellcheckStringV(const string &text, const vector< const char * > &words)
Given a misspelled string and a list of correct spellings, returns the closest match or NULL if there...
Definition: util.cc:415
The singleton that stores metrics and prints the report.
Definition: metrics.h:51
const Rule * rule_
Definition: graph.h:148
Runs the process of creating GraphViz .dot file output.
Definition: graphviz.h:25
bool Stat(DiskInterface *disk_interface, string *err)
Return false on error.
Definition: graph.cc:30
int GetProcessorCount()
Definition: util.cc:500
Options (e.g. verbosity, parallelism) passed to a build.
Definition: build.h:121
Global state (file status) for a single run.
Definition: state.h:84
const string & name() const
Definition: eval_env.h:58
bool g_keep_rsp
Definition: debug_flags.cc:17
void Warning(const char *msg,...)
Log a warning message.
Definition: util.cc:73
Definition: clean.h:30
void AddTarget(Node *node)
Definition: graphviz.cc:22
bool dry_run
Definition: build.h:131
const vector< Edge * > & out_edges() const
Definition: graph.h:89
void Error(const char *msg,...)
Log an error message.
Definition: util.cc:82
Can answer questions about the manifest for the BuildLog.
Definition: build_log.h:29
vector< Node * > outputs_
Definition: graph.h:151