Merge "Add a debug tool to show all (recursive) inputs to a given target."
diff --git a/src/graph.h b/src/graph.h
index 4559027..5c8ea8a 100644
--- a/src/graph.h
+++ b/src/graph.h
@@ -202,6 +202,10 @@
void Dump(const char* prefix="") const;
+ // Used in the inputs debug tool.
+ bool InputsChecked() const { return inputs_checked_; }
+ void MarkInputsChecked() { inputs_checked_ = true; }
+
private:
const HashedStr path_;
@@ -243,6 +247,10 @@
std::atomic<EdgeList*> out_edges_ { nullptr };
std::vector<Edge*> dep_scan_out_edges_;
+
+ /// Stores if this node's inputs have been already computed. Used in the
+ /// inputs debug tool.
+ bool inputs_checked_ = false;
};
struct EdgeEval {
diff --git a/src/ninja.cc b/src/ninja.cc
index eae093c..c84342d 100644
--- a/src/ninja.cc
+++ b/src/ninja.cc
@@ -127,6 +127,7 @@
// The various subcommands, run via "-t XXX".
int ToolGraph(const Options* options, int argc, char* argv[]);
int ToolPath(const Options* options, int argc, char* argv[]);
+ int ToolInputs(const Options* options, int argc, char* argv[]);
int ToolQuery(const Options* options, int argc, char* argv[]);
int ToolDeps(const Options* options, int argc, char* argv[]);
int ToolBrowse(const Options* options, int argc, char* argv[]);
@@ -412,6 +413,104 @@
return 1;
}
+void ToolInputsProcessNodeDeps(Node* node, DepsLog* deps_log, bool leaf_only,
+ bool include_deps);
+
+void ToolInputsProcessNode(Node* input, DepsLog* deps_log, bool leaf_only,
+ bool include_deps) {
+ if (input->InputsChecked()) return;
+ input->MarkInputsChecked();
+
+ // Recursively process input edges, possibly printing this node here.
+ Edge* input_edge = input->in_edge();
+ if (input_edge == nullptr || !leaf_only) {
+ printf("%s\n", input->path().c_str());
+ }
+ if (input_edge) {
+ for (Node* input : input_edge->inputs_) {
+ ToolInputsProcessNode(input, deps_log, leaf_only, include_deps);
+ }
+ if (include_deps && input_edge->outputs_.size() > 0) {
+ // Check deps on the input edge's first output because deps log entries
+ // are only stored on the first output of an edge.
+ ToolInputsProcessNodeDeps(input_edge->outputs_[0], deps_log, leaf_only,
+ include_deps);
+ }
+ }
+}
+
+void ToolInputsProcessNodeDeps(Node* node, DepsLog* deps_log, bool leaf_only,
+ bool include_deps) {
+ // Print all of this node's deps from the deps log. This often includes files
+ // that are not known by the node's input edge.
+ if (deps_log->IsDepsEntryLiveFor(node)) {
+ if (DepsLog::Deps* deps = deps_log->GetDeps(node); deps != nullptr) {
+ for (int i = 0; i < deps->node_count; ++i) {
+ if (Node* dep = deps->nodes[i]; dep != nullptr) {
+ ToolInputsProcessNode(dep, deps_log, leaf_only, include_deps);
+ }
+ }
+ }
+ }
+}
+
+int NinjaMain::ToolInputs(const Options* options, int argc, char* argv[]) {
+ // The inputs tool uses getopt, and expects argv[0] to contain the name of
+ // the tool, i.e. "inputs".
+ ++argc;
+ --argv;
+
+ bool leaf_only = true;
+ bool include_deps = false;
+
+ optind = 1;
+ int opt;
+ while ((opt = getopt(argc, argv, "idh")) != -1) {
+ switch (opt) {
+ case 'i':
+ leaf_only = false;
+ break;
+ case 'd':
+ include_deps = true;
+ break;
+ case 'h':
+ default:
+ printf(
+ "usage: ninja -t inputs [options] target [target...]\n\n"
+ "options:\n"
+ " -i Include intermediate inputs.\n"
+ " -d Include deps from the deps log file (.ninja_deps).\n");
+ return 1;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ vector<Node*> nodes;
+ string err;
+ if (!CollectTargetsFromArgs(argc, argv, &nodes, &err)) {
+ Error("%s", err.c_str());
+ return 1;
+ }
+
+ for (Node* node : nodes) {
+ node->MarkInputsChecked();
+ // Call ToolInputsProcessNode on this node's inputs, and not on itself,
+ // so that this node is not included in the output.
+ if (Edge* edge = node->in_edge(); edge != nullptr) {
+ for (Node* input : edge->inputs_) {
+ ToolInputsProcessNode(input, &deps_log_, leaf_only, include_deps);
+ }
+ if (include_deps && edge->outputs_.size() > 0) {
+ ToolInputsProcessNodeDeps(edge->outputs_[0], &deps_log_, leaf_only,
+ include_deps);
+ }
+ }
+ }
+ return 0;
+}
+
+
int NinjaMain::ToolQuery(const Options* options, int argc, char* argv[]) {
if (argc == 0) {
Error("expected a target to query");
@@ -892,6 +991,8 @@
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolDeps },
{ "graph", "output graphviz dot file for targets",
Tool::RUN_AFTER_LOAD, &NinjaMain::ToolGraph },
+ { "inputs", "show all (recursive) inputs for a target",
+ Tool::RUN_AFTER_LOGS, &NinjaMain::ToolInputs },
{ "path", "find dependency path between two targets",
Tool::RUN_AFTER_LOGS, &NinjaMain::ToolPath },
{ "query", "show inputs/outputs for a path",