Home | History | Annotate | Download | only in gn
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 #include <set>
      7 #include <sstream>
      8 
      9 #include "base/command_line.h"
     10 #include "tools/gn/commands.h"
     11 #include "tools/gn/config.h"
     12 #include "tools/gn/config_values_extractors.h"
     13 #include "tools/gn/item.h"
     14 #include "tools/gn/item_node.h"
     15 #include "tools/gn/label.h"
     16 #include "tools/gn/setup.h"
     17 #include "tools/gn/standard_out.h"
     18 #include "tools/gn/target.h"
     19 
     20 namespace commands {
     21 
     22 namespace {
     23 
     24 struct CompareTargetLabel {
     25   bool operator()(const Target* a, const Target* b) const {
     26     return a->label() < b->label();
     27   }
     28 };
     29 
     30 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
     31   if (result->find(target->label()) != result->end())
     32     return;  // Already did this target.
     33   result->insert(target->label());
     34 
     35   const std::vector<const Target*>& deps = target->deps();
     36   for (size_t i = 0; i < deps.size(); i++)
     37     RecursiveCollectDeps(deps[i], result);
     38 
     39   const std::vector<const Target*>& datadeps = target->datadeps();
     40   for (size_t i = 0; i < datadeps.size(); i++)
     41     RecursiveCollectDeps(datadeps[i], result);
     42 }
     43 
     44 // Prints dependencies of the given target (not the target itself).
     45 void RecursivePrintDeps(const Target* target,
     46                         const Label& default_toolchain,
     47                         int indent_level) {
     48   std::vector<const Target*> sorted_deps = target->deps();
     49   const std::vector<const Target*> datadeps = target->datadeps();
     50   for (size_t i = 0; i < datadeps.size(); i++)
     51     sorted_deps.push_back(datadeps[i]);
     52   std::sort(sorted_deps.begin(), sorted_deps.end(), CompareTargetLabel());
     53 
     54   std::string indent(indent_level * 2, ' ');
     55   for (size_t i = 0; i < sorted_deps.size(); i++) {
     56     OutputString(indent +
     57         sorted_deps[i]->label().GetUserVisibleName(default_toolchain) + "\n");
     58     RecursivePrintDeps(sorted_deps[i], default_toolchain, indent_level + 1);
     59   }
     60 }
     61 
     62 void PrintDeps(const Target* target, bool display_header) {
     63   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
     64   Label toolchain_label = target->label().GetToolchainLabel();
     65 
     66   // Tree mode is separate.
     67   if (cmdline->HasSwitch("tree")) {
     68     if (display_header)
     69       OutputString("\nDependency tree:\n");
     70     RecursivePrintDeps(target, toolchain_label, 1);
     71     return;
     72   }
     73 
     74   // Collect the deps to display.
     75   std::vector<Label> deps;
     76   if (cmdline->HasSwitch("all")) {
     77     if (display_header)
     78       OutputString("\nAll recursive dependencies:\n");
     79 
     80     std::set<Label> all_deps;
     81     RecursiveCollectDeps(target, &all_deps);
     82     for (std::set<Label>::iterator i = all_deps.begin();
     83          i != all_deps.end(); ++i)
     84       deps.push_back(*i);
     85   } else {
     86     if (display_header) {
     87       OutputString("\nDirect dependencies "
     88                    "(try also \"--all\" and \"--tree\"):\n");
     89     }
     90 
     91     const std::vector<const Target*>& target_deps = target->deps();
     92     for (size_t i = 0; i < target_deps.size(); i++)
     93       deps.push_back(target_deps[i]->label());
     94 
     95     const std::vector<const Target*>& target_datadeps = target->datadeps();
     96     for (size_t i = 0; i < target_datadeps.size(); i++)
     97       deps.push_back(target_datadeps[i]->label());
     98   }
     99 
    100   std::sort(deps.begin(), deps.end());
    101   for (size_t i = 0; i < deps.size(); i++)
    102     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
    103 }
    104 
    105 void PrintConfigs(const Target* target, bool display_header) {
    106   // Configs (don't sort since the order determines how things are processed).
    107   if (display_header)
    108     OutputString("\nConfigs (in order applying):\n");
    109 
    110   Label toolchain_label = target->label().GetToolchainLabel();
    111   const std::vector<const Config*>& configs = target->configs();
    112   for (size_t i = 0; i < configs.size(); i++) {
    113     OutputString("  " +
    114         configs[i]->label().GetUserVisibleName(toolchain_label) + "\n");
    115   }
    116 }
    117 
    118 void PrintSources(const Target* target, bool display_header) {
    119   if (display_header)
    120     OutputString("\nSources:\n");
    121 
    122   Target::FileList sources = target->sources();
    123   std::sort(sources.begin(), sources.end());
    124   for (size_t i = 0; i < sources.size(); i++)
    125     OutputString("  " + sources[i].value() + "\n");
    126 }
    127 
    128 // Attempts to attribute the gen dependency of the given target to some source
    129 // code and outputs the string to the output stream.
    130 //
    131 // The attribution of the source of the dependencies is stored in the ItemNode
    132 // which is the parallel structure to the target dependency map, so we have
    133 // to jump through a few loops to find everything.
    134 void OutputSourceOfDep(const Target* target,
    135                        const Label& dep_label,
    136                        std::ostream& out) {
    137   ItemTree& item_tree = target->settings()->build_settings()->item_tree();
    138   base::AutoLock lock(item_tree.lock());
    139 
    140   ItemNode* target_node = item_tree.GetExistingNodeLocked(target->label());
    141   CHECK(target_node);
    142   ItemNode* dep_node = item_tree.GetExistingNodeLocked(dep_label);
    143   CHECK(dep_node);
    144 
    145   const ItemNode::ItemNodeMap& direct_deps = target_node->direct_dependencies();
    146   ItemNode::ItemNodeMap::const_iterator found = direct_deps.find(dep_node);
    147   if (found == direct_deps.end())
    148     return;
    149 
    150   const Location& location = found->second.begin();
    151   out << "       (Added by " + location.file()->name().value() << ":"
    152       << location.line_number() << ")\n";
    153 }
    154 
    155 // Templatized writer for writing out different config value types.
    156 template<typename T> struct DescValueWriter {};
    157 template<> struct DescValueWriter<std::string> {
    158   void operator()(const std::string& str, std::ostream& out) const {
    159     out << "    " << str << "\n";
    160   }
    161 };
    162 template<> struct DescValueWriter<SourceFile> {
    163   void operator()(const SourceFile& file, std::ostream& out) const {
    164     out << "    " << file.value() << "\n";
    165   }
    166 };
    167 template<> struct DescValueWriter<SourceDir> {
    168   void operator()(const SourceDir& dir, std::ostream& out) const {
    169     out << "    " << dir.value() << "\n";
    170   }
    171 };
    172 
    173 // Writes a given config value type to the string, optionally with attribution.
    174 // This should match RecursiveTargetConfigToStream in the order it traverses.
    175 template<typename T> void OutputRecursiveTargetConfig(
    176     const Target* target,
    177     const char* header_name,
    178     const std::vector<T>& (ConfigValues::* getter)() const) {
    179   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
    180 
    181   DescValueWriter<T> writer;
    182   std::ostringstream out;
    183 
    184   // First write the values from the config itself.
    185   if (!(target->config_values().*getter)().empty()) {
    186     if (display_blame)
    187       out << "  From " << target->label().GetUserVisibleName(false) << "\n";
    188     ConfigValuesToStream(target->config_values(), getter, writer, out);
    189   }
    190 
    191   // TODO(brettw) annotate where forced config includes came from!
    192 
    193   // Then write the configs in order.
    194   for (size_t i = 0; i < target->configs().size(); i++) {
    195     const Config* config = target->configs()[i];
    196     const ConfigValues& values = config->config_values();
    197 
    198     if (!(values.*getter)().empty()) {
    199       if (display_blame) {
    200         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
    201         OutputSourceOfDep(target, config->label(), out);
    202       }
    203       ConfigValuesToStream(values, getter, writer, out);
    204     }
    205   }
    206 
    207   std::string out_str = out.str();
    208   if (!out_str.empty()) {
    209     OutputString(std::string(header_name) + "\n");
    210     OutputString(out_str);
    211   }
    212 }
    213 
    214 }  // namespace
    215 
    216 // desc ------------------------------------------------------------------------
    217 
    218 const char kDesc[] = "desc";
    219 const char kDesc_HelpShort[] =
    220     "desc: Show lots of insightful information about a target.";
    221 const char kDesc_Help[] =
    222     "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
    223     "  Displays information about a given labeled target.\n"
    224     "\n"
    225     "Possibilities for <what to show>:\n"
    226     "  (If unspecified an overall summary will be displayed.)\n"
    227     "\n"
    228     "  sources\n"
    229     "      Source files.\n"
    230     "\n"
    231     "  configs\n"
    232     "      Shows configs applied to the given target, sorted in the order\n"
    233     "      they're specified. This includes both configs specified in the\n"
    234     "      \"configs\" variable, as well as configs pushed onto this target\n"
    235     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
    236     "      configs.\n"
    237     "\n"
    238     "  deps [--all | --tree]\n"
    239     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
    240     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
    241     "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
    242     "      Both \"deps\" and \"datadeps\" will be included.\n"
    243     "\n"
    244     "  defines    [--blame]\n"
    245     "  includes   [--blame]\n"
    246     "  cflags     [--blame]\n"
    247     "  cflags_cc  [--blame]\n"
    248     "  cflags_cxx [--blame]\n"
    249     "  ldflags    [--blame]\n"
    250     "      Shows the given values taken from the target and all configs\n"
    251     "      applying. See \"--blame\" below.\n"
    252     "\n"
    253     "  --blame\n"
    254     "      Used with any value specified by a config, this will name\n"
    255     "      the config that specified the value.\n"
    256     "\n"
    257     "Note:\n"
    258     "  This command will show the full name of directories and source files,\n"
    259     "  but when directories and source paths are written to the build file,\n"
    260     "  they will be adjusted to be relative to the build directory. So the\n"
    261     "  values for paths displayed by this command won't match (but should\n"
    262     "  mean the same thing.\n"
    263     "\n"
    264     "Examples:\n"
    265     "  gn desc //base:base\n"
    266     "      Summarizes the given target.\n"
    267     "\n"
    268     "  gn desc :base_unittests deps --tree\n"
    269     "      Shows a dependency tree of the \"base_unittests\" project in\n"
    270     "      the current directory.\n"
    271     "\n"
    272     "  gn desc //base defines --blame\n"
    273     "      Shows defines set for the //base:base target, annotated by where\n"
    274     "      each one was set from.\n";
    275 
    276 int RunDesc(const std::vector<std::string>& args) {
    277   if (args.size() != 1 && args.size() != 2) {
    278     Err(Location(), "You're holding it wrong.",
    279         "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
    280     return 1;
    281   }
    282 
    283   const Target* target = GetTargetForDesc(args);
    284   if (!target)
    285     return 1;
    286 
    287 #define CONFIG_VALUE_HANDLER(name) \
    288     } else if (what == #name) { \
    289       OutputRecursiveTargetConfig(target, #name, &ConfigValues::name);
    290 
    291   if (args.size() == 2) {
    292     // User specified one thing to display.
    293     const std::string& what = args[1];
    294     if (what == "configs") {
    295       PrintConfigs(target, false);
    296     } else if (what == "sources") {
    297       PrintSources(target, false);
    298     } else if (what == "deps") {
    299       PrintDeps(target, false);
    300 
    301     CONFIG_VALUE_HANDLER(defines)
    302     CONFIG_VALUE_HANDLER(includes)
    303     CONFIG_VALUE_HANDLER(cflags)
    304     CONFIG_VALUE_HANDLER(cflags_c)
    305     CONFIG_VALUE_HANDLER(cflags_cc)
    306     CONFIG_VALUE_HANDLER(ldflags)
    307 
    308     } else {
    309       OutputString("Don't know how to display \"" + what + "\".\n");
    310       return 1;
    311     }
    312 
    313 #undef CONFIG_VALUE_HANDLER
    314     return 0;
    315   }
    316 
    317   // Display summary.
    318 
    319   // Generally we only want to display toolchains on labels when the toolchain
    320   // is different than the default one for this target (which we always print
    321   // in the header).
    322   Label target_toolchain = target->label().GetToolchainLabel();
    323 
    324   // Header.
    325   std::string title_target =
    326       "Target: " + target->label().GetUserVisibleName(false);
    327   std::string title_toolchain =
    328       "Toolchain: " + target_toolchain.GetUserVisibleName(false);
    329   OutputString(title_target + "\n", DECORATION_YELLOW);
    330   OutputString(title_toolchain + "\n", DECORATION_YELLOW);
    331   OutputString(std::string(
    332       std::max(title_target.size(), title_toolchain.size()), '=') + "\n");
    333 
    334   PrintSources(target, true);
    335   PrintConfigs(target, true);
    336   OutputString("\n  (Use \"gn desc <label> <thing you want to see>\" to show "
    337                "the actual values\n   applied by the different configs. "
    338                "See \"gn help desc\" for more.)\n");
    339   PrintDeps(target, true);
    340 
    341   return 0;
    342 }
    343 
    344 }  // namespace commands
    345