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