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