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/file_template.h"
     14 #include "tools/gn/filesystem_utils.h"
     15 #include "tools/gn/item.h"
     16 #include "tools/gn/label.h"
     17 #include "tools/gn/setup.h"
     18 #include "tools/gn/standard_out.h"
     19 #include "tools/gn/target.h"
     20 
     21 namespace commands {
     22 
     23 namespace {
     24 
     25 // Prints the given directory in a nice way for the user to view.
     26 std::string FormatSourceDir(const SourceDir& dir) {
     27 #if defined(OS_WIN)
     28   // On Windows we fix up system absolute paths to look like native ones.
     29   // Internally, they'll look like "/C:\foo\bar/"
     30   if (dir.is_system_absolute()) {
     31     std::string buf = dir.value();
     32     if (buf.size() > 3 && buf[2] == ':') {
     33       buf.erase(buf.begin());  // Erase beginning slash.
     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     // Don't print groups. Groups are flattened such that the deps of the
     74     // group are added directly to the target that depended on the group.
     75     // Printing and recursing into groups here will cause such targets to be
     76     // duplicated.
     77     //
     78     // It would be much more intuitive to do the opposite and not display the
     79     // deps that were copied from the group to the target and instead display
     80     // the group, but the source of those dependencies is not tracked.
     81     if (sorted_deps[i].ptr->output_type() == Target::GROUP)
     82       continue;
     83 
     84     OutputString(indent +
     85         sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
     86     RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
     87   }
     88 }
     89 
     90 void PrintDeps(const Target* target, bool display_header) {
     91   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
     92   Label toolchain_label = target->label().GetToolchainLabel();
     93 
     94   // Tree mode is separate.
     95   if (cmdline->HasSwitch("tree")) {
     96     if (display_header)
     97       OutputString("\nDependency tree:\n");
     98     RecursivePrintDeps(target, toolchain_label, 1);
     99     return;
    100   }
    101 
    102   // Collect the deps to display.
    103   std::vector<Label> deps;
    104   if (cmdline->HasSwitch("all")) {
    105     if (display_header)
    106       OutputString("\nAll recursive dependencies:\n");
    107 
    108     std::set<Label> all_deps;
    109     RecursiveCollectChildDeps(target, &all_deps);
    110     for (std::set<Label>::iterator i = all_deps.begin();
    111          i != all_deps.end(); ++i)
    112       deps.push_back(*i);
    113   } else {
    114     if (display_header) {
    115       OutputString("\nDirect dependencies "
    116                    "(try also \"--all\" and \"--tree\"):\n");
    117     }
    118 
    119     const LabelTargetVector& target_deps = target->deps();
    120     for (size_t i = 0; i < target_deps.size(); i++)
    121       deps.push_back(target_deps[i].label);
    122 
    123     const LabelTargetVector& target_datadeps = target->datadeps();
    124     for (size_t i = 0; i < target_datadeps.size(); i++)
    125       deps.push_back(target_datadeps[i].label);
    126   }
    127 
    128   std::sort(deps.begin(), deps.end());
    129   for (size_t i = 0; i < deps.size(); i++)
    130     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
    131 }
    132 
    133 void PrintForwardDependentConfigsFrom(const Target* target,
    134                                       bool display_header) {
    135   if (target->forward_dependent_configs().empty())
    136     return;
    137 
    138   if (display_header)
    139     OutputString("\nforward_dependent_configs_from:\n");
    140 
    141   // Collect the sorted list of deps.
    142   std::vector<Label> forward;
    143   for (size_t i = 0; i < target->forward_dependent_configs().size(); i++)
    144     forward.push_back(target->forward_dependent_configs()[i].label);
    145   std::sort(forward.begin(), forward.end());
    146 
    147   Label toolchain_label = target->label().GetToolchainLabel();
    148   for (size_t i = 0; i < forward.size(); i++)
    149     OutputString("  " + forward[i].GetUserVisibleName(toolchain_label) + "\n");
    150 }
    151 
    152 // libs and lib_dirs are special in that they're inherited. We don't currently
    153 // implement a blame feature for this since the bottom-up inheritance makes
    154 // this difficult.
    155 void PrintLibDirs(const Target* target, bool display_header) {
    156   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
    157   if (lib_dirs.empty())
    158     return;
    159 
    160   if (display_header)
    161     OutputString("\nlib_dirs\n");
    162 
    163   for (size_t i = 0; i < lib_dirs.size(); i++)
    164     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
    165 }
    166 
    167 void PrintLibs(const Target* target, bool display_header) {
    168   const OrderedSet<std::string>& libs = target->all_libs();
    169   if (libs.empty())
    170     return;
    171 
    172   if (display_header)
    173     OutputString("\nlibs\n");
    174 
    175   for (size_t i = 0; i < libs.size(); i++)
    176     OutputString("    " + libs[i] + "\n");
    177 }
    178 
    179 void PrintPublic(const Target* target, bool display_header) {
    180   if (display_header)
    181     OutputString("\npublic:\n");
    182 
    183   if (target->all_headers_public()) {
    184     OutputString("  [All headers listed in the sources are public.]\n");
    185     return;
    186   }
    187 
    188   Target::FileList public_headers = target->public_headers();
    189   std::sort(public_headers.begin(), public_headers.end());
    190   for (size_t i = 0; i < public_headers.size(); i++)
    191     OutputString("  " + public_headers[i].value() + "\n");
    192 }
    193 
    194 void PrintVisibility(const Target* target, bool display_header) {
    195   if (display_header)
    196     OutputString("\nvisibility:\n");
    197 
    198   OutputString(target->visibility().Describe(2, false));
    199 }
    200 
    201 void PrintConfigsVector(const Target* target,
    202                         const LabelConfigVector& configs,
    203                         const std::string& heading,
    204                         bool display_header) {
    205   if (configs.empty())
    206     return;
    207 
    208   // Don't sort since the order determines how things are processed.
    209   if (display_header)
    210     OutputString("\n" + heading + " (in order applying):\n");
    211 
    212   Label toolchain_label = target->label().GetToolchainLabel();
    213   for (size_t i = 0; i < configs.size(); i++) {
    214     OutputString("  " +
    215         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
    216   }
    217 }
    218 
    219 void PrintConfigs(const Target* target, bool display_header) {
    220   PrintConfigsVector(target, target->configs(), "configs", display_header);
    221 }
    222 
    223 void PrintDirectDependentConfigs(const Target* target, bool display_header) {
    224   PrintConfigsVector(target, target->direct_dependent_configs(),
    225                      "direct_dependent_configs", display_header);
    226 }
    227 
    228 void PrintAllDependentConfigs(const Target* target, bool display_header) {
    229   PrintConfigsVector(target, target->all_dependent_configs(),
    230                      "all_dependent_configs", display_header);
    231 }
    232 
    233 void PrintFileList(const Target::FileList& files,
    234                    const std::string& header,
    235                    bool indent_extra,
    236                    bool display_header) {
    237   if (files.empty())
    238     return;
    239 
    240   if (display_header)
    241     OutputString("\n" + header + ":\n");
    242 
    243   std::string indent = indent_extra ? "    " : "  ";
    244 
    245   Target::FileList sorted = files;
    246   std::sort(sorted.begin(), sorted.end());
    247   for (size_t i = 0; i < sorted.size(); i++)
    248     OutputString(indent + sorted[i].value() + "\n");
    249 }
    250 
    251 void PrintSources(const Target* target, bool display_header) {
    252   PrintFileList(target->sources(), "sources", false, display_header);
    253 }
    254 
    255 void PrintInputs(const Target* target, bool display_header) {
    256   PrintFileList(target->inputs(), "inputs", false, display_header);
    257 }
    258 
    259 void PrintOutputs(const Target* target, bool display_header) {
    260   if (target->output_type() == Target::ACTION) {
    261     // Just display the outputs directly.
    262     PrintFileList(target->action_values().outputs(), "outputs", false,
    263                   display_header);
    264   } else if (target->output_type() == Target::ACTION_FOREACH) {
    265     // Display both the output pattern and resolved list.
    266     if (display_header)
    267       OutputString("\noutputs:\n");
    268 
    269     // Display the pattern.
    270     OutputString("  Output pattern:\n");
    271     PrintFileList(target->action_values().outputs(), "", true, false);
    272 
    273     // Now display what that resolves to given the sources.
    274     OutputString("\n  Resolved output file list:\n");
    275 
    276     std::vector<std::string> output_strings;
    277     FileTemplate file_template = FileTemplate::GetForTargetOutputs(target);
    278     for (size_t i = 0; i < target->sources().size(); i++)
    279       file_template.Apply(target->sources()[i], &output_strings);
    280 
    281     std::sort(output_strings.begin(), output_strings.end());
    282     for (size_t i = 0; i < output_strings.size(); i++) {
    283       OutputString("    " + output_strings[i] + "\n");
    284     }
    285   }
    286 }
    287 
    288 void PrintScript(const Target* target, bool display_header) {
    289   if (display_header)
    290     OutputString("\nscript:\n");
    291   OutputString("  " + target->action_values().script().value() + "\n");
    292 }
    293 
    294 void PrintArgs(const Target* target, bool display_header) {
    295   if (display_header)
    296     OutputString("\nargs:\n");
    297   for (size_t i = 0; i < target->action_values().args().size(); i++)
    298     OutputString("  " + target->action_values().args()[i] + "\n");
    299 }
    300 
    301 void PrintDepfile(const Target* target, bool display_header) {
    302   if (target->action_values().depfile().value().empty())
    303     return;
    304   if (display_header)
    305     OutputString("\ndepfile:\n");
    306   OutputString("  " + target->action_values().depfile().value() + "\n");
    307 }
    308 
    309 // Attribute the origin for attributing from where a target came from. Does
    310 // nothing if the input is null or it does not have a location.
    311 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
    312   if (!origin)
    313     return;
    314   Location location = origin->GetRange().begin();
    315   out << "       (Added by " + location.file()->name().value() << ":"
    316       << location.line_number() << ")\n";
    317 }
    318 
    319 // Templatized writer for writing out different config value types.
    320 template<typename T> struct DescValueWriter {};
    321 template<> struct DescValueWriter<std::string> {
    322   void operator()(const std::string& str, std::ostream& out) const {
    323     out << "    " << str << "\n";
    324   }
    325 };
    326 template<> struct DescValueWriter<SourceDir> {
    327   void operator()(const SourceDir& dir, std::ostream& out) const {
    328     out << "    " << FormatSourceDir(dir) << "\n";
    329   }
    330 };
    331 
    332 // Writes a given config value type to the string, optionally with attribution.
    333 // This should match RecursiveTargetConfigToStream in the order it traverses.
    334 template<typename T> void OutputRecursiveTargetConfig(
    335     const Target* target,
    336     const char* header_name,
    337     const std::vector<T>& (ConfigValues::* getter)() const) {
    338   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
    339 
    340   DescValueWriter<T> writer;
    341   std::ostringstream out;
    342 
    343   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
    344     if ((iter.cur().*getter)().empty())
    345       continue;
    346 
    347     // Optional blame sub-head.
    348     if (display_blame) {
    349       const Config* config = iter.GetCurrentConfig();
    350       if (config) {
    351         // Source of this value is a config.
    352         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
    353         OutputSourceOfDep(iter.origin(), out);
    354       } else {
    355         // Source of this value is the target itself.
    356         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
    357       }
    358     }
    359 
    360     // Actual values.
    361     ConfigValuesToStream(iter.cur(), getter, writer, out);
    362   }
    363 
    364   std::string out_str = out.str();
    365   if (!out_str.empty()) {
    366     OutputString("\n" + std::string(header_name) + "\n");
    367     OutputString(out_str);
    368   }
    369 }
    370 
    371 }  // namespace
    372 
    373 // desc ------------------------------------------------------------------------
    374 
    375 const char kDesc[] = "desc";
    376 const char kDesc_HelpShort[] =
    377     "desc: Show lots of insightful information about a target.";
    378 const char kDesc_Help[] =
    379     "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
    380     "  Displays information about a given labeled target.\n"
    381     "\n"
    382     "Possibilities for <what to show>:\n"
    383     "  (If unspecified an overall summary will be displayed.)\n"
    384     "\n"
    385     "  sources\n"
    386     "      Source files.\n"
    387     "\n"
    388     "  inputs\n"
    389     "      Additional input dependencies.\n"
    390     "\n"
    391     "  public\n"
    392     "      Public header files.\n"
    393     "\n"
    394     "  visibility\n"
    395     "      Prints which targets can depend on this one.\n"
    396     "\n"
    397     "  configs\n"
    398     "      Shows configs applied to the given target, sorted in the order\n"
    399     "      they're specified. This includes both configs specified in the\n"
    400     "      \"configs\" variable, as well as configs pushed onto this target\n"
    401     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
    402     "      configs.\n"
    403     "\n"
    404     "  deps [--all | --tree]\n"
    405     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
    406     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
    407     "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
    408     "      Both \"deps\" and \"datadeps\" will be included.\n"
    409     "\n"
    410     "  direct_dependent_configs\n"
    411     "  all_dependent_configs\n"
    412     "      Shows the labels of configs applied to targets that depend on this\n"
    413     "      one (either directly or all of them).\n"
    414     "\n"
    415     "  forward_dependent_configs_from\n"
    416     "      Shows the labels of dependencies for which dependent configs will\n"
    417     "      be pushed to targets depending on the current one.\n"
    418     "\n"
    419     "  script\n"
    420     "  args\n"
    421     "  depfile\n"
    422     "      Actions only. The script and related values.\n"
    423     "\n"
    424     "  outputs\n"
    425     "      Outputs for script and copy target types.\n"
    426     "\n"
    427     "  defines       [--blame]\n"
    428     "  include_dirs  [--blame]\n"
    429     "  cflags        [--blame]\n"
    430     "  cflags_cc     [--blame]\n"
    431     "  cflags_cxx    [--blame]\n"
    432     "  ldflags       [--blame]\n"
    433     "  lib_dirs\n"
    434     "  libs\n"
    435     "      Shows the given values taken from the target and all configs\n"
    436     "      applying. See \"--blame\" below.\n"
    437     "\n"
    438     "  --blame\n"
    439     "      Used with any value specified by a config, this will name\n"
    440     "      the config that specified the value. This doesn't currently work\n"
    441     "      for libs and lib_dirs because those are inherited and are more\n"
    442     "      complicated to figure out the blame (patches welcome).\n"
    443     "\n"
    444     "Note:\n"
    445     "  This command will show the full name of directories and source files,\n"
    446     "  but when directories and source paths are written to the build file,\n"
    447     "  they will be adjusted to be relative to the build directory. So the\n"
    448     "  values for paths displayed by this command won't match (but should\n"
    449     "  mean the same thing).\n"
    450     "\n"
    451     "Examples:\n"
    452     "  gn desc //base:base\n"
    453     "      Summarizes the given target.\n"
    454     "\n"
    455     "  gn desc :base_unittests deps --tree\n"
    456     "      Shows a dependency tree of the \"base_unittests\" project in\n"
    457     "      the current directory.\n"
    458     "\n"
    459     "  gn desc //base defines --blame\n"
    460     "      Shows defines set for the //base:base target, annotated by where\n"
    461     "      each one was set from.\n";
    462 
    463 #define OUTPUT_CONFIG_VALUE(name, type) \
    464     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
    465 
    466 int RunDesc(const std::vector<std::string>& args) {
    467   if (args.size() != 1 && args.size() != 2) {
    468     Err(Location(), "You're holding it wrong.",
    469         "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
    470     return 1;
    471   }
    472 
    473   const Target* target = GetTargetForDesc(args);
    474   if (!target)
    475     return 1;
    476 
    477 #define CONFIG_VALUE_HANDLER(name, type) \
    478     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
    479 
    480   if (args.size() == 2) {
    481     // User specified one thing to display.
    482     const std::string& what = args[1];
    483     if (what == "configs") {
    484       PrintConfigs(target, false);
    485     } else if (what == "direct_dependent_configs") {
    486       PrintDirectDependentConfigs(target, false);
    487     } else if (what == "all_dependent_configs") {
    488       PrintAllDependentConfigs(target, false);
    489     } else if (what == "forward_dependent_configs_from") {
    490       PrintForwardDependentConfigsFrom(target, false);
    491     } else if (what == "sources") {
    492       PrintSources(target, false);
    493     } else if (what == "public") {
    494       PrintPublic(target, false);
    495     } else if (what == "visibility") {
    496       PrintVisibility(target, false);
    497     } else if (what == "inputs") {
    498       PrintInputs(target, false);
    499     } else if (what == "script") {
    500       PrintScript(target, false);
    501     } else if (what == "args") {
    502       PrintArgs(target, false);
    503     } else if (what == "depfile") {
    504       PrintDepfile(target, false);
    505     } else if (what == "outputs") {
    506       PrintOutputs(target, false);
    507     } else if (what == "deps") {
    508       PrintDeps(target, false);
    509     } else if (what == "lib_dirs") {
    510       PrintLibDirs(target, false);
    511     } else if (what == "libs") {
    512       PrintLibs(target, false);
    513 
    514     CONFIG_VALUE_HANDLER(defines, std::string)
    515     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
    516     CONFIG_VALUE_HANDLER(cflags, std::string)
    517     CONFIG_VALUE_HANDLER(cflags_c, std::string)
    518     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
    519     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
    520     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
    521     CONFIG_VALUE_HANDLER(ldflags, std::string)
    522 
    523     } else {
    524       OutputString("Don't know how to display \"" + what + "\".\n");
    525       return 1;
    526     }
    527 
    528 #undef CONFIG_VALUE_HANDLER
    529     return 0;
    530   }
    531 
    532   // Display summary.
    533 
    534   // Display this only applicable to binary targets.
    535   bool is_binary_output =
    536     target->output_type() != Target::GROUP &&
    537     target->output_type() != Target::COPY_FILES &&
    538     target->output_type() != Target::ACTION &&
    539     target->output_type() != Target::ACTION_FOREACH;
    540 
    541   // Generally we only want to display toolchains on labels when the toolchain
    542   // is different than the default one for this target (which we always print
    543   // in the header).
    544   Label target_toolchain = target->label().GetToolchainLabel();
    545 
    546   // Header.
    547   OutputString("Target: ", DECORATION_YELLOW);
    548   OutputString(target->label().GetUserVisibleName(false) + "\n");
    549   OutputString("Type: ", DECORATION_YELLOW);
    550   OutputString(std::string(
    551       Target::GetStringForOutputType(target->output_type())) + "\n");
    552   OutputString("Toolchain: ", DECORATION_YELLOW);
    553   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
    554 
    555   PrintSources(target, true);
    556   if (is_binary_output)
    557     PrintPublic(target, true);
    558   PrintVisibility(target, true);
    559   if (is_binary_output)
    560     PrintConfigs(target, true);
    561 
    562   PrintDirectDependentConfigs(target, true);
    563   PrintAllDependentConfigs(target, true);
    564   PrintForwardDependentConfigsFrom(target, true);
    565 
    566   PrintInputs(target, true);
    567 
    568   if (is_binary_output) {
    569     OUTPUT_CONFIG_VALUE(defines, std::string)
    570     OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
    571     OUTPUT_CONFIG_VALUE(cflags, std::string)
    572     OUTPUT_CONFIG_VALUE(cflags_c, std::string)
    573     OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
    574     OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
    575     OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
    576     OUTPUT_CONFIG_VALUE(ldflags, std::string)
    577   }
    578 
    579   if (target->output_type() == Target::ACTION ||
    580       target->output_type() == Target::ACTION_FOREACH) {
    581     PrintScript(target, true);
    582     PrintArgs(target, true);
    583     PrintDepfile(target, true);
    584   }
    585 
    586   if (target->output_type() == Target::ACTION ||
    587       target->output_type() == Target::ACTION_FOREACH ||
    588       target->output_type() == Target::COPY_FILES) {
    589     PrintOutputs(target, true);
    590   }
    591 
    592   // Libs can be part of any target and get recursively pushed up the chain,
    593   // so always display them, even for groups and such.
    594   PrintLibs(target, true);
    595   PrintLibDirs(target, true);
    596 
    597   PrintDeps(target, true);
    598 
    599   return 0;
    600 }
    601 
    602 }  // namespace commands
    603