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