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