summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2011-10-03 03:02:11 (GMT)
committerPeter Collingbourne <peter@pcc.me.uk>2011-11-04 19:10:31 (GMT)
commit4836a864667df3a8c1dd90bb9db7571c6a91e4dc (patch)
treee31a16b42f2607395c429b5e35f9d3fed243412a
parent801377e0651d35a8f006ea3722a44f52cfe787bf (diff)
downloadNinja-4836a864667df3a8c1dd90bb9db7571c6a91e4dc.zip
Ninja-4836a864667df3a8c1dd90bb9db7571c6a91e4dc.tar.gz
Ninja-4836a864667df3a8c1dd90bb9db7571c6a91e4dc.tar.bz2
Add a "commands" tool
This tool performs a post-order traversal of the build graph, starting from a list of targets specified on the command line, and for each build statement encountered, prints the evaluated command line. Use cases include: - Generating input for a tool which needs to know the full command line for every command invoked during a build. Many static analysis and indexing tools require this information. - Generating a build script which does not depend on Ninja. For example, such a script could be used by Ninja to bootstrap itself.
-rw-r--r--doc/manual.asciidoc4
-rw-r--r--src/ninja.cc44
2 files changed, 42 insertions, 6 deletions
diff --git a/doc/manual.asciidoc b/doc/manual.asciidoc
index d59f471..bc15a1f 100644
--- a/doc/manual.asciidoc
+++ b/doc/manual.asciidoc
@@ -382,6 +382,10 @@ than the _depth_ mode. It returns non-zero if an error occurs.
one. It can be used to know which rule name to pass to
+ninja -t targets rule _name_+.
+`commands`:: given a list of targets, print a list of commands which, if
+executed in order, may be used to rebuild those targets, assuming that all
+output files are out of date.
+
`clean`:: remove built files. If used like this +ninja -t clean+ it removes
all the built files, except for those created by the generator. If used
like this +ninja -t clean -g+ it also removes built files created by the
diff --git a/src/ninja.cc b/src/ninja.cc
index a058e95..47693d1 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -65,12 +65,13 @@ void Usage(const BuildConfig& config) {
" -t TOOL run a subtool.\n"
" terminates toplevel options; further flags are passed to the tool.\n"
" 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"
-" targets list targets by their rule or depth in the DAG\n"
-" rules list all rules\n"
-" clean clean built files\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"
+" targets list targets by their rule or depth in the DAG\n"
+" rules list all rules\n"
+" commands list all commands required to rebuild given targets\n"
+" clean clean built files\n",
config.parallelism);
}
@@ -357,6 +358,35 @@ int CmdRules(State* state, int argc, char* argv[]) {
return 0;
}
+void PrintCommands(Edge* edge, set<Edge*>* seen) {
+ if (!edge)
+ return;
+ if (!seen->insert(edge).second)
+ return;
+
+ for (vector<Node*>::iterator in = edge->inputs_.begin();
+ in != edge->inputs_.end(); ++in)
+ PrintCommands((*in)->in_edge_, seen);
+
+ if (!edge->is_phony())
+ puts(edge->EvaluateCommand().c_str());
+}
+
+int CmdCommands(State* state, int argc, char* argv[]) {
+ vector<Node*> nodes;
+ string err;
+ if (!CollectTargetsFromArgs(state, argc, argv, &nodes, &err)) {
+ Error("%s", err.c_str());
+ return 1;
+ }
+
+ set<Edge*> seen;
+ for (vector<Node*>::iterator in = nodes.begin(); in != nodes.end(); ++in)
+ PrintCommands((*in)->in_edge_, &seen);
+
+ return 0;
+}
+
int CmdClean(State* state, int argc, char* argv[], const BuildConfig& config) {
bool generator = false;
bool clean_rules = false;
@@ -489,6 +519,8 @@ reload:
return CmdTargets(&state, argc, argv);
if (tool == "rules")
return CmdRules(&state, argc, argv);
+ if (tool == "commands")
+ return CmdCommands(&state, argc, argv);
// The clean tool uses getopt, and expects argv[0] to contain the name of
// the tool, i.e. "clean".
if (tool == "clean")