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/deps_iterator.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/substitution_writer.h"
     20 #include "tools/gn/target.h"
     21 #include "tools/gn/variables.h"
     22 
     23 namespace commands {
     24 
     25 namespace {
     26 
     27 // Prints the given directory in a nice way for the user to view.
     28 std::string FormatSourceDir(const SourceDir& dir) {
     29 #if defined(OS_WIN)
     30   // On Windows we fix up system absolute paths to look like native ones.
     31   // Internally, they'll look like "/C:\foo\bar/"
     32   if (dir.is_system_absolute()) {
     33     std::string buf = dir.value();
     34     if (buf.size() > 3 && buf[2] == ':') {
     35       buf.erase(buf.begin());  // Erase beginning slash.
     36       return buf;
     37     }
     38   }
     39 #endif
     40   return dir.value();
     41 }
     42 
     43 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
     44 
     45 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
     46   if (result->find(target->label()) != result->end())
     47     return;  // Already did this target.
     48   result->insert(target->label());
     49 
     50   RecursiveCollectChildDeps(target, result);
     51 }
     52 
     53 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
     54   for (DepsIterator iter(target); !iter.done(); iter.Advance())
     55     RecursiveCollectDeps(iter.target(), result);
     56 }
     57 
     58 // Prints dependencies of the given target (not the target itself). If the
     59 // set is non-null, new targets encountered will be added to the set, and if
     60 // a dependency is in the set already, it will not be recused into. When the
     61 // set is null, all dependencies will be printed.
     62 void RecursivePrintDeps(const Target* target,
     63                         const Label& default_toolchain,
     64                         std::set<const Target*>* seen_targets,
     65                         int indent_level) {
     66   // Combine all deps into one sorted list.
     67   std::vector<LabelTargetPair> sorted_deps;
     68   for (DepsIterator iter(target); !iter.done(); iter.Advance())
     69     sorted_deps.push_back(iter.pair());
     70   std::sort(sorted_deps.begin(), sorted_deps.end(),
     71             LabelPtrLabelLess<Target>());
     72 
     73   std::string indent(indent_level * 2, ' ');
     74   for (size_t i = 0; i < sorted_deps.size(); i++) {
     75     const Target* cur_dep = sorted_deps[i].ptr;
     76 
     77     OutputString(indent +
     78         cur_dep->label().GetUserVisibleName(default_toolchain));
     79     bool print_children = true;
     80     if (seen_targets) {
     81       if (seen_targets->find(cur_dep) == seen_targets->end()) {
     82         // New target, mark it visited.
     83         seen_targets->insert(cur_dep);
     84       } else {
     85         // Already seen.
     86         print_children = false;
     87         // Only print "..." if something is actually elided, which means that
     88         // the current target has children.
     89         if (!cur_dep->public_deps().empty() ||
     90             !cur_dep->private_deps().empty() ||
     91             !cur_dep->data_deps().empty())
     92           OutputString("...");
     93       }
     94     }
     95 
     96     OutputString("\n");
     97     if (print_children) {
     98       RecursivePrintDeps(cur_dep, default_toolchain, seen_targets,
     99                          indent_level + 1);
    100     }
    101   }
    102 }
    103 
    104 void PrintDeps(const Target* target, bool display_header) {
    105   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
    106   Label toolchain_label = target->label().GetToolchainLabel();
    107 
    108   // Tree mode is separate.
    109   if (cmdline->HasSwitch("tree")) {
    110     if (display_header)
    111       OutputString("\nDependency tree:\n");
    112 
    113     if (cmdline->HasSwitch("all")) {
    114       // Show all tree deps with no eliding.
    115       RecursivePrintDeps(target, toolchain_label, NULL, 1);
    116     } else {
    117       // Don't recurse into duplicates.
    118       std::set<const Target*> seen_targets;
    119       RecursivePrintDeps(target, toolchain_label, &seen_targets, 1);
    120     }
    121     return;
    122   }
    123 
    124   // Collect the deps to display.
    125   std::vector<Label> deps;
    126   if (cmdline->HasSwitch("all")) {
    127     // Show all dependencies.
    128     if (display_header)
    129       OutputString("\nAll recursive dependencies:\n");
    130 
    131     std::set<Label> all_deps;
    132     RecursiveCollectChildDeps(target, &all_deps);
    133     for (std::set<Label>::iterator i = all_deps.begin();
    134          i != all_deps.end(); ++i)
    135       deps.push_back(*i);
    136   } else {
    137     // Show direct dependencies only.
    138     if (display_header) {
    139       OutputString(
    140           "\nDirect dependencies "
    141           "(try also \"--all\", \"--tree\", or even \"--all --tree\"):\n");
    142     }
    143     for (DepsIterator iter(target); !iter.done(); iter.Advance())
    144       deps.push_back(iter.label());
    145   }
    146 
    147   std::sort(deps.begin(), deps.end());
    148   for (size_t i = 0; i < deps.size(); i++)
    149     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
    150 }
    151 
    152 void PrintForwardDependentConfigsFrom(const Target* target,
    153                                       bool display_header) {
    154   if (target->forward_dependent_configs().empty())
    155     return;
    156 
    157   if (display_header)
    158     OutputString("\nforward_dependent_configs_from:\n");
    159 
    160   // Collect the sorted list of deps.
    161   std::vector<Label> forward;
    162   for (size_t i = 0; i < target->forward_dependent_configs().size(); i++)
    163     forward.push_back(target->forward_dependent_configs()[i].label);
    164   std::sort(forward.begin(), forward.end());
    165 
    166   Label toolchain_label = target->label().GetToolchainLabel();
    167   for (size_t i = 0; i < forward.size(); i++)
    168     OutputString("  " + forward[i].GetUserVisibleName(toolchain_label) + "\n");
    169 }
    170 
    171 // libs and lib_dirs are special in that they're inherited. We don't currently
    172 // implement a blame feature for this since the bottom-up inheritance makes
    173 // this difficult.
    174 void PrintLibDirs(const Target* target, bool display_header) {
    175   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
    176   if (lib_dirs.empty())
    177     return;
    178 
    179   if (display_header)
    180     OutputString("\nlib_dirs\n");
    181 
    182   for (size_t i = 0; i < lib_dirs.size(); i++)
    183     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
    184 }
    185 
    186 void PrintLibs(const Target* target, bool display_header) {
    187   const OrderedSet<std::string>& libs = target->all_libs();
    188   if (libs.empty())
    189     return;
    190 
    191   if (display_header)
    192     OutputString("\nlibs\n");
    193 
    194   for (size_t i = 0; i < libs.size(); i++)
    195     OutputString("    " + libs[i] + "\n");
    196 }
    197 
    198 void PrintPublic(const Target* target, bool display_header) {
    199   if (display_header)
    200     OutputString("\npublic:\n");
    201 
    202   if (target->all_headers_public()) {
    203     OutputString("  [All headers listed in the sources are public.]\n");
    204     return;
    205   }
    206 
    207   Target::FileList public_headers = target->public_headers();
    208   std::sort(public_headers.begin(), public_headers.end());
    209   for (size_t i = 0; i < public_headers.size(); i++)
    210     OutputString("  " + public_headers[i].value() + "\n");
    211 }
    212 
    213 void PrintCheckIncludes(const Target* target, bool display_header) {
    214   if (display_header)
    215     OutputString("\ncheck_includes:\n");
    216 
    217   if (target->check_includes())
    218     OutputString("  true\n");
    219   else
    220     OutputString("  false\n");
    221 }
    222 
    223 void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) {
    224   if (display_header)
    225     OutputString("\nallow_circular_includes_from:\n");
    226 
    227   Label toolchain_label = target->label().GetToolchainLabel();
    228   const std::set<Label>& allow = target->allow_circular_includes_from();
    229   for (std::set<Label>::const_iterator iter = allow.begin();
    230        iter != allow.end(); ++iter)
    231     OutputString("  " + iter->GetUserVisibleName(toolchain_label) + "\n");
    232 }
    233 
    234 void PrintVisibility(const Target* target, bool display_header) {
    235   if (display_header)
    236     OutputString("\nvisibility:\n");
    237 
    238   OutputString(target->visibility().Describe(2, false));
    239 }
    240 
    241 void PrintTestonly(const Target* target, bool display_header) {
    242   if (display_header)
    243     OutputString("\ntestonly:\n");
    244 
    245   if (target->testonly())
    246     OutputString("  true\n");
    247   else
    248     OutputString("  false\n");
    249 }
    250 
    251 void PrintConfigsVector(const Target* target,
    252                         const LabelConfigVector& configs,
    253                         const std::string& heading,
    254                         bool display_header) {
    255   if (configs.empty())
    256     return;
    257 
    258   // Don't sort since the order determines how things are processed.
    259   if (display_header)
    260     OutputString("\n" + heading + " (in order applying):\n");
    261 
    262   Label toolchain_label = target->label().GetToolchainLabel();
    263   for (size_t i = 0; i < configs.size(); i++) {
    264     OutputString("  " +
    265         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
    266   }
    267 }
    268 
    269 void PrintConfigsVector(const Target* target,
    270                         const UniqueVector<LabelConfigPair>& configs,
    271                         const std::string& heading,
    272                         bool display_header) {
    273   if (configs.empty())
    274     return;
    275 
    276   // Don't sort since the order determines how things are processed.
    277   if (display_header)
    278     OutputString("\n" + heading + " (in order applying):\n");
    279 
    280   Label toolchain_label = target->label().GetToolchainLabel();
    281   for (size_t i = 0; i < configs.size(); i++) {
    282     OutputString("  " +
    283         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
    284   }
    285 }
    286 
    287 void PrintConfigs(const Target* target, bool display_header) {
    288   PrintConfigsVector(target, target->configs().vector(), "configs",
    289                      display_header);
    290 }
    291 
    292 void PrintPublicConfigs(const Target* target, bool display_header) {
    293   PrintConfigsVector(target, target->public_configs(),
    294                      "public_configs", display_header);
    295 }
    296 
    297 void PrintAllDependentConfigs(const Target* target, bool display_header) {
    298   PrintConfigsVector(target, target->all_dependent_configs(),
    299                      "all_dependent_configs", display_header);
    300 }
    301 
    302 void PrintFileList(const Target::FileList& files,
    303                    const std::string& header,
    304                    bool indent_extra,
    305                    bool display_header) {
    306   if (files.empty())
    307     return;
    308 
    309   if (display_header)
    310     OutputString("\n" + header + ":\n");
    311 
    312   std::string indent = indent_extra ? "    " : "  ";
    313 
    314   Target::FileList sorted = files;
    315   std::sort(sorted.begin(), sorted.end());
    316   for (size_t i = 0; i < sorted.size(); i++)
    317     OutputString(indent + sorted[i].value() + "\n");
    318 }
    319 
    320 void PrintSources(const Target* target, bool display_header) {
    321   PrintFileList(target->sources(), "sources", false, display_header);
    322 }
    323 
    324 void PrintInputs(const Target* target, bool display_header) {
    325   PrintFileList(target->inputs(), "inputs", false, display_header);
    326 }
    327 
    328 void PrintOutputs(const Target* target, bool display_header) {
    329   if (display_header)
    330     OutputString("\noutputs:\n");
    331 
    332   if (target->output_type() == Target::ACTION) {
    333     // Action, print out outputs, don't apply sources to it.
    334     for (size_t i = 0; i < target->action_values().outputs().list().size();
    335          i++) {
    336       OutputString("  " +
    337                    target->action_values().outputs().list()[i].AsString() +
    338                    "\n");
    339     }
    340   } else {
    341     const SubstitutionList& outputs = target->action_values().outputs();
    342     if (!outputs.required_types().empty()) {
    343       // Display the pattern and resolved pattern separately, since there are
    344       // subtitutions used.
    345       OutputString("  Output pattern:\n");
    346       for (size_t i = 0; i < outputs.list().size(); i++)
    347         OutputString("    " + outputs.list()[i].AsString() + "\n");
    348 
    349       // Now display what that resolves to given the sources.
    350       OutputString("\n  Resolved output file list:\n");
    351     }
    352 
    353     // Resolved output list.
    354     std::vector<SourceFile> output_files;
    355     SubstitutionWriter::ApplyListToSources(target->settings(), outputs,
    356                                            target->sources(), &output_files);
    357     PrintFileList(output_files, "", true, false);
    358   }
    359 }
    360 
    361 void PrintScript(const Target* target, bool display_header) {
    362   if (display_header)
    363     OutputString("\nscript:\n");
    364   OutputString("  " + target->action_values().script().value() + "\n");
    365 }
    366 
    367 void PrintArgs(const Target* target, bool display_header) {
    368   if (display_header)
    369     OutputString("\nargs:\n");
    370   for (size_t i = 0; i < target->action_values().args().list().size(); i++) {
    371     OutputString("  " +
    372                  target->action_values().args().list()[i].AsString() + "\n");
    373   }
    374 }
    375 
    376 void PrintDepfile(const Target* target, bool display_header) {
    377   if (target->action_values().depfile().empty())
    378     return;
    379   if (display_header)
    380     OutputString("\ndepfile:\n");
    381   OutputString("  " + target->action_values().depfile().AsString() + "\n");
    382 }
    383 
    384 // Attribute the origin for attributing from where a target came from. Does
    385 // nothing if the input is null or it does not have a location.
    386 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
    387   if (!origin)
    388     return;
    389   Location location = origin->GetRange().begin();
    390   out << "       (Added by " + location.file()->name().value() << ":"
    391       << location.line_number() << ")\n";
    392 }
    393 
    394 // Templatized writer for writing out different config value types.
    395 template<typename T> struct DescValueWriter {};
    396 template<> struct DescValueWriter<std::string> {
    397   void operator()(const std::string& str, std::ostream& out) const {
    398     out << "    " << str << "\n";
    399   }
    400 };
    401 template<> struct DescValueWriter<SourceDir> {
    402   void operator()(const SourceDir& dir, std::ostream& out) const {
    403     out << "    " << FormatSourceDir(dir) << "\n";
    404   }
    405 };
    406 
    407 // Writes a given config value type to the string, optionally with attribution.
    408 // This should match RecursiveTargetConfigToStream in the order it traverses.
    409 template<typename T> void OutputRecursiveTargetConfig(
    410     const Target* target,
    411     const char* header_name,
    412     const std::vector<T>& (ConfigValues::* getter)() const) {
    413   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
    414 
    415   DescValueWriter<T> writer;
    416   std::ostringstream out;
    417 
    418   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
    419     if ((iter.cur().*getter)().empty())
    420       continue;
    421 
    422     // Optional blame sub-head.
    423     if (display_blame) {
    424       const Config* config = iter.GetCurrentConfig();
    425       if (config) {
    426         // Source of this value is a config.
    427         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
    428         OutputSourceOfDep(iter.origin(), out);
    429       } else {
    430         // Source of this value is the target itself.
    431         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
    432       }
    433     }
    434 
    435     // Actual values.
    436     ConfigValuesToStream(iter.cur(), getter, writer, out);
    437   }
    438 
    439   std::string out_str = out.str();
    440   if (!out_str.empty()) {
    441     OutputString("\n" + std::string(header_name) + "\n");
    442     OutputString(out_str);
    443   }
    444 }
    445 
    446 }  // namespace
    447 
    448 // desc ------------------------------------------------------------------------
    449 
    450 const char kDesc[] = "desc";
    451 const char kDesc_HelpShort[] =
    452     "desc: Show lots of insightful information about a target.";
    453 const char kDesc_Help[] =
    454     "gn desc <out_dir> <target label> [<what to show>]\n"
    455     "        [--blame] [--all | --tree]\n"
    456     "\n"
    457     "  Displays information about a given labeled target for the given build.\n"
    458     "  The build parameters will be taken for the build in the given\n"
    459     "  <out_dir>.\n"
    460     "\n"
    461     "Possibilities for <what to show>:\n"
    462     "  (If unspecified an overall summary will be displayed.)\n"
    463     "\n"
    464     "  sources\n"
    465     "      Source files.\n"
    466     "\n"
    467     "  inputs\n"
    468     "      Additional input dependencies.\n"
    469     "\n"
    470     "  public\n"
    471     "      Public header files.\n"
    472     "\n"
    473     "  check_includes\n"
    474     "      Whether \"gn check\" checks this target for include usage.\n"
    475     "\n"
    476     "  allow_circular_includes_from\n"
    477     "      Permit includes from these targets.\n"
    478     "\n"
    479     "  visibility\n"
    480     "      Prints which targets can depend on this one.\n"
    481     "\n"
    482     "  testonly\n"
    483     "      Whether this target may only be used in tests.\n"
    484     "\n"
    485     "  configs\n"
    486     "      Shows configs applied to the given target, sorted in the order\n"
    487     "      they're specified. This includes both configs specified in the\n"
    488     "      \"configs\" variable, as well as configs pushed onto this target\n"
    489     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
    490     "      configs.\n"
    491     "\n"
    492     "  deps [--all | --tree]\n"
    493     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
    494     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
    495     "      in a tree format with duplicates elided (noted by \"...\").\n"
    496     "      \"--all\" shows them sorted alphabetically. Using both flags will\n"
    497     "      print a tree with no omissions. The \"deps\", \"public_deps\", and\n"
    498     "      \"data_deps\" will all be included.\n"
    499     "\n"
    500     "  public_configs\n"
    501     "  all_dependent_configs\n"
    502     "      Shows the labels of configs applied to targets that depend on this\n"
    503     "      one (either directly or all of them).\n"
    504     "\n"
    505     "  forward_dependent_configs_from\n"
    506     "      Shows the labels of dependencies for which dependent configs will\n"
    507     "      be pushed to targets depending on the current one.\n"
    508     "\n"
    509     "  script\n"
    510     "  args\n"
    511     "  depfile\n"
    512     "      Actions only. The script and related values.\n"
    513     "\n"
    514     "  outputs\n"
    515     "      Outputs for script and copy target types.\n"
    516     "\n"
    517     "  defines       [--blame]\n"
    518     "  include_dirs  [--blame]\n"
    519     "  cflags        [--blame]\n"
    520     "  cflags_cc     [--blame]\n"
    521     "  cflags_cxx    [--blame]\n"
    522     "  ldflags       [--blame]\n"
    523     "  lib_dirs\n"
    524     "  libs\n"
    525     "      Shows the given values taken from the target and all configs\n"
    526     "      applying. See \"--blame\" below.\n"
    527     "\n"
    528     "  --blame\n"
    529     "      Used with any value specified by a config, this will name\n"
    530     "      the config that specified the value. This doesn't currently work\n"
    531     "      for libs and lib_dirs because those are inherited and are more\n"
    532     "      complicated to figure out the blame (patches welcome).\n"
    533     "\n"
    534     "Note:\n"
    535     "  This command will show the full name of directories and source files,\n"
    536     "  but when directories and source paths are written to the build file,\n"
    537     "  they will be adjusted to be relative to the build directory. So the\n"
    538     "  values for paths displayed by this command won't match (but should\n"
    539     "  mean the same thing).\n"
    540     "\n"
    541     "Examples:\n"
    542     "  gn desc out/Debug //base:base\n"
    543     "      Summarizes the given target.\n"
    544     "\n"
    545     "  gn desc out/Foo :base_unittests deps --tree\n"
    546     "      Shows a dependency tree of the \"base_unittests\" project in\n"
    547     "      the current directory.\n"
    548     "\n"
    549     "  gn desc out/Debug //base defines --blame\n"
    550     "      Shows defines set for the //base:base target, annotated by where\n"
    551     "      each one was set from.\n";
    552 
    553 #define OUTPUT_CONFIG_VALUE(name, type) \
    554     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
    555 
    556 int RunDesc(const std::vector<std::string>& args) {
    557   if (args.size() != 2 && args.size() != 3) {
    558     Err(Location(), "You're holding it wrong.",
    559         "Usage: \"gn desc <out_dir> <target_name> [<what to display>]\"")
    560         .PrintToStdout();
    561     return 1;
    562   }
    563 
    564   // Deliberately leaked to avoid expensive process teardown.
    565   Setup* setup = new Setup;
    566   if (!setup->DoSetup(args[0], false))
    567     return 1;
    568   if (!setup->Run())
    569     return 1;
    570 
    571   const Target* target = ResolveTargetFromCommandLineString(setup, args[1]);
    572   if (!target)
    573     return 1;
    574 
    575 #define CONFIG_VALUE_HANDLER(name, type) \
    576     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
    577 
    578   if (args.size() == 3) {
    579     // User specified one thing to display.
    580     const std::string& what = args[2];
    581     if (what == variables::kConfigs) {
    582       PrintConfigs(target, false);
    583     } else if (what == variables::kPublicConfigs) {
    584       PrintPublicConfigs(target, false);
    585     } else if (what == variables::kAllDependentConfigs) {
    586       PrintAllDependentConfigs(target, false);
    587     } else if (what == variables::kForwardDependentConfigsFrom) {
    588       PrintForwardDependentConfigsFrom(target, false);
    589     } else if (what == variables::kSources) {
    590       PrintSources(target, false);
    591     } else if (what == variables::kPublic) {
    592       PrintPublic(target, false);
    593     } else if (what == variables::kCheckIncludes) {
    594       PrintCheckIncludes(target, false);
    595     } else if (what == variables::kAllowCircularIncludesFrom) {
    596       PrintAllowCircularIncludesFrom(target, false);
    597     } else if (what == variables::kVisibility) {
    598       PrintVisibility(target, false);
    599     } else if (what == variables::kTestonly) {
    600       PrintTestonly(target, false);
    601     } else if (what == variables::kInputs) {
    602       PrintInputs(target, false);
    603     } else if (what == variables::kScript) {
    604       PrintScript(target, false);
    605     } else if (what == variables::kArgs) {
    606       PrintArgs(target, false);
    607     } else if (what == variables::kDepfile) {
    608       PrintDepfile(target, false);
    609     } else if (what == variables::kOutputs) {
    610       PrintOutputs(target, false);
    611     } else if (what == variables::kDeps) {
    612       PrintDeps(target, false);
    613     } else if (what == variables::kLibDirs) {
    614       PrintLibDirs(target, false);
    615     } else if (what == variables::kLibs) {
    616       PrintLibs(target, false);
    617 
    618     CONFIG_VALUE_HANDLER(defines, std::string)
    619     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
    620     CONFIG_VALUE_HANDLER(cflags, std::string)
    621     CONFIG_VALUE_HANDLER(cflags_c, std::string)
    622     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
    623     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
    624     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
    625     CONFIG_VALUE_HANDLER(ldflags, std::string)
    626 
    627     } else {
    628       OutputString("Don't know how to display \"" + what + "\".\n");
    629       return 1;
    630     }
    631 
    632 #undef CONFIG_VALUE_HANDLER
    633     return 0;
    634   }
    635 
    636   // Display summary.
    637 
    638   // Display this only applicable to binary targets.
    639   bool is_binary_output =
    640     target->output_type() != Target::GROUP &&
    641     target->output_type() != Target::COPY_FILES &&
    642     target->output_type() != Target::ACTION &&
    643     target->output_type() != Target::ACTION_FOREACH;
    644 
    645   // Generally we only want to display toolchains on labels when the toolchain
    646   // is different than the default one for this target (which we always print
    647   // in the header).
    648   Label target_toolchain = target->label().GetToolchainLabel();
    649 
    650   // Header.
    651   OutputString("Target: ", DECORATION_YELLOW);
    652   OutputString(target->label().GetUserVisibleName(false) + "\n");
    653   OutputString("Type: ", DECORATION_YELLOW);
    654   OutputString(std::string(
    655       Target::GetStringForOutputType(target->output_type())) + "\n");
    656   OutputString("Toolchain: ", DECORATION_YELLOW);
    657   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
    658 
    659   PrintSources(target, true);
    660   if (is_binary_output) {
    661     PrintPublic(target, true);
    662     PrintCheckIncludes(target, true);
    663     PrintAllowCircularIncludesFrom(target, true);
    664   }
    665   PrintVisibility(target, true);
    666   if (is_binary_output) {
    667     PrintTestonly(target, true);
    668     PrintConfigs(target, true);
    669   }
    670 
    671   PrintPublicConfigs(target, true);
    672   PrintAllDependentConfigs(target, true);
    673   PrintForwardDependentConfigsFrom(target, true);
    674 
    675   PrintInputs(target, true);
    676 
    677   if (is_binary_output) {
    678     OUTPUT_CONFIG_VALUE(defines, std::string)
    679     OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
    680     OUTPUT_CONFIG_VALUE(cflags, std::string)
    681     OUTPUT_CONFIG_VALUE(cflags_c, std::string)
    682     OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
    683     OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
    684     OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
    685     OUTPUT_CONFIG_VALUE(ldflags, std::string)
    686   }
    687 
    688   if (target->output_type() == Target::ACTION ||
    689       target->output_type() == Target::ACTION_FOREACH) {
    690     PrintScript(target, true);
    691     PrintArgs(target, true);
    692     PrintDepfile(target, true);
    693   }
    694 
    695   if (target->output_type() == Target::ACTION ||
    696       target->output_type() == Target::ACTION_FOREACH ||
    697       target->output_type() == Target::COPY_FILES) {
    698     PrintOutputs(target, true);
    699   }
    700 
    701   // Libs can be part of any target and get recursively pushed up the chain,
    702   // so always display them, even for groups and such.
    703   PrintLibs(target, true);
    704   PrintLibDirs(target, true);
    705 
    706   PrintDeps(target, true);
    707 
    708   return 0;
    709 }
    710 
    711 }  // namespace commands
    712