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/filesystem_utils.h"
     14 #include "tools/gn/item.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 // Prints the given directory in a nice way for the user to view.
     25 std::string FormatSourceDir(const SourceDir& dir) {
     26 #if defined(OS_WIN)
     27   // On Windows we fix up system absolute paths to look like native ones.
     28   // Internally, they'll look like "/C:\foo\bar/"
     29   if (dir.is_system_absolute()) {
     30     std::string buf = dir.value();
     31     if (buf.size() > 3 && buf[2] == ':') {
     32       buf.erase(buf.begin());  // Erase beginning slash.
     33       ConvertPathToSystem(&buf);  // Convert to backslashes.
     34       return buf;
     35     }
     36   }
     37 #endif
     38   return dir.value();
     39 }
     40 
     41 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
     42 
     43 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
     44   if (result->find(target->label()) != result->end())
     45     return;  // Already did this target.
     46   result->insert(target->label());
     47 
     48   RecursiveCollectChildDeps(target, result);
     49 }
     50 
     51 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
     52   const LabelTargetVector& deps = target->deps();
     53   for (size_t i = 0; i < deps.size(); i++)
     54     RecursiveCollectDeps(deps[i].ptr, result);
     55 
     56   const LabelTargetVector& datadeps = target->datadeps();
     57   for (size_t i = 0; i < datadeps.size(); i++)
     58     RecursiveCollectDeps(datadeps[i].ptr, result);
     59 }
     60 
     61 // Prints dependencies of the given target (not the target itself).
     62 void RecursivePrintDeps(const Target* target,
     63                         const Label& default_toolchain,
     64                         int indent_level) {
     65   LabelTargetVector sorted_deps = target->deps();
     66   const LabelTargetVector& datadeps = target->datadeps();
     67   sorted_deps.insert(sorted_deps.end(), datadeps.begin(), datadeps.end());
     68   std::sort(sorted_deps.begin(), sorted_deps.end(),
     69             LabelPtrLabelLess<Target>());
     70 
     71   std::string indent(indent_level * 2, ' ');
     72   for (size_t i = 0; i < sorted_deps.size(); i++) {
     73     OutputString(indent +
     74         sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
     75     RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
     76   }
     77 }
     78 
     79 void PrintDeps(const Target* target, bool display_header) {
     80   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
     81   Label toolchain_label = target->label().GetToolchainLabel();
     82 
     83   // Tree mode is separate.
     84   if (cmdline->HasSwitch("tree")) {
     85     if (display_header)
     86       OutputString("\nDependency tree:\n");
     87     RecursivePrintDeps(target, toolchain_label, 1);
     88     return;
     89   }
     90 
     91   // Collect the deps to display.
     92   std::vector<Label> deps;
     93   if (cmdline->HasSwitch("all")) {
     94     if (display_header)
     95       OutputString("\nAll recursive dependencies:\n");
     96 
     97     std::set<Label> all_deps;
     98     RecursiveCollectChildDeps(target, &all_deps);
     99     for (std::set<Label>::iterator i = all_deps.begin();
    100          i != all_deps.end(); ++i)
    101       deps.push_back(*i);
    102   } else {
    103     if (display_header) {
    104       OutputString("\nDirect dependencies "
    105                    "(try also \"--all\" and \"--tree\"):\n");
    106     }
    107 
    108     const LabelTargetVector& target_deps = target->deps();
    109     for (size_t i = 0; i < target_deps.size(); i++)
    110       deps.push_back(target_deps[i].label);
    111 
    112     const LabelTargetVector& target_datadeps = target->datadeps();
    113     for (size_t i = 0; i < target_datadeps.size(); i++)
    114       deps.push_back(target_datadeps[i].label);
    115   }
    116 
    117   std::sort(deps.begin(), deps.end());
    118   for (size_t i = 0; i < deps.size(); i++)
    119     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
    120 }
    121 
    122 // libs and lib_dirs are special in that they're inherited. We don't currently
    123 // implement a blame feature for this since the bottom-up inheritance makes
    124 // this difficult.
    125 void PrintLibDirs(const Target* target, bool display_header) {
    126   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
    127   if (lib_dirs.empty())
    128     return;
    129 
    130   if (display_header)
    131     OutputString("\nlib_dirs\n");
    132 
    133   for (size_t i = 0; i < lib_dirs.size(); i++)
    134     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
    135 }
    136 
    137 void PrintLibs(const Target* target, bool display_header) {
    138   const OrderedSet<std::string>& libs = target->all_libs();
    139   if (libs.empty())
    140     return;
    141 
    142   if (display_header)
    143     OutputString("\nlibs\n");
    144 
    145   for (size_t i = 0; i < libs.size(); i++)
    146     OutputString("    " + libs[i] + "\n");
    147 }
    148 
    149 void PrintConfigs(const Target* target, bool display_header) {
    150   // Configs (don't sort since the order determines how things are processed).
    151   if (display_header)
    152     OutputString("\nConfigs (in order applying):\n");
    153 
    154   Label toolchain_label = target->label().GetToolchainLabel();
    155   const LabelConfigVector& configs = target->configs();
    156   for (size_t i = 0; i < configs.size(); i++) {
    157     OutputString("  " +
    158         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
    159   }
    160 }
    161 
    162 void PrintSources(const Target* target, bool display_header) {
    163   if (display_header)
    164     OutputString("\nSources:\n");
    165 
    166   Target::FileList sources = target->sources();
    167   std::sort(sources.begin(), sources.end());
    168   for (size_t i = 0; i < sources.size(); i++)
    169     OutputString("  " + sources[i].value() + "\n");
    170 }
    171 
    172 // Attribute the origin for attributing from where a target came from. Does
    173 // nothing if the input is null or it does not have a location.
    174 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
    175   if (!origin)
    176     return;
    177   Location location = origin->GetRange().begin();
    178   out << "       (Added by " + location.file()->name().value() << ":"
    179       << location.line_number() << ")\n";
    180 }
    181 
    182 // Templatized writer for writing out different config value types.
    183 template<typename T> struct DescValueWriter {};
    184 template<> struct DescValueWriter<std::string> {
    185   void operator()(const std::string& str, std::ostream& out) const {
    186     out << "    " << str << "\n";
    187   }
    188 };
    189 template<> struct DescValueWriter<SourceFile> {
    190   void operator()(const SourceFile& file, std::ostream& out) const {
    191     out << "    " << file.value() << "\n";
    192   }
    193 };
    194 template<> struct DescValueWriter<SourceDir> {
    195   void operator()(const SourceDir& dir, std::ostream& out) const {
    196     out << "    " << FormatSourceDir(dir) << "\n";
    197   }
    198 };
    199 
    200 // Writes a given config value type to the string, optionally with attribution.
    201 // This should match RecursiveTargetConfigToStream in the order it traverses.
    202 template<typename T> void OutputRecursiveTargetConfig(
    203     const Target* target,
    204     const char* header_name,
    205     const std::vector<T>& (ConfigValues::* getter)() const) {
    206   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
    207 
    208   DescValueWriter<T> writer;
    209   std::ostringstream out;
    210 
    211   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
    212     if ((iter.cur().*getter)().empty())
    213       continue;
    214 
    215     // Optional blame sub-head.
    216     if (display_blame) {
    217       const Config* config = iter.GetCurrentConfig();
    218       if (config) {
    219         // Source of this value is a config.
    220         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
    221         OutputSourceOfDep(iter.origin(), out);
    222       } else {
    223         // Source of this value is the target itself.
    224         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
    225       }
    226     }
    227 
    228     // Actual values.
    229     ConfigValuesToStream(iter.cur(), getter, writer, out);
    230   }
    231 
    232   std::string out_str = out.str();
    233   if (!out_str.empty()) {
    234     OutputString("\n" + std::string(header_name) + "\n");
    235     OutputString(out_str);
    236   }
    237 }
    238 
    239 }  // namespace
    240 
    241 // desc ------------------------------------------------------------------------
    242 
    243 const char kDesc[] = "desc";
    244 const char kDesc_HelpShort[] =
    245     "desc: Show lots of insightful information about a target.";
    246 const char kDesc_Help[] =
    247     "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
    248     "  Displays information about a given labeled target.\n"
    249     "\n"
    250     "Possibilities for <what to show>:\n"
    251     "  (If unspecified an overall summary will be displayed.)\n"
    252     "\n"
    253     "  sources\n"
    254     "      Source files.\n"
    255     "\n"
    256     "  configs\n"
    257     "      Shows configs applied to the given target, sorted in the order\n"
    258     "      they're specified. This includes both configs specified in the\n"
    259     "      \"configs\" variable, as well as configs pushed onto this target\n"
    260     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
    261     "      configs.\n"
    262     "\n"
    263     "  deps [--all | --tree]\n"
    264     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
    265     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
    266     "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
    267     "      Both \"deps\" and \"datadeps\" will be included.\n"
    268     "\n"
    269     "  defines       [--blame]\n"
    270     "  include_dirs  [--blame]\n"
    271     "  cflags        [--blame]\n"
    272     "  cflags_cc     [--blame]\n"
    273     "  cflags_cxx    [--blame]\n"
    274     "  ldflags       [--blame]\n"
    275     "  lib_dirs\n"
    276     "  libs\n"
    277     "      Shows the given values taken from the target and all configs\n"
    278     "      applying. See \"--blame\" below.\n"
    279     "\n"
    280     "  --blame\n"
    281     "      Used with any value specified by a config, this will name\n"
    282     "      the config that specified the value. This doesn't currently work\n"
    283     "      for libs and lib_dirs because those are inherited and are more\n"
    284     "      complicated to figure out the blame (patches welcome).\n"
    285     "\n"
    286     "Note:\n"
    287     "  This command will show the full name of directories and source files,\n"
    288     "  but when directories and source paths are written to the build file,\n"
    289     "  they will be adjusted to be relative to the build directory. So the\n"
    290     "  values for paths displayed by this command won't match (but should\n"
    291     "  mean the same thing.\n"
    292     "\n"
    293     "Examples:\n"
    294     "  gn desc //base:base\n"
    295     "      Summarizes the given target.\n"
    296     "\n"
    297     "  gn desc :base_unittests deps --tree\n"
    298     "      Shows a dependency tree of the \"base_unittests\" project in\n"
    299     "      the current directory.\n"
    300     "\n"
    301     "  gn desc //base defines --blame\n"
    302     "      Shows defines set for the //base:base target, annotated by where\n"
    303     "      each one was set from.\n";
    304 
    305 #define OUTPUT_CONFIG_VALUE(name, type) \
    306     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
    307 
    308 int RunDesc(const std::vector<std::string>& args) {
    309   if (args.size() != 1 && args.size() != 2) {
    310     Err(Location(), "You're holding it wrong.",
    311         "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
    312     return 1;
    313   }
    314 
    315   const Target* target = GetTargetForDesc(args);
    316   if (!target)
    317     return 1;
    318 
    319 #define CONFIG_VALUE_HANDLER(name, type) \
    320     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
    321 
    322   if (args.size() == 2) {
    323     // User specified one thing to display.
    324     const std::string& what = args[1];
    325     if (what == "configs") {
    326       PrintConfigs(target, false);
    327     } else if (what == "sources") {
    328       PrintSources(target, false);
    329     } else if (what == "deps") {
    330       PrintDeps(target, false);
    331     } else if (what == "lib_dirs") {
    332       PrintLibDirs(target, false);
    333     } else if (what == "libs") {
    334       PrintLibs(target, false);
    335 
    336     CONFIG_VALUE_HANDLER(defines, std::string)
    337     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
    338     CONFIG_VALUE_HANDLER(cflags, std::string)
    339     CONFIG_VALUE_HANDLER(cflags_c, std::string)
    340     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
    341     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
    342     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
    343     CONFIG_VALUE_HANDLER(ldflags, std::string)
    344 
    345     } else {
    346       OutputString("Don't know how to display \"" + what + "\".\n");
    347       return 1;
    348     }
    349 
    350 #undef CONFIG_VALUE_HANDLER
    351     return 0;
    352   }
    353 
    354   // Display summary.
    355 
    356   // Generally we only want to display toolchains on labels when the toolchain
    357   // is different than the default one for this target (which we always print
    358   // in the header).
    359   Label target_toolchain = target->label().GetToolchainLabel();
    360 
    361   // Header.
    362   OutputString("Target: ", DECORATION_YELLOW);
    363   OutputString(target->label().GetUserVisibleName(false) + "\n");
    364   OutputString("Type: ", DECORATION_YELLOW);
    365   OutputString(std::string(
    366       Target::GetStringForOutputType(target->output_type())) + "\n");
    367   OutputString("Toolchain: ", DECORATION_YELLOW);
    368   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
    369 
    370   PrintSources(target, true);
    371   PrintConfigs(target, true);
    372 
    373   OUTPUT_CONFIG_VALUE(defines, std::string)
    374   OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
    375   OUTPUT_CONFIG_VALUE(cflags, std::string)
    376   OUTPUT_CONFIG_VALUE(cflags_c, std::string)
    377   OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
    378   OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
    379   OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
    380   OUTPUT_CONFIG_VALUE(ldflags, std::string)
    381   PrintLibs(target, true);
    382   PrintLibDirs(target, true);
    383 
    384   PrintDeps(target, true);
    385 
    386   return 0;
    387 }
    388 
    389 }  // namespace commands
    390