From 065526303afd0f5e1d634480421dcafc87894f72 Mon Sep 17 00:00:00 2001 From: csmoe Date: Mon, 25 Mar 2019 04:30:59 +0800 Subject: [PATCH] Allow 'ninja -t compdb' accept targets Test: ./ninja -t compdb -a wrong_target (fail) ./ninja -t compdb -a test_target (empty due to lack of rules) ./ninja -t compdb -a test_target cc cxx (ok) ./ninja -t compdb cxx (ok, regression test) ./ninja ninja_test && ./ninja_test (passed) Co-authored-by: Linkun Chen Co-authored-by: csmoe --- src/ninja.cc | 74 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/src/ninja.cc b/src/ninja.cc index 887d89f8d8..9c8463f19a 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include #include @@ -909,6 +912,38 @@ void printCompdb(const char* const directory, const Edge* const edge, printf("\"\n }"); } +bool GetAllDependentEdges(Node* node, std::vector* depend_edges, + std::set* visited_nodes=NULL, + std::set* visited_edges=NULL) { + if (visited_nodes == NULL || visited_edges == NULL) { + std::set visited_nodes_; + std::set visited_edges_; + return GetAllDependentEdges(node, depend_edges, &visited_nodes_, &visited_edges_); + } + + assert(node); + assert(depend_edges); + + if (visited_nodes->count(node)) { + return true; + } + visited_nodes->insert(node); + + Edge* edge = node->in_edge(); + // Leaf node + if (!edge || visited_edges->count(edge)) { + return true; + } + visited_edges->insert(edge); + depend_edges->push_back(edge); + + for (Node* input_node : edge->inputs_) { + if (!GetAllDependentEdges(input_node, depend_edges, visited_nodes, visited_edges)) + return false; + } + return true; +} + int NinjaMain::ToolCompilationDatabase(const Options* options, int argc, char* argv[]) { // The compdb tool uses getopt, and expects argv[0] to contain the name of @@ -920,19 +955,50 @@ int NinjaMain::ToolCompilationDatabase(const Options* options, int argc, optind = 1; int opt; - while ((opt = getopt(argc, argv, const_cast("hx"))) != -1) { + const option long_options[] = { + {"target", required_argument, NULL, 't'}, + {NULL, 0, NULL, 0} + }; + + std::vector edges_to_process = state_.edges_; + while ((opt = getopt_long(argc, argv, "x:", long_options, NULL)) != -1) { switch(opt) { case 'x': eval_mode = ECM_EXPAND_RSPFILE; break; + case 't': { + std::istringstream iss(optarg); + string target; + std::vector user_interested_edges; + + while (std::getline(iss, target, ',')) { + string err; + Node* node = CollectTarget(target.c_str(), &err); + + if (!node) { + Error("%s", err.c_str()); + return 1; + } + if (!GetAllDependentEdges(node, &user_interested_edges)) { + return 1; + } + } + if (user_interested_edges.size() > 0) { + edges_to_process = user_interested_edges; + } + + break; + } + case 'h': default: printf( "usage: ninja -t compdb [options] [rules]\n" "\n" "options:\n" - " -x expand @rspfile style response file invocations\n" + " -x expand @rspfile style response file invocations\n" + " --target generate compilation database for given targets, separated by commas\n" ); return 1; } @@ -955,8 +1021,8 @@ int NinjaMain::ToolCompilationDatabase(const Options* options, int argc, } putchar('['); - for (vector::iterator e = state_.edges_.begin(); - e != state_.edges_.end(); ++e) { + for (vector::iterator e = edges_to_process.begin(); + e != edges_to_process.end(); ++e) { if ((*e)->inputs_.empty()) continue; if (argc == 0) {