1 // Copyright 2011 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <sys/types.h>
22 #if defined(__APPLE__) || defined(__FreeBSD__)
23 #include <sys/sysctl.h>
25 #include <sys/sysinfo.h>
38 #include "build_log.h"
40 #include "edit_distance.h"
50 /// Global information passed into subtools.
52 Globals() : state(new State()) {}
57 /// Deletes and recreates state so it is empty.
63 /// Command line used to run Ninja.
64 const char* ninja_command;
65 /// Build configuration (e.g. parallelism).
67 /// Loaded state (rules, nodes). This is a pointer so it can be reset.
71 /// Print usage information.
72 void Usage(const BuildConfig& config) {
74 "usage: ninja [options] [targets...]\n"
76 "if targets are unspecified, builds the 'default' target (see manual).\n"
77 "targets are paths, with additional special syntax:\n"
78 " 'target^' means 'the first output that uses target'.\n"
79 " example: 'ninja foo.cc^' will likely build foo.o.\n"
82 " -C DIR change to DIR before doing anything else\n"
83 " -f FILE specify input build file [default=build.ninja]\n"
85 " -j N run N jobs in parallel [default=%d]\n"
86 " -k N keep going until N jobs fail [default=1]\n"
87 " -n dry run (don't run commands but pretend they succeeded)\n"
88 " -v show all command lines while building\n"
90 " -d MODE enable debugging (use -d list to list modes)\n"
91 " -t TOOL run a subtool\n"
92 " use '-t list' to list subtools.\n"
93 " terminates toplevel options; further flags are passed to the tool.\n",
97 /// Choose a default value for the -j (parallelism) flag.
98 int GuessParallelism() {
102 processors = get_nprocs();
103 #elif defined(__APPLE__) || defined(__FreeBSD__)
104 size_t processors_size = sizeof(processors);
105 int name[] = {CTL_HW, HW_NCPU};
106 if (sysctl(name, sizeof(name) / sizeof(int),
107 &processors, &processors_size,
111 #elif defined(_WIN32)
113 GetSystemInfo(&info);
114 processors = info.dwNumberOfProcessors;
117 switch (processors) {
124 return processors + 2;
128 /// An implementation of ManifestParser::FileReader that actually reads
130 struct RealFileReader : public ManifestParser::FileReader {
131 bool ReadFile(const string& path, string* content, string* err) {
132 return ::ReadFile(path, content, err) == 0;
136 /// Rebuild the build manifest, if necessary.
137 /// Returns true if the manifest was rebuilt.
138 bool RebuildManifest(State* state, const BuildConfig& config,
139 const char* input_file, string* err) {
140 string path = input_file;
141 if (!CanonicalizePath(&path, err))
143 Node* node = state->LookupNode(path);
147 Builder manifest_builder(state, config);
148 if (!manifest_builder.AddTarget(node, err))
151 if (manifest_builder.AlreadyUpToDate())
152 return false; // Not an error, but we didn't rebuild.
153 if (!manifest_builder.Build(err))
156 // The manifest was only rebuilt if it is now dirty (it may have been cleaned
158 return node->dirty();
161 bool CollectTargetsFromArgs(State* state, int argc, char* argv[],
162 vector<Node*>* targets, string* err) {
164 *targets = state->DefaultNodes(err);
168 for (int i = 0; i < argc; ++i) {
169 string path = argv[i];
170 if (!CanonicalizePath(&path, err))
173 // Special syntax: "foo.cc^" means "the first output of foo.cc".
174 bool first_dependent = false;
175 if (!path.empty() && path[path.size() - 1] == '^') {
176 path.resize(path.size() - 1);
177 first_dependent = true;
180 Node* node = state->LookupNode(path);
182 if (first_dependent) {
183 if (node->out_edges().empty()) {
184 *err = "'" + path + "' has no out edge";
187 Edge* edge = node->out_edges()[0];
188 if (edge->outputs_.empty()) {
190 Fatal("edge has no outputs");
192 node = edge->outputs_[0];
194 targets->push_back(node);
196 *err = "unknown target '" + path + "'";
198 Node* suggestion = state->SpellcheckNode(path);
200 *err += ", did you mean '" + suggestion->path() + "'?";
209 int ToolGraph(Globals* globals, int argc, char* argv[]) {
212 if (!CollectTargetsFromArgs(globals->state, argc, argv, &nodes, &err)) {
213 Error("%s", err.c_str());
219 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
226 int ToolQuery(Globals* globals, int argc, char* argv[]) {
228 Error("expected a target to query");
231 for (int i = 0; i < argc; ++i) {
232 Node* node = globals->state->LookupNode(argv[i]);
234 Node* suggestion = globals->state->SpellcheckNode(argv[i]);
236 printf("%s unknown, did you mean %s?\n",
237 argv[i], suggestion->path().c_str());
239 printf("%s unknown\n", argv[i]);
244 printf("%s:\n", argv[i]);
245 if (Edge* edge = node->in_edge()) {
246 printf(" input: %s\n", edge->rule_->name().c_str());
247 for (int in = 0; in < (int)edge->inputs_.size(); in++) {
248 const char* label = "";
249 if (edge->is_implicit(in))
251 else if (edge->is_order_only(in))
253 printf(" %s%s\n", label, edge->inputs_[in]->path().c_str());
256 printf(" outputs:\n");
257 for (vector<Edge*>::const_iterator edge = node->out_edges().begin();
258 edge != node->out_edges().end(); ++edge) {
259 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
260 out != (*edge)->outputs_.end(); ++out) {
261 printf(" %s\n", (*out)->path().c_str());
268 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
269 int ToolBrowse(Globals* globals, int argc, char* argv[]) {
271 Error("expected a target to browse");
274 RunBrowsePython(globals->state, globals->ninja_command, argv[0]);
275 // If we get here, the browse failed.
280 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) {
281 for (vector<Node*>::const_iterator n = nodes.begin();
284 for (int i = 0; i < indent; ++i)
286 const char* target = (*n)->path().c_str();
287 if ((*n)->in_edge()) {
288 printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
289 if (depth > 1 || depth <= 0)
290 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
292 printf("%s\n", target);
298 int ToolTargetsSourceList(State* state) {
299 for (vector<Edge*>::iterator e = state->edges_.begin();
300 e != state->edges_.end(); ++e) {
301 for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
302 inps != (*e)->inputs_.end(); ++inps) {
303 if (!(*inps)->in_edge())
304 printf("%s\n", (*inps)->path().c_str());
310 int ToolTargetsList(State* state, const string& rule_name) {
313 // Gather the outputs.
314 for (vector<Edge*>::iterator e = state->edges_.begin();
315 e != state->edges_.end(); ++e) {
316 if ((*e)->rule_->name() == rule_name) {
317 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
318 out_node != (*e)->outputs_.end(); ++out_node) {
319 rules.insert((*out_node)->path());
325 for (set<string>::const_iterator i = rules.begin();
326 i != rules.end(); ++i) {
327 printf("%s\n", (*i).c_str());
333 int ToolTargetsList(State* state) {
334 for (vector<Edge*>::iterator e = state->edges_.begin();
335 e != state->edges_.end(); ++e) {
336 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
337 out_node != (*e)->outputs_.end(); ++out_node) {
339 (*out_node)->path().c_str(),
340 (*e)->rule_->name().c_str());
346 int ToolTargets(Globals* globals, int argc, char* argv[]) {
349 string mode = argv[0];
350 if (mode == "rule") {
355 return ToolTargetsSourceList(globals->state);
357 return ToolTargetsList(globals->state, rule);
358 } else if (mode == "depth") {
360 depth = atoi(argv[1]);
361 } else if (mode == "all") {
362 return ToolTargetsList(globals->state);
364 const char* suggestion =
365 SpellcheckString(mode, "rule", "depth", "all", NULL);
367 Error("unknown target tool mode '%s', did you mean '%s'?",
368 mode.c_str(), suggestion);
370 Error("unknown target tool mode '%s'", mode.c_str());
377 vector<Node*> root_nodes = globals->state->RootNodes(&err);
379 return ToolTargetsList(root_nodes, depth, 0);
381 Error("%s", err.c_str());
386 int ToolRules(Globals* globals, int argc, char* /* argv */[]) {
387 for (map<string, const Rule*>::iterator i = globals->state->rules_.begin();
388 i != globals->state->rules_.end(); ++i) {
389 if (i->second->description().empty()) {
390 printf("%s\n", i->first.c_str());
394 // XXX I changed it such that we don't have an easy way
395 // to get the source text anymore, so this output is
396 // unsatisfactory. How useful is this command, anyway?
397 i->second->description().Serialize().c_str());
403 void PrintCommands(Edge* edge, set<Edge*>* seen) {
406 if (!seen->insert(edge).second)
409 for (vector<Node*>::iterator in = edge->inputs_.begin();
410 in != edge->inputs_.end(); ++in)
411 PrintCommands((*in)->in_edge(), seen);
413 if (!edge->is_phony())
414 puts(edge->EvaluateCommand().c_str());
417 int ToolCommands(Globals* globals, int argc, char* argv[]) {
420 if (!CollectTargetsFromArgs(globals->state, argc, argv, &nodes, &err)) {
421 Error("%s", err.c_str());
426 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
427 PrintCommands((*in)->in_edge(), &seen);
432 int ToolClean(Globals* globals, int argc, char* argv[]) {
433 // The clean tool uses getopt, and expects argv[0] to contain the name of
434 // the tool, i.e. "clean".
438 bool generator = false;
439 bool clean_rules = false;
443 while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) {
453 printf("usage: ninja -t clean [options] [targets]\n"
456 " -g also clean files marked as ninja generator output\n"
457 " -r interpret targets as a list of rules to clean instead\n"
465 if (clean_rules && argc == 0) {
466 Error("expected a rule to clean");
470 Cleaner cleaner(globals->state, globals->config);
473 return cleaner.CleanRules(argc, argv);
475 return cleaner.CleanTargets(argc, argv);
477 return cleaner.CleanAll(generator);
484 " 13 ,3;2!2;\n8 ,;<11!;\n5 `'<10!(2`'2!\n11 ,6;, `\\. `\\9 .,c13$ec,.\n6 "
485 ",2;11!>; `. ,;!2> .e8$2\".2 \"?7$e.\n <:<8!'` 2.3,.2` ,3!' ;,(?7\";2!2'<"
486 "; `?6$PF ,;,\n2 `'4!8;<!3'`2 3! ;,`'2`2'3!;4!`2.`!;2 3,2 .<!2'`).\n5 3`5"
487 "'2`9 `!2 `4!><3;5! J2$b,`!>;2!:2!`,d?b`!>\n26 `'-;,(<9!> $F3 )3.:!.2 d\""
488 "2 ) !>\n30 7`2'<3!- \"=-='5 .2 `2-=\",!>\n25 .ze9$er2 .,cd16$bc.'\n22 .e"
489 "14$,26$.\n21 z45$c .\n20 J50$c\n20 14$P\"`?34$b\n20 14$ dbc `2\"?22$?7$c"
490 "\n20 ?18$c.6 4\"8?4\" c8$P\n9 .2,.8 \"20$c.3 ._14 J9$\n .2,2c9$bec,.2 `?"
491 "21$c.3`4%,3%,3 c8$P\"\n22$c2 2\"?21$bc2,.2` .2,c7$P2\",cb\n23$b bc,.2\"2"
492 "?14$2F2\"5?2\",J5$P\" ,zd3$\n24$ ?$3?%3 `2\"2?12$bcucd3$P3\"2 2=7$\n23$P"
493 "\" ,3;<5!>2;,. `4\"6?2\"2 ,9;, `\"?2$\n19$P2\",;23!6;17!;2 \"\n";
495 for (const char* p = urtle; *p; p++) {
496 if ('0' <= *p && *p <= '9') {
497 count = count*10 + *p - '0';
499 for (int i = 0; i < std::max(count, 1); ++i)
506 int RunTool(const string& tool, Globals* globals, int argc, char** argv) {
507 typedef int (*ToolFunc)(Globals*, int, char**);
513 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
514 { "browse", "browse dependency graph in a web browser",
517 { "clean", "clean built files",
519 { "commands", "list all commands required to rebuild given targets",
521 { "graph", "output graphviz dot file for targets",
523 { "query", "show inputs/outputs for a path",
525 { "rules", "list all rules",
527 { "targets", "list targets by their rule or depth in the DAG",
532 if (tool == "list") {
533 printf("ninja subtools:\n");
534 for (int i = 0; tools[i].name; ++i) {
535 printf("%10s %s\n", tools[i].name, tools[i].desc);
538 } else if (tool == "urtle") {
543 for (int i = 0; tools[i].name; ++i) {
544 if (tool == tools[i].name)
545 return tools[i].func(globals, argc, argv);
548 vector<const char*> words;
549 for (int i = 0; tools[i].name; ++i)
550 words.push_back(tools[i].name);
551 const char* suggestion = SpellcheckStringV(tool, words);
553 Error("unknown tool '%s', did you mean '%s'?", tool.c_str(), suggestion);
555 Error("unknown tool '%s'", tool.c_str());
560 /// Enable a debugging mode. Returns false if Ninja should exit instead
562 bool DebugEnable(const string& name, Globals* globals) {
563 if (name == "list") {
564 printf("debugging modes:\n"
565 " stats print operation counts/timing info\n");
566 //"multiple modes can be enabled via -d FOO -d BAR\n");
568 } else if (name == "stats") {
569 g_metrics = new Metrics;
572 printf("ninja: unknown debug setting '%s'\n", name.c_str());
577 int RunBuild(Globals* globals, int argc, char** argv) {
579 vector<Node*> targets;
580 if (!CollectTargetsFromArgs(globals->state, argc, argv, &targets, &err)) {
581 Error("%s", err.c_str());
585 Builder builder(globals->state, globals->config);
586 for (size_t i = 0; i < targets.size(); ++i) {
587 if (!builder.AddTarget(targets[i], &err)) {
589 Error("%s", err.c_str());
592 // Added a target that is already up-to-date; not really
598 if (builder.AlreadyUpToDate()) {
599 printf("ninja: no work to do.\n");
603 if (!builder.Build(&err)) {
604 printf("ninja: build stopped: %s.\n", err.c_str());
611 } // anonymous namespace
613 int main(int argc, char** argv) {
615 globals.ninja_command = argv[0];
616 const char* input_file = "build.ninja";
617 const char* working_dir = NULL;
620 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
622 globals.config.parallelism = GuessParallelism();
624 const option kLongOptions[] = {
625 { "help", no_argument, NULL, 'h' },
630 while (tool.empty() &&
631 (opt = getopt_long(argc, argv, "d:f:hj:k:nt:vC:", kLongOptions,
635 if (!DebugEnable(optarg, &globals))
642 globals.config.parallelism = atoi(optarg);
646 int value = strtol(optarg, &end, 10);
648 Fatal("-k parameter not numeric; did you mean -k0?");
650 // We want to go until N jobs fail, which means we should allow
651 // N failures and then stop. For N <= 0, INT_MAX is close enough
652 // to infinite for most sane builds.
653 globals.config.failures_allowed = value > 0 ? value : INT_MAX;
657 globals.config.dry_run = true;
660 globals.config.verbosity = BuildConfig::VERBOSE;
666 working_dir = optarg;
670 Usage(globals.config);
678 // The formatting of this string, complete with funny quotes, is
679 // so Emacs can properly identify that the cwd has changed for
680 // subsequent commands.
681 printf("ninja: Entering directory `%s'\n", working_dir);
683 if (_chdir(working_dir) < 0) {
685 if (chdir(working_dir) < 0) {
687 Fatal("chdir to '%s' - %s", working_dir, strerror(errno));
691 bool rebuilt_manifest = false;
694 RealFileReader file_reader;
695 ManifestParser parser(globals.state, &file_reader);
697 if (!parser.Load(input_file, &err)) {
698 Error("%s", err.c_str());
703 return RunTool(tool, &globals, argc, argv);
706 build_log.SetConfig(&globals.config);
707 globals.state->build_log_ = &build_log;
709 const string build_dir = globals.state->bindings_.LookupVariable("builddir");
710 const char* kLogPath = ".ninja_log";
711 string log_path = kLogPath;
712 if (!build_dir.empty()) {
713 if (MakeDir(build_dir) < 0 && errno != EEXIST) {
714 Error("creating build directory %s: %s",
715 build_dir.c_str(), strerror(errno));
718 log_path = build_dir + "/" + kLogPath;
721 if (!build_log.Load(log_path.c_str(), &err)) {
722 Error("loading build log %s: %s",
723 log_path.c_str(), err.c_str());
727 if (!build_log.OpenForWrite(log_path.c_str(), &err)) {
728 Error("opening build log: %s", err.c_str());
732 if (!rebuilt_manifest) { // Don't get caught in an infinite loop by a rebuild
733 // target that is never up to date.
734 if (RebuildManifest(globals.state, globals.config, input_file, &err)) {
735 rebuilt_manifest = true;
736 globals.ResetState();
738 } else if (!err.empty()) {
739 Error("rebuilding '%s': %s", input_file, err.c_str());
744 int result = RunBuild(&globals, argc, argv);
749 int count = (int)globals.state->paths_.size();
752 (int)globals.state->paths_.comp.bucket_size;
754 (int)globals.state->paths_.bucket_count();
756 printf("path->node hash load %.2f (%d entries / %d buckets)\n",
757 count / (double) buckets, count, buckets);