summaryrefslogtreecommitdiffstats
path: root/src/ninja.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninja.cc')
-rw-r--r--src/ninja.cc170
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());
}