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.
19 #include <sys/types.h>
21 #if defined(__APPLE__) || defined(__FreeBSD__)
22 #include <sys/sysctl.h>
24 #include <sys/sysinfo.h>
37 #include "build_log.h"
39 #include "edit_distance.h"
49 /// Global information passed into subtools.
51 Globals() : state(new State()) {}
56 /// Deletes and recreates state so it is empty.
62 /// Command line used to run Ninja.
63 const char* ninja_command;
64 /// Build configuration (e.g. parallelism).
66 /// Loaded state (rules, nodes). This is a pointer so it can be reset.
70 /// Print usage information.
71 void Usage(const BuildConfig& config) {
73 "usage: ninja [options] [targets...]\n"
75 "if targets are unspecified, builds the 'default' target (see manual).\n"
76 "targets are paths, with additional special syntax:\n"
77 " 'target^' means 'the first output that uses target'.\n"
78 " example: 'ninja foo.cc^' will likely build foo.o.\n"
81 " -C DIR change to DIR before doing anything else\n"
82 " -f FILE specify input build file [default=build.ninja]\n"
84 " -j N run N jobs in parallel [default=%d]\n"
85 " -k N keep going until N jobs fail [default=1]\n"
86 " -n dry run (don't run commands but pretend they succeeded)\n"
87 " -v show all command lines while building\n"
89 " -d MODE enable debugging (use -d list to list modes)\n"
90 " -t TOOL run a subtool\n"
91 " use '-t list' to list subtools.\n"
92 " terminates toplevel options; further flags are passed to the tool.\n",
96 /// Choose a default value for the -j (parallelism) flag.
97 int GuessParallelism() {
101 processors = get_nprocs();
102 #elif defined(__APPLE__) || defined(__FreeBSD__)
103 size_t processors_size = sizeof(processors);
104 int name[] = {CTL_HW, HW_NCPU};
105 if (sysctl(name, sizeof(name) / sizeof(int),
106 &processors, &processors_size,
110 #elif defined(_WIN32)
112 GetSystemInfo(&info);
113 processors = info.dwNumberOfProcessors;
116 switch (processors) {
123 return processors + 2;
127 /// An implementation of ManifestParser::FileReader that actually reads
129 struct RealFileReader : public ManifestParser::FileReader {
130 bool ReadFile(const string& path, string* content, string* err) {
131 return ::ReadFile(path, content, err) == 0;
135 /// Rebuild the build manifest, if necessary.
136 /// Returns true if the manifest was rebuilt.
137 bool RebuildManifest(State* state, const BuildConfig& config,
138 const char* input_file, string* err) {
139 string path = input_file;
140 if (!CanonicalizePath(&path, err))
142 Node* node = state->LookupNode(path);
146 Builder manifest_builder(state, config);
147 if (!manifest_builder.AddTarget(node, err))
150 if (manifest_builder.AlreadyUpToDate())
151 return false; // Not an error, but we didn't rebuild.
152 return manifest_builder.Build(err);
155 bool CollectTargetsFromArgs(State* state, int argc, char* argv[],
156 vector<Node*>* targets, string* err) {
158 *targets = state->DefaultNodes(err);
162 for (int i = 0; i < argc; ++i) {
163 string path = argv[i];
164 if (!CanonicalizePath(&path, err))
167 // Special syntax: "foo.cc^" means "the first output of foo.cc".
168 bool first_dependent = false;
169 if (!path.empty() && path[path.size() - 1] == '^') {
170 path.resize(path.size() - 1);
171 first_dependent = true;
174 Node* node = state->LookupNode(path);
176 if (first_dependent) {
177 if (node->out_edges().empty()) {
178 *err = "'" + path + "' has no out edge";
181 Edge* edge = node->out_edges()[0];
182 if (edge->outputs_.empty()) {
184 Fatal("edge has no outputs");
186 node = edge->outputs_[0];
188 targets->push_back(node);
190 *err = "unknown target '" + path + "'";
192 Node* suggestion = state->SpellcheckNode(path);
194 *err += ", did you mean '" + suggestion->path() + "'?";
203 int ToolGraph(Globals* globals, int argc, char* argv[]) {
206 if (!CollectTargetsFromArgs(globals->state, argc, argv, &nodes, &err)) {
207 Error("%s", err.c_str());
213 for (vector<Node*>::const_iterator n = nodes.begin(); n != nodes.end(); ++n)
220 int ToolQuery(Globals* globals, int argc, char* argv[]) {
222 Error("expected a target to query");
225 for (int i = 0; i < argc; ++i) {
226 Node* node = globals->state->LookupNode(argv[i]);
228 printf("%s:\n", argv[i]);
229 if (node->in_edge()) {
230 printf(" input: %s\n", node->in_edge()->rule_->name().c_str());
231 for (vector<Node*>::iterator in = node->in_edge()->inputs_.begin();
232 in != node->in_edge()->inputs_.end(); ++in) {
233 printf(" %s\n", (*in)->path().c_str());
236 for (vector<Edge*>::const_iterator edge = node->out_edges().begin();
237 edge != node->out_edges().end(); ++edge) {
238 printf(" output: %s\n", (*edge)->rule_->name().c_str());
239 for (vector<Node*>::iterator out = (*edge)->outputs_.begin();
240 out != (*edge)->outputs_.end(); ++out) {
241 printf(" %s\n", (*out)->path().c_str());
245 Node* suggestion = globals->state->SpellcheckNode(argv[i]);
247 printf("%s unknown, did you mean %s?\n",
248 argv[i], suggestion->path().c_str());
250 printf("%s unknown\n", argv[i]);
258 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
259 int ToolBrowse(Globals* globals, int argc, char* argv[]) {
261 Error("expected a target to browse");
264 RunBrowsePython(globals->state, globals->ninja_command, argv[0]);
265 // If we get here, the browse failed.
270 int ToolTargetsList(const vector<Node*>& nodes, int depth, int indent) {
271 for (vector<Node*>::const_iterator n = nodes.begin();
274 for (int i = 0; i < indent; ++i)
276 const char* target = (*n)->path().c_str();
277 if ((*n)->in_edge()) {
278 printf("%s: %s\n", target, (*n)->in_edge()->rule_->name().c_str());
279 if (depth > 1 || depth <= 0)
280 ToolTargetsList((*n)->in_edge()->inputs_, depth - 1, indent + 1);
282 printf("%s\n", target);
288 int ToolTargetsSourceList(State* state) {
289 for (vector<Edge*>::iterator e = state->edges_.begin();
290 e != state->edges_.end(); ++e) {
291 for (vector<Node*>::iterator inps = (*e)->inputs_.begin();
292 inps != (*e)->inputs_.end(); ++inps) {
293 if (!(*inps)->in_edge())
294 printf("%s\n", (*inps)->path().c_str());
300 int ToolTargetsList(State* state, const string& rule_name) {
303 // Gather the outputs.
304 for (vector<Edge*>::iterator e = state->edges_.begin();
305 e != state->edges_.end(); ++e) {
306 if ((*e)->rule_->name() == rule_name) {
307 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
308 out_node != (*e)->outputs_.end(); ++out_node) {
309 rules.insert((*out_node)->path());
315 for (set<string>::const_iterator i = rules.begin();
316 i != rules.end(); ++i) {
317 printf("%s\n", (*i).c_str());
323 int ToolTargetsList(State* state) {
324 for (vector<Edge*>::iterator e = state->edges_.begin();
325 e != state->edges_.end(); ++e) {
326 for (vector<Node*>::iterator out_node = (*e)->outputs_.begin();
327 out_node != (*e)->outputs_.end(); ++out_node) {
329 (*out_node)->path().c_str(),
330 (*e)->rule_->name().c_str());
336 int ToolTargets(Globals* globals, int argc, char* argv[]) {
339 string mode = argv[0];
340 if (mode == "rule") {
345 return ToolTargetsSourceList(globals->state);
347 return ToolTargetsList(globals->state, rule);
348 } else if (mode == "depth") {
350 depth = atoi(argv[1]);
351 } else if (mode == "all") {
352 return ToolTargetsList(globals->state);
354 const char* suggestion =
355 SpellcheckString(mode, "rule", "depth", "all", NULL);
357 Error("unknown target tool mode '%s', did you mean '%s'?",
358 mode.c_str(), suggestion);
360 Error("unknown target tool mode '%s'", mode.c_str());
367 vector<Node*> root_nodes = globals->state->RootNodes(&err);
369 return ToolTargetsList(root_nodes, depth, 0);
371 Error("%s", err.c_str());
376 int ToolRules(Globals* globals, int argc, char* /* argv */[]) {
377 for (map<string, const Rule*>::iterator i = globals->state->rules_.begin();
378 i != globals->state->rules_.end(); ++i) {
379 if (i->second->description().empty()) {
380 printf("%s\n", i->first.c_str());
384 // XXX I changed it such that we don't have an easy way
385 // to get the source text anymore, so this output is
386 // unsatisfactory. How useful is this command, anyway?
387 i->second->description().Serialize().c_str());
393 void PrintCommands(Edge* edge, set<Edge*>* seen) {
396 if (!seen->insert(edge).second)
399 for (vector<Node*>::iterator in = edge->inputs_.begin();
400 in != edge->inputs_.end(); ++in)
401 PrintCommands((*in)->in_edge(), seen);
403 if (!edge->is_phony())
404 puts(edge->EvaluateCommand().c_str());
407 int ToolCommands(Globals* globals, int argc, char* argv[]) {
410 if (!CollectTargetsFromArgs(globals->state, argc, argv, &nodes, &err)) {
411 Error("%s", err.c_str());
416 for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
417 PrintCommands((*in)->in_edge(), &seen);
422 int ToolClean(Globals* globals, int argc, char* argv[]) {
423 // The clean tool uses getopt, and expects argv[0] to contain the name of
424 // the tool, i.e. "clean".
428 bool generator = false;
429 bool clean_rules = false;
433 while ((opt = getopt(argc, argv, const_cast<char*>("hgr"))) != -1) {
443 printf("usage: ninja -t clean [options] [targets]\n"
446 " -g also clean files marked as ninja generator output\n"
447 " -r interpret targets as a list of rules to clean instead\n"
455 if (clean_rules && argc == 0) {
456 Error("expected a rule to clean");
460 Cleaner cleaner(globals->state, globals->config);
463 return cleaner.CleanRules(argc, argv);
465 return cleaner.CleanTargets(argc, argv);
467 return cleaner.CleanAll(generator);
471 int RunTool(const string& tool, Globals* globals, int argc, char** argv) {
472 typedef int (*ToolFunc)(Globals*, int, char**);
478 #if !defined(_WIN32) && !defined(NINJA_BOOTSTRAP)
479 { "browse", "browse dependency graph in a web browser",
482 { "clean", "clean built files",
484 { "commands", "list all commands required to rebuild given targets",
486 { "graph", "output graphviz dot file for targets",
488 { "query", "show inputs/outputs for a path",
490 { "rules", "list all rules",
492 { "targets", "list targets by their rule or depth in the DAG",
497 if (tool == "list") {
498 printf("ninja subtools:\n");
499 for (int i = 0; tools[i].name; ++i) {
500 printf("%10s %s\n", tools[i].name, tools[i].desc);
505 for (int i = 0; tools[i].name; ++i) {
506 if (tool == tools[i].name)
507 return tools[i].func(globals, argc, argv);
510 vector<const char*> words;
511 for (int i = 0; tools[i].name; ++i)
512 words.push_back(tools[i].name);
513 const char* suggestion = SpellcheckStringV(tool, words);
515 Error("unknown tool '%s', did you mean '%s'?", tool.c_str(), suggestion);
517 Error("unknown tool '%s'", tool.c_str());
522 /// Enable a debugging mode. Returns false if Ninja should exit instead
524 bool DebugEnable(const string& name, Globals* globals) {
525 if (name == "list") {
526 printf("debugging modes:\n"
527 " stats print operation counts/timing info\n");
528 //"multiple modes can be enabled via -d FOO -d BAR\n");
530 } else if (name == "stats") {
531 g_metrics = new Metrics;
534 printf("ninja: unknown debug setting '%s'\n", name.c_str());
539 int RunBuild(Globals* globals, int argc, char** argv) {
541 vector<Node*> targets;
542 if (!CollectTargetsFromArgs(globals->state, argc, argv, &targets, &err)) {
543 Error("%s", err.c_str());
547 Builder builder(globals->state, globals->config);
548 for (size_t i = 0; i < targets.size(); ++i) {
549 if (!builder.AddTarget(targets[i], &err)) {
551 Error("%s", err.c_str());
554 // Added a target that is already up-to-date; not really
560 if (builder.AlreadyUpToDate()) {
561 printf("ninja: no work to do.\n");
565 if (!builder.Build(&err)) {
566 printf("ninja: build stopped: %s.\n", err.c_str());
573 } // anonymous namespace
575 int main(int argc, char** argv) {
577 globals.ninja_command = argv[0];
578 const char* input_file = "build.ninja";
579 const char* working_dir = NULL;
582 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
584 globals.config.parallelism = GuessParallelism();
586 const option kLongOptions[] = {
587 { "help", no_argument, NULL, 'h' },
592 while (tool.empty() &&
593 (opt = getopt_long(argc, argv, "d:f:hj:k:nt:vC:", kLongOptions,
597 if (!DebugEnable(optarg, &globals))
604 globals.config.parallelism = atoi(optarg);
608 int value = strtol(optarg, &end, 10);
610 Fatal("-k parameter not numeric; did you mean -k0?");
612 // We want to go until N jobs fail, which means we should ignore
613 // the first N-1 that fail and then stop.
614 globals.config.swallow_failures = value - 1;
618 globals.config.dry_run = true;
621 globals.config.verbosity = BuildConfig::VERBOSE;
627 working_dir = optarg;
631 Usage(globals.config);
639 // The formatting of this string, complete with funny quotes, is
640 // so Emacs can properly identify that the cwd has changed for
641 // subsequent commands.
642 printf("ninja: Entering directory `%s'\n", working_dir);
644 if (_chdir(working_dir) < 0) {
646 if (chdir(working_dir) < 0) {
648 Fatal("chdir to '%s' - %s", working_dir, strerror(errno));
652 bool rebuilt_manifest = false;
655 RealFileReader file_reader;
656 ManifestParser parser(globals.state, &file_reader);
658 if (!parser.Load(input_file, &err)) {
659 Error("%s", err.c_str());
664 return RunTool(tool, &globals, argc, argv);
667 build_log.SetConfig(&globals.config);
668 globals.state->build_log_ = &build_log;
670 const string build_dir = globals.state->bindings_.LookupVariable("builddir");
671 const char* kLogPath = ".ninja_log";
672 string log_path = kLogPath;
673 if (!build_dir.empty()) {
674 if (MakeDir(build_dir) < 0 && errno != EEXIST) {
675 Error("creating build directory %s: %s",
676 build_dir.c_str(), strerror(errno));
679 log_path = build_dir + "/" + kLogPath;
682 if (!build_log.Load(log_path.c_str(), &err)) {
683 Error("loading build log %s: %s",
684 log_path.c_str(), err.c_str());
688 if (!build_log.OpenForWrite(log_path.c_str(), &err)) {
689 Error("opening build log: %s", err.c_str());
693 if (!rebuilt_manifest) { // Don't get caught in an infinite loop by a rebuild
694 // target that is never up to date.
695 if (RebuildManifest(globals.state, globals.config, input_file, &err)) {
696 rebuilt_manifest = true;
697 globals.ResetState();
699 } else if (!err.empty()) {
700 Error("rebuilding '%s': %s", input_file, err.c_str());
705 int result = RunBuild(&globals, argc, argv);
710 int count = (int)globals.state->paths_.size();
713 (int)globals.state->paths_.comp.bucket_size;
715 (int)globals.state->paths_.bucket_count();
717 printf("path->node hash load %.2f (%d entries / %d buckets)\n",
718 count / (double) buckets, count, buckets);