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