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