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