diff options
Diffstat (limited to 'src/ninja.cc')
-rw-r--r-- | src/ninja.cc | 170 |
1 files changed, 168 insertions, 2 deletions
diff --git a/src/ninja.cc b/src/ninja.cc index 6359aaf..5a0c00d 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -38,6 +38,7 @@ #include "graphviz.h" #include "parsers.h" #include "util.h" +#include "clean.h" option options[] = { { "help", no_argument, NULL, 'h' }, @@ -53,11 +54,15 @@ void usage(const BuildConfig& config) { " -j N run N jobs in parallel [default=%d]\n" " -n dry run (don't run commands but pretend they succeeded)\n" " -v show all command lines\n" +" -C DIR change to DIR before doing anything else\n" "\n" " -t TOOL run a subtool. tools are:\n" " browse browse dependency graph in a web browser\n" " graph output graphviz dot file for targets\n" -" query show inputs/outputs for a path\n", +" query show inputs/outputs for a path\n" +" targets list targets by their rule or depth in the DAG\n" +" rules list all rules\n" +" clean clean built files\n", config.parallelism); } @@ -160,15 +165,161 @@ int CmdBrowse(State* state, int argc, char* argv[]) { return 1; } +int CmdTargetsList(const vector<Node*>& nodes, int depth, int indent) { + for (vector<Node*>::const_iterator n = nodes.begin(); + n != nodes.end(); + ++n) { + for (int i = 0; i < indent; ++i) + printf(" "); + const char* target = (*n)->file_->path_.c_str(); + if ((*n)->in_edge_) { + printf("%s: %s\n", target, (*n)->in_edge_->rule_->name_.c_str()); + if (depth > 1 || depth <= 0) + CmdTargetsList((*n)->in_edge_->inputs_, depth - 1, indent + 1); + } else { + printf("%s\n", target); + } + } + return 0; +} + +int CmdTargetsList(const vector<Node*>& nodes, int depth) { + return CmdTargetsList(nodes, depth, 0); +} + +int CmdTargetsSourceList(State* state) { + for (vector<Edge*>::iterator e = state->edges_.begin(); + e != state->edges_.end(); + ++e) + for (vector<Node*>::iterator inps = (*e)->inputs_.begin(); + inps != (*e)->inputs_.end(); + ++inps) + if (!(*inps)->in_edge_) + printf("%s\n", (*inps)->file_->path_.c_str()); + return 0; +} + +int CmdTargetsList(State* state, const string& rule_name) { + set<string> rules; + // Gather the outputs. + for (vector<Edge*>::iterator e = state->edges_.begin(); + e != state->edges_.end(); + ++e) + if ((*e)->rule_->name_ == rule_name) + for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); + out_node != (*e)->outputs_.end(); + ++out_node) + rules.insert((*out_node)->file_->path_); + // Print them. + for (set<string>::const_iterator i = rules.begin(); + i != rules.end(); + ++i) + printf("%s\n", (*i).c_str()); + return 0; +} + +int CmdTargetsList(State* state) { + for (vector<Edge*>::iterator e = state->edges_.begin(); + e != state->edges_.end(); + ++e) + for (vector<Node*>::iterator out_node = (*e)->outputs_.begin(); + out_node != (*e)->outputs_.end(); + ++out_node) + printf("%s: %s\n", + (*out_node)->file_->path_.c_str(), + (*e)->rule_->name_.c_str()); + return 0; +} + +int CmdTargets(State* state, int argc, char* argv[]) { + int depth = 1; + if (argc >= 1) { + string mode = argv[0]; + if (mode == "rule") { + string rule; + if (argc > 1) + rule = argv[1]; + if (rule.empty()) + return CmdTargetsSourceList(state); + else + return CmdTargetsList(state, rule); + } else if (mode == "depth") { + if (argc > 1) + depth = atoi(argv[1]); + } else if (mode == "all") { + return CmdTargetsList(state); + } else { + Error("unknown target tool mode '%s'", mode.c_str()); + return 1; + } + } + + string err; + vector<Node*> root_nodes = state->RootNodes(&err); + if (err.empty()) { + return CmdTargetsList(root_nodes, depth); + } else { + Error("%s", err.c_str()); + return 1; + } +} + +int CmdRules(State* state, int argc, char* argv[]) { + for (map<string, const Rule*>::iterator i = state->rules_.begin(); + i != state->rules_.end(); + ++i) { + if (i->second->description_.unparsed_.empty()) + printf("%s\n", i->first.c_str()); + else + printf("%s: %s\n", + i->first.c_str(), + i->second->description_.unparsed_.c_str()); + } + return 0; +} + +int CmdClean(State* state, + int argc, + char* argv[], + const BuildConfig& config) { + Cleaner cleaner(state, config); + if (argc >= 1) + { + string mode = argv[0]; + if (mode == "target") { + if (argc >= 2) { + return cleaner.CleanTargets(argc - 1, &argv[1]); + } else { + Error("expected a target to clean"); + return 1; + } + } else if (mode == "rule") { + if (argc >= 2) { + return cleaner.CleanRules(argc - 1, &argv[1]); + } else { + Error("expected a rule to clean"); + return 1; + } + } else { + return cleaner.CleanTargets(argc, argv); + } + } + else { + cleaner.CleanAll(); + return 0; + } +} + int main(int argc, char** argv) { BuildConfig config; const char* input_file = "build.ninja"; + const char* working_dir = 0; string tool; config.parallelism = GuessParallelism(); int opt; - while ((opt = getopt_long(argc, argv, "f:hj:nt:v", options, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "f:hj:nt:vC:", options, NULL)) != -1) { switch (opt) { case 'f': input_file = optarg; @@ -185,6 +336,9 @@ int main(int argc, char** argv) { case 't': tool = optarg; break; + case 'C': + working_dir = optarg; + break; case 'h': default: usage(config); @@ -199,6 +353,12 @@ int main(int argc, char** argv) { argv += optind; argc -= optind; + if (working_dir) { + if (chdir(working_dir) < 0) { + Fatal("chdir to '%s' - %s", working_dir, strerror(errno)); + } + } + State state; RealFileReader file_reader; ManifestParser parser(&state, &file_reader); @@ -215,6 +375,12 @@ int main(int argc, char** argv) { return CmdQuery(&state, argc, argv); if (tool == "browse") return CmdBrowse(&state, argc, argv); + if (tool == "targets") + return CmdTargets(&state, argc, argv); + if (tool == "rules") + return CmdRules(&state, argc, argv); + if (tool == "clean") + return CmdClean(&state, argc, argv, config); Error("unknown tool '%s'", tool.c_str()); } |