| Index: tools/gn/command_desc.cc | 
| diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc | 
| index 021232c1243c139f7e643d0d02a63f7ee04dd4eb..f2371e9d7cb5a8591681819956cf39309e925b4f 100644 | 
| --- a/tools/gn/command_desc.cc | 
| +++ b/tools/gn/command_desc.cc | 
| @@ -21,6 +21,7 @@ | 
| #include "tools/gn/setup.h" | 
| #include "tools/gn/standard_out.h" | 
| #include "tools/gn/substitution_writer.h" | 
| +#include "tools/gn/switches.h" | 
| #include "tools/gn/target.h" | 
| #include "tools/gn/variables.h" | 
|  | 
| @@ -119,7 +120,7 @@ void PrintDeps(const Target* target, bool display_header) { | 
| // Tree mode is separate. | 
| if (cmdline->HasSwitch(kTree)) { | 
| if (display_header) | 
| -      OutputString("\nDependency tree:\n"); | 
| +      OutputString("\nDependency tree\n"); | 
|  | 
| if (cmdline->HasSwitch("all")) { | 
| // Show all tree deps with no eliding. | 
| @@ -136,7 +137,7 @@ void PrintDeps(const Target* target, bool display_header) { | 
| if (cmdline->HasSwitch("all")) { | 
| // Show all dependencies. | 
| if (display_header) | 
| -      OutputString("\nAll recursive dependencies:\n"); | 
| +      OutputString("\nAll recursive dependencies\n"); | 
|  | 
| std::set<const Target*> all_deps; | 
| RecursiveCollectChildDeps(target, &all_deps); | 
| @@ -147,7 +148,7 @@ void PrintDeps(const Target* target, bool display_header) { | 
| if (display_header) { | 
| OutputString( | 
| "\nDirect dependencies " | 
| -          "(try also \"--all\", \"--tree\", or even \"--all --tree\"):\n"); | 
| +          "(try also \"--all\", \"--tree\", or even \"--all --tree\")\n"); | 
| } | 
| for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) | 
| deps.push_back(pair.ptr); | 
| @@ -185,7 +186,7 @@ void PrintLibs(const Target* target, bool display_header) { | 
|  | 
| void PrintPublic(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\npublic:\n"); | 
| +    OutputString("\npublic\n"); | 
|  | 
| if (target->all_headers_public()) { | 
| OutputString("  [All headers listed in the sources are public.]\n"); | 
| @@ -200,7 +201,7 @@ void PrintPublic(const Target* target, bool display_header) { | 
|  | 
| void PrintCheckIncludes(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\ncheck_includes:\n"); | 
| +    OutputString("\ncheck_includes\n"); | 
|  | 
| if (target->check_includes()) | 
| OutputString("  true\n"); | 
| @@ -210,7 +211,7 @@ void PrintCheckIncludes(const Target* target, bool display_header) { | 
|  | 
| void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\nallow_circular_includes_from:\n"); | 
| +    OutputString("\nallow_circular_includes_from\n"); | 
|  | 
| Label toolchain_label = target->label().GetToolchainLabel(); | 
| for (const auto& cur : target->allow_circular_includes_from()) | 
| @@ -219,14 +220,14 @@ void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) { | 
|  | 
| void PrintVisibility(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\nvisibility:\n"); | 
| +    OutputString("\nvisibility\n"); | 
|  | 
| OutputString(target->visibility().Describe(2, false)); | 
| } | 
|  | 
| void PrintTestonly(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\ntestonly:\n"); | 
| +    OutputString("\ntestonly\n"); | 
|  | 
| if (target->testonly()) | 
| OutputString("  true\n"); | 
| @@ -251,7 +252,7 @@ void PrintSubConfigs(const Config* config, int indent_level) { | 
| // This allows configs stored as either std::vector<LabelConfigPair> or | 
| // UniqueVector<LabelConfigPair> to be printed. | 
| template <class VectorType> | 
| -void PrintConfigsVector(const Target* target, | 
| +void PrintConfigsVector(const Item* item, | 
| const VectorType& configs, | 
| const std::string& heading, | 
| bool display_header) { | 
| @@ -263,12 +264,12 @@ void PrintConfigsVector(const Target* target, | 
| // Don't sort since the order determines how things are processed. | 
| if (display_header) { | 
| if (tree) | 
| -      OutputString("\n" + heading + " tree (in order applying):\n"); | 
| +      OutputString("\n" + heading + " tree (in order applying)\n"); | 
| else | 
| -      OutputString("\n" + heading + " (in order applying, try also --tree):\n"); | 
| +      OutputString("\n" + heading + " (in order applying, try also --tree)\n"); | 
| } | 
|  | 
| -  Label toolchain_label = target->label().GetToolchainLabel(); | 
| +  Label toolchain_label = item->label().GetToolchainLabel(); | 
| for (const auto& config : configs) { | 
| OutputString("  " + config.label.GetUserVisibleName(toolchain_label) + | 
| "\n"); | 
| @@ -282,6 +283,11 @@ void PrintConfigs(const Target* target, bool display_header) { | 
| display_header); | 
| } | 
|  | 
| +void PrintConfigs(const Config* config, bool display_header) { | 
| +  PrintConfigsVector(config, config->configs().vector(), "configs", | 
| +                     display_header); | 
| +} | 
| + | 
| void PrintPublicConfigs(const Target* target, bool display_header) { | 
| PrintConfigsVector(target, target->public_configs(), | 
| "public_configs", display_header); | 
| @@ -300,7 +306,7 @@ void PrintFileList(const Target::FileList& files, | 
| return; | 
|  | 
| if (display_header) | 
| -    OutputString("\n" + header + ":\n"); | 
| +    OutputString("\n" + header + "\n"); | 
|  | 
| std::string indent = indent_extra ? "    " : "  "; | 
|  | 
| @@ -320,7 +326,7 @@ void PrintInputs(const Target* target, bool display_header) { | 
|  | 
| void PrintOutputs(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\noutputs:\n"); | 
| +    OutputString("\noutputs\n"); | 
|  | 
| if (target->output_type() == Target::ACTION) { | 
| // Action, print out outputs, don't apply sources to it. | 
| @@ -337,12 +343,12 @@ void PrintOutputs(const Target* target, bool display_header) { | 
| if (!outputs.required_types().empty()) { | 
| // Display the pattern and resolved pattern separately, since there are | 
| // subtitutions used. | 
| -      OutputString("  Output pattern:\n"); | 
| +      OutputString("  Output pattern\n"); | 
| for (const auto& elem : outputs.list()) | 
| OutputString("    " + elem.AsString() + "\n"); | 
|  | 
| // Now display what that resolves to given the sources. | 
| -      OutputString("\n  Resolved output file list:\n"); | 
| +      OutputString("\n  Resolved output file list\n"); | 
| } | 
|  | 
| // Resolved output list. | 
| @@ -355,13 +361,13 @@ void PrintOutputs(const Target* target, bool display_header) { | 
|  | 
| void PrintScript(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\nscript:\n"); | 
| +    OutputString("\nscript\n"); | 
| OutputString("  " + target->action_values().script().value() + "\n"); | 
| } | 
|  | 
| void PrintArgs(const Target* target, bool display_header) { | 
| if (display_header) | 
| -    OutputString("\nargs:\n"); | 
| +    OutputString("\nargs\n"); | 
| for (const auto& elem : target->action_values().args().list()) { | 
| OutputString("  " + elem.AsString() + "\n"); | 
| } | 
| @@ -371,7 +377,7 @@ void PrintDepfile(const Target* target, bool display_header) { | 
| if (target->action_values().depfile().empty()) | 
| return; | 
| if (display_header) | 
| -    OutputString("\ndepfile:\n"); | 
| +    OutputString("\ndepfile\n"); | 
| OutputString("  " + target->action_values().depfile().AsString() + "\n"); | 
| } | 
|  | 
| @@ -392,12 +398,22 @@ template<> struct DescValueWriter<std::string> { | 
| out << "    " << str << "\n"; | 
| } | 
| }; | 
| + | 
| template<> struct DescValueWriter<SourceDir> { | 
| void operator()(const SourceDir& dir, std::ostream& out) const { | 
| out << "    " << FormatSourceDir(dir) << "\n"; | 
| } | 
| }; | 
|  | 
| +template<> struct DescValueWriter<LibFile> { | 
| +  void operator()(const LibFile& lib, std::ostream& out) const { | 
| +    if (lib.is_source_file()) | 
| +      out << "    " << lib.source_file().value() << "\n"; | 
| +    else | 
| +      out << "    " << lib.value() << "\n"; | 
| +  } | 
| +}; | 
| + | 
| // Writes a given config value type to the string, optionally with attribution. | 
| // This should match RecursiveTargetConfigToStream in the order it traverses. | 
| template<typename T> void OutputRecursiveTargetConfig( | 
| @@ -433,7 +449,26 @@ template<typename T> void OutputRecursiveTargetConfig( | 
|  | 
| std::string out_str = out.str(); | 
| if (!out_str.empty()) { | 
| -    OutputString("\n" + std::string(header_name) + "\n"); | 
| +    if (header_name) | 
| +      OutputString("\n" + std::string(header_name) + "\n"); | 
| +    OutputString(out_str); | 
| +  } | 
| +} | 
| + | 
| +template<typename T> void OutputConfigValueArray( | 
| +    const ConfigValues& values, | 
| +    const char* header_name, | 
| +    const std::vector<T>& (ConfigValues::* getter)() const) { | 
| +  std::ostringstream out; | 
| + | 
| +  DescValueWriter<T> writer; | 
| +  for (const T& cur : (values.*getter)()) | 
| +    writer(cur, out); | 
| + | 
| +  std::string out_str = out.str(); | 
| +  if (!out_str.empty()) { | 
| +    if (header_name) | 
| +      OutputString("\n" + std::string(header_name) + "\n"); | 
| OutputString(out_str); | 
| } | 
| } | 
| @@ -462,79 +497,295 @@ void PrintRuntimeDeps(const Target* target) { | 
| } | 
| } | 
|  | 
| +// If "what" is empty, prints all PCH info. If "what" is nonempty, prints only | 
| +// the things that match (if any). Returns true if anything was printed. | 
| +bool PrintPrecompiledHeaderInfo(const ConfigValues& values, | 
| +                                const std::string& what, | 
| +                                bool display_headers) { | 
| +  bool found_match = false; | 
| +  if (what == variables::kPrecompiledHeader || what.empty()) { | 
| +    if (!values.precompiled_header().empty()) { | 
| +      if (display_headers) | 
| +        OutputString("\nprecompiled_header\n"); | 
| +      OutputString(values.precompiled_header() + "\n"); | 
| +    } | 
| +    found_match = true; | 
| +  } | 
| +  if (what == variables::kPrecompiledSource || what.empty()) { | 
| +    if (!values.precompiled_source().is_null()) { | 
| +      if (display_headers) | 
| +        OutputString("\nprecompiled_source\n"); | 
| +      OutputString(values.precompiled_source().value() + "\n"); | 
| +    } | 
| +    found_match = true; | 
| +  } | 
| +  return found_match; | 
| +} | 
| + | 
| +bool PrintTarget(const Target* target, | 
| +                 const std::string& what, | 
| +                 bool display_target_header) { | 
| +  if (display_target_header) { | 
| +    OutputString("Target: ", DECORATION_YELLOW); | 
| +    OutputString(target->label().GetUserVisibleName(false) + "\n"); | 
| +    OutputString("Type: ", DECORATION_YELLOW); | 
| +    OutputString(std::string( | 
| +        Target::GetStringForOutputType(target->output_type())) + "\n"); | 
| +    OutputString("Toolchain: ", DECORATION_YELLOW); | 
| +    OutputString( | 
| +        target->label().GetToolchainLabel().GetUserVisibleName(false) + "\n"); | 
| +  } | 
| + | 
| +  // Display headers when outputting everything. | 
| +  bool display_headers = what.empty(); | 
| +  bool is_binary_output = target->IsBinary(); | 
| + | 
| +  bool found_match = false; | 
| + | 
| +  // General target meta variables. | 
| +  if (what.empty() || what == variables::kVisibility) { | 
| +    PrintVisibility(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| +  if (what.empty() || what == variables::kTestonly) { | 
| +    PrintTestonly(target, display_headers); | 
| +    found_match  = true; | 
| +  } | 
| + | 
| +  // Binary target meta variables. | 
| +  if (is_binary_output) { | 
| +    if (what.empty() || what == variables::kCheckIncludes) { | 
| +      PrintCheckIncludes(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +    if (what.empty() || what == variables::kAllowCircularIncludesFrom) { | 
| +      PrintAllowCircularIncludesFrom(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +  } | 
| + | 
| +  // Sources and inputs. | 
| +  if (what.empty() || what == variables::kSources) { | 
| +    PrintSources(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| +  if (what.empty() || what == variables::kPublic) { | 
| +    PrintPublic(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| +  if (what.empty() || what == variables::kInputs) { | 
| +    PrintInputs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  // Configs. Configs set directly on a target are only relevant for binary | 
| +  // targets | 
| +  if (is_binary_output && (what.empty() || what == variables::kConfigs)) { | 
| +    PrintConfigs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  // Dependent/public configs can be applied to anything. | 
| +  if (what.empty() || what == variables::kPublicConfigs) { | 
| +    PrintPublicConfigs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| +  if (what.empty() || what == variables::kAllDependentConfigs) { | 
| +    PrintAllDependentConfigs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  // Action values. | 
| +  if (target->output_type() == Target::ACTION || | 
| +      target->output_type() == Target::ACTION_FOREACH) { | 
| +    if (what.empty() || what == variables::kScript) { | 
| +      PrintScript(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +    if (what.empty() || what == variables::kArgs) { | 
| +      PrintArgs(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +    if (what.empty() || what == variables::kDepfile) { | 
| +      PrintDepfile(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +  } | 
| + | 
| +  // Outputs. | 
| +  if (target->output_type() == Target::ACTION || | 
| +      target->output_type() == Target::ACTION_FOREACH || | 
| +      target->output_type() == Target::COPY_FILES || | 
| +      target->output_type() == Target::CREATE_BUNDLE) { | 
| +    if (what.empty() || what == variables::kOutputs) { | 
| +      PrintOutputs(target, display_headers); | 
| +      found_match = true; | 
| +    } | 
| +  } | 
| + | 
| +  // Values from configs only apply to binary targets. | 
| +  if (is_binary_output) { | 
| +    #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \ | 
| +      if (what.empty() || what == #name) { \ | 
| +        OutputRecursiveTargetConfig<type>( \ | 
| +            target, display_headers ? #name : nullptr, &ConfigValues::name); \ | 
| +        found_match = true; \ | 
| +      } | 
| + | 
| +    CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(defines, std::string) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir) | 
| +    CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string) | 
| +    // Libs and lib_dirs are handled specially below. | 
| + | 
| +    #undef CONFIG_VALUE_ARRAY_HANDLER | 
| + | 
| +    found_match |= PrintPrecompiledHeaderInfo(target->config_values(), | 
| +                                              what, display_headers); | 
| +  } | 
| + | 
| +  // Deps | 
| +  if (what.empty() || what == "deps") { | 
| +    PrintDeps(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  // Runtime deps are special, print only when explicitly asked for and not in | 
| +  // overview mode. | 
| +  if (what == "runtime_deps") { | 
| +    PrintRuntimeDeps(target); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  // Libs can be part of any target and get recursively pushed up the chain, | 
| +  // so display them regardless of target type. | 
| +  if (what.empty() || what == variables::kLibs) { | 
| +    PrintLibs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| +  if (what.empty() || what == variables::kLibDirs) { | 
| +    PrintLibDirs(target, display_headers); | 
| +    found_match = true; | 
| +  } | 
| + | 
| +  if (!found_match) { | 
| +    OutputString("Don't know how to display \"" + what + "\" for \"" + | 
| +        Target::GetStringForOutputType(target->output_type()) + "\".\n"); | 
| +    return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| +bool PrintConfig(const Config* config, | 
| +                 const std::string& what, | 
| +                 bool display_config_header) { | 
| +  const ConfigValues& values = config->resolved_values(); | 
| + | 
| +  if (display_config_header) { | 
| +    OutputString("Config: ", DECORATION_YELLOW); | 
| +    OutputString(config->label().GetUserVisibleName(false) + "\n"); | 
| +    OutputString("Toolchain: ", DECORATION_YELLOW); | 
| +    OutputString( | 
| +        config->label().GetToolchainLabel().GetUserVisibleName(false) + "\n"); | 
| +    if (what.empty() && !config->configs().empty()) { | 
| +      OutputString( | 
| +          "(This is a composite config, the values below are after the\n" | 
| +          "expansion of the child configs.)\n"); | 
| +    } | 
| +  } | 
| + | 
| +  // Display headers when outputting everything. | 
| +  bool display_headers = what.empty(); | 
| + | 
| +  if (what.empty() || what == variables::kConfigs) | 
| +    PrintConfigs(config, display_headers); | 
| + | 
| +#define CONFIG_VALUE_ARRAY_HANDLER(name, type) \ | 
| +  if (what.empty() || what == #name) { \ | 
| +    OutputConfigValueArray<type>(values, display_headers ? #name : nullptr, \ | 
| +                                 &ConfigValues::name); \ | 
| +    found_match = true; \ | 
| +  } | 
| + | 
| +  bool found_match = false; | 
| + | 
| +  CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(defines, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir) | 
| +  CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile) | 
| + | 
| +#undef CONFIG_VALUE_ARRAY_HANDLER | 
| + | 
| +  // Handles all PCH-related variables. | 
| +  found_match |= PrintPrecompiledHeaderInfo(config->resolved_values(), | 
| +                                            what, display_headers); | 
| + | 
| +  if (!found_match) { | 
| +    OutputString("Don't know how to display \"" + what + "\" for a config.\n"); | 
| +    return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| }  // namespace | 
|  | 
| // desc ------------------------------------------------------------------------ | 
|  | 
| const char kDesc[] = "desc"; | 
| const char kDesc_HelpShort[] = | 
| -    "desc: Show lots of insightful information about a target."; | 
| +    "desc: Show lots of insightful information about a target or config."; | 
| const char kDesc_Help[] = | 
| -    "gn desc <out_dir> <target label> [<what to show>] [--blame]\n" | 
| +    "gn desc <out_dir> <label or pattern> [<what to show>] [--blame]\n" | 
| "\n" | 
| -    "  Displays information about a given labeled target for the given build.\n" | 
| -    "  The build parameters will be taken for the build in the given\n" | 
| -    "  <out_dir>.\n" | 
| +    "  Displays information about a given target or config. The build\n" | 
| +    "  build parameters will be taken for the build in the given <out_dir>.\n" | 
| "\n" | 
| -    "Possibilities for <what to show>\n" | 
| -    "  (If unspecified an overall summary will be displayed.)\n" | 
| -    "\n" | 
| -    "  sources\n" | 
| -    "      Source files.\n" | 
| -    "\n" | 
| -    "  inputs\n" | 
| -    "      Additional input dependencies.\n" | 
| +    "  The <label or pattern> can be a target label, a config label, or a\n" | 
| +    "  label pattern (see \"gn help label_pattern\"). A label pattern will\n" | 
| +    "  only match targets.\n" | 
| "\n" | 
| -    "  public\n" | 
| -    "      Public header files.\n" | 
| -    "\n" | 
| -    "  check_includes\n" | 
| -    "      Whether \"gn check\" checks this target for include usage.\n" | 
| -    "\n" | 
| -    "  allow_circular_includes_from\n" | 
| -    "      Permit includes from these targets.\n" | 
| -    "\n" | 
| -    "  visibility\n" | 
| -    "      Prints which targets can depend on this one.\n" | 
| -    "\n" | 
| -    "  testonly\n" | 
| -    "      Whether this target may only be used in tests.\n" | 
| -    "\n" | 
| -    "  configs\n" | 
| -    "      Shows configs applied to the given target, sorted in the order\n" | 
| -    "      they're specified. This includes both configs specified in the\n" | 
| -    "      \"configs\" variable, as well as configs pushed onto this target\n" | 
| -    "      via dependencies specifying \"all\" or \"direct\" dependent\n" | 
| -    "      configs.\n" | 
| +    "Possibilities for <what to show>\n" | 
| "\n" | 
| -    "  deps\n" | 
| -    "      Show immediate or recursive dependencies. See below for flags that\n" | 
| -    "      control deps printing.\n" | 
| +    "  (If unspecified an overall summary will be displayed.)\n" | 
| "\n" | 
| -    "  public_configs\n" | 
| "  all_dependent_configs\n" | 
| -    "      Shows the labels of configs applied to targets that depend on this\n" | 
| -    "      one (either directly or all of them).\n" | 
| -    "\n" | 
| -    "  script\n" | 
| +    "  allow_circular_includes_from\n" | 
| +    "  arflags [--blame]\n" | 
| "  args\n" | 
| +    "  cflags [--blame]\n" | 
| +    "  cflags_cc [--blame]\n" | 
| +    "  cflags_cxx [--blame]\n" | 
| +    "  check_includes\n" | 
| +    "  configs [--tree] (see below)\n" | 
| +    "  defines [--blame]\n" | 
| "  depfile\n" | 
| -    "      Actions only. The script and related values.\n" | 
| -    "\n" | 
| -    "  outputs\n" | 
| -    "      Outputs for script and copy target types.\n" | 
| -    "\n" | 
| -    "  arflags       [--blame]\n" | 
| -    "  defines       [--blame]\n" | 
| -    "  include_dirs  [--blame]\n" | 
| -    "  cflags        [--blame]\n" | 
| -    "  cflags_cc     [--blame]\n" | 
| -    "  cflags_cxx    [--blame]\n" | 
| -    "  ldflags       [--blame]\n" | 
| +    "  deps [--all] [--tree] (see below)\n" | 
| +    "  include_dirs [--blame]\n" | 
| +    "  inputs\n" | 
| +    "  ldflags [--blame]\n" | 
| "  lib_dirs\n" | 
| "  libs\n" | 
| -    "      Shows the given values taken from the target and all configs\n" | 
| -    "      applying. See \"--blame\" below.\n" | 
| +    "  outputs\n" | 
| +    "  public_configs\n" | 
| +    "  public\n" | 
| +    "  script\n" | 
| +    "  sources\n" | 
| +    "  testonly\n" | 
| +    "  visibility\n" | 
| "\n" | 
| "  runtime_deps\n" | 
| "      Compute all runtime deps for the given target. This is a\n" | 
| @@ -548,13 +799,32 @@ const char kDesc_Help[] = | 
| "\n" | 
| "Shared flags\n" | 
| "\n" | 
| +    ALL_TOOLCHAINS_SWITCH_HELP | 
| +    "\n" | 
| +    "Target flags\n" | 
| +    "\n" | 
| "  --blame\n" | 
| -    "      Used with any value specified by a config, this will name\n" | 
| -    "      the config that specified the value. This doesn't currently work\n" | 
| -    "      for libs and lib_dirs because those are inherited and are more\n" | 
| -    "      complicated to figure out the blame (patches welcome).\n" | 
| +    "      Used with any value specified on a config, this will name\n" | 
| +    "      the config that cause that target to get the flag. This doesn't\n" | 
| +    "      currently work for libs and lib_dirs because those are inherited\n" | 
| +    "      and are more complicated to figure out the blame (patches\n" | 
| +    "      welcome).\n" | 
| "\n" | 
| -    "Flags that control how deps are printed\n" | 
| +    "Configs\n" | 
| +    "\n" | 
| +    "  The \"configs\" section will list all configs that apply. For targets\n" | 
| +    "  this will include configs specified in the \"configs\" variable of\n" | 
| +    "  the target, and also configs pushed onto this target via public\n" | 
| +    "  or \"all dependent\" configs.\n" | 
| +    "\n" | 
| +    "  Configs can have child configs. Specifying --tree will show the\n" | 
| +    "  hierarchy.\n" | 
| +    "\n" | 
| +    "Printing deps\n" | 
| +    "\n" | 
| +    "  Deps will include all public, private, and data deps (TODO this could\n" | 
| +    "  be clarified and enhanced) sorted in order applying. The following\n" | 
| +    "  may be used:\n" | 
| "\n" | 
| "  --all\n" | 
| "      Collects all recursive dependencies and prints a sorted flat list.\n" | 
| @@ -598,9 +868,6 @@ const char kDesc_Help[] = | 
| "      Shows defines set for the //base:base target, annotated by where\n" | 
| "      each one was set from.\n"; | 
|  | 
| -#define OUTPUT_CONFIG_VALUE(name, type) \ | 
| -    OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name); | 
| - | 
| int RunDesc(const std::vector<std::string>& args) { | 
| if (args.size() != 2 && args.size() != 3) { | 
| Err(Location(), "You're holding it wrong.", | 
| @@ -608,6 +875,7 @@ int RunDesc(const std::vector<std::string>& args) { | 
| .PrintToStdout(); | 
| return 1; | 
| } | 
| +  const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); | 
|  | 
| // Deliberately leaked to avoid expensive process teardown. | 
| Setup* setup = new Setup; | 
| @@ -617,153 +885,48 @@ int RunDesc(const std::vector<std::string>& args) { | 
| if (!setup->Run()) | 
| return 1; | 
|  | 
| -  const Target* target = ResolveTargetFromCommandLineString(setup, args[1]); | 
| -  if (!target) | 
| -    return 1; | 
| - | 
| -#define CONFIG_VALUE_HANDLER(name, type) \ | 
| -    } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type) | 
| - | 
| -  if (args.size() == 3) { | 
| -    // User specified one thing to display. | 
| -    const std::string& what = args[2]; | 
| -    if (what == variables::kConfigs) { | 
| -      PrintConfigs(target, false); | 
| -    } else if (what == variables::kPublicConfigs) { | 
| -      PrintPublicConfigs(target, false); | 
| -    } else if (what == variables::kAllDependentConfigs) { | 
| -      PrintAllDependentConfigs(target, false); | 
| -    } else if (what == variables::kSources) { | 
| -      PrintSources(target, false); | 
| -    } else if (what == variables::kPublic) { | 
| -      PrintPublic(target, false); | 
| -    } else if (what == variables::kCheckIncludes) { | 
| -      PrintCheckIncludes(target, false); | 
| -    } else if (what == variables::kAllowCircularIncludesFrom) { | 
| -      PrintAllowCircularIncludesFrom(target, false); | 
| -    } else if (what == variables::kVisibility) { | 
| -      PrintVisibility(target, false); | 
| -    } else if (what == variables::kTestonly) { | 
| -      PrintTestonly(target, false); | 
| -    } else if (what == variables::kInputs) { | 
| -      PrintInputs(target, false); | 
| -    } else if (what == variables::kScript) { | 
| -      PrintScript(target, false); | 
| -    } else if (what == variables::kArgs) { | 
| -      PrintArgs(target, false); | 
| -    } else if (what == variables::kDepfile) { | 
| -      PrintDepfile(target, false); | 
| -    } else if (what == variables::kOutputs) { | 
| -      PrintOutputs(target, false); | 
| -    } else if (what == variables::kDeps) { | 
| -      PrintDeps(target, false); | 
| -    } else if (what == variables::kLibDirs) { | 
| -      PrintLibDirs(target, false); | 
| -    } else if (what == variables::kLibs) { | 
| -      PrintLibs(target, false); | 
| -    } else if (what == "runtime_deps") { | 
| -      PrintRuntimeDeps(target); | 
| -//  }  Hidden closing brace in macro below. | 
| - | 
| -    CONFIG_VALUE_HANDLER(defines, std::string) | 
| -    CONFIG_VALUE_HANDLER(include_dirs, SourceDir) | 
| -    CONFIG_VALUE_HANDLER(arflags, std::string) | 
| -    CONFIG_VALUE_HANDLER(asmflags, std::string) | 
| -    CONFIG_VALUE_HANDLER(cflags, std::string) | 
| -    CONFIG_VALUE_HANDLER(cflags_c, std::string) | 
| -    CONFIG_VALUE_HANDLER(cflags_cc, std::string) | 
| -    CONFIG_VALUE_HANDLER(cflags_objc, std::string) | 
| -    CONFIG_VALUE_HANDLER(cflags_objcc, std::string) | 
| -    CONFIG_VALUE_HANDLER(ldflags, std::string) | 
| - | 
| -    } else { | 
| -      OutputString("Don't know how to display \"" + what + "\".\n"); | 
| -      return 1; | 
| -    } | 
| - | 
| -#undef CONFIG_VALUE_HANDLER | 
| -    return 0; | 
| -  } | 
| - | 
| -  // Display summary. | 
| +  // Resolve target(s) and config from inputs. | 
| +  UniqueVector<const Target*> target_matches; | 
| +  UniqueVector<const Config*> config_matches; | 
| +  UniqueVector<const Toolchain*> toolchain_matches; | 
| +  UniqueVector<SourceFile> file_matches; | 
|  | 
| -  // Display this only applicable to binary targets. | 
| -  bool is_binary_output = | 
| -    target->output_type() != Target::GROUP && | 
| -    target->output_type() != Target::COPY_FILES && | 
| -    target->output_type() != Target::ACTION && | 
| -    target->output_type() != Target::ACTION_FOREACH && | 
| -    target->output_type() != Target::BUNDLE_DATA && | 
| -    target->output_type() != Target::CREATE_BUNDLE; | 
| +  std::vector<std::string> target_list; | 
| +  target_list.push_back(args[1]); | 
|  | 
| -  // Generally we only want to display toolchains on labels when the toolchain | 
| -  // is different than the default one for this target (which we always print | 
| -  // in the header). | 
| -  Label target_toolchain = target->label().GetToolchainLabel(); | 
| - | 
| -  // Header. | 
| -  OutputString("Target: ", DECORATION_YELLOW); | 
| -  OutputString(target->label().GetUserVisibleName(false) + "\n"); | 
| -  OutputString("Type: ", DECORATION_YELLOW); | 
| -  OutputString(std::string( | 
| -      Target::GetStringForOutputType(target->output_type())) + "\n"); | 
| -  OutputString("Toolchain: ", DECORATION_YELLOW); | 
| -  OutputString(target_toolchain.GetUserVisibleName(false) + "\n"); | 
| - | 
| -  PrintSources(target, true); | 
| -  if (is_binary_output) { | 
| -    PrintPublic(target, true); | 
| -    PrintCheckIncludes(target, true); | 
| -    PrintAllowCircularIncludesFrom(target, true); | 
| -  } | 
| -  PrintVisibility(target, true); | 
| -  if (is_binary_output) { | 
| -    PrintTestonly(target, true); | 
| -    PrintConfigs(target, true); | 
| -  } | 
| +  if (!ResolveFromCommandLineInput( | 
| +          setup, target_list, cmdline->HasSwitch(switches::kAllToolchains), | 
| +          &target_matches, &config_matches, &toolchain_matches, &file_matches)) | 
| +    return 1; | 
|  | 
| -  PrintPublicConfigs(target, true); | 
| -  PrintAllDependentConfigs(target, true); | 
| +  std::string what_to_print; | 
| +  if (args.size() == 3) | 
| +    what_to_print = args[2]; | 
|  | 
| -  PrintInputs(target, true); | 
| +  bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1; | 
|  | 
| -  if (is_binary_output) { | 
| -    OUTPUT_CONFIG_VALUE(defines, std::string) | 
| -    OUTPUT_CONFIG_VALUE(include_dirs, SourceDir) | 
| -    OUTPUT_CONFIG_VALUE(asmflags, std::string) | 
| -    OUTPUT_CONFIG_VALUE(cflags, std::string) | 
| -    OUTPUT_CONFIG_VALUE(cflags_c, std::string) | 
| -    OUTPUT_CONFIG_VALUE(cflags_cc, std::string) | 
| -    OUTPUT_CONFIG_VALUE(cflags_objc, std::string) | 
| -    OUTPUT_CONFIG_VALUE(cflags_objcc, std::string) | 
| +  // Display headers for each target when printing all values, or when printing | 
| +  // multiple targets or configs. | 
| +  bool display_item_header = multiple_outputs || what_to_print.empty(); | 
|  | 
| -    if (target->output_type() == Target::STATIC_LIBRARY) | 
| -      OUTPUT_CONFIG_VALUE(arflags, std::string) | 
| -    else if (target->output_type() != Target::SOURCE_SET) | 
| -      OUTPUT_CONFIG_VALUE(ldflags, std::string) | 
| -  } | 
| +  bool printed_output = false; | 
| +  for (const Target* target : target_matches) { | 
| +    if (printed_output) | 
| +      OutputString("\n\n"); | 
| +    printed_output = true; | 
|  | 
| -  if (target->output_type() == Target::ACTION || | 
| -      target->output_type() == Target::ACTION_FOREACH) { | 
| -    PrintScript(target, true); | 
| -    PrintArgs(target, true); | 
| -    PrintDepfile(target, true); | 
| +    if (!PrintTarget(target, what_to_print, display_item_header)) | 
| +      return 1; | 
| } | 
| +  for (const Config* config : config_matches) { | 
| +    if (printed_output) | 
| +      OutputString("\n\n"); | 
| +    printed_output = true; | 
|  | 
| -  if (target->output_type() == Target::ACTION || | 
| -      target->output_type() == Target::ACTION_FOREACH || | 
| -      target->output_type() == Target::COPY_FILES || | 
| -      target->output_type() == Target::CREATE_BUNDLE) { | 
| -    PrintOutputs(target, true); | 
| +    if (!PrintConfig(config, what_to_print, display_item_header)) | 
| +      return 1; | 
| } | 
|  | 
| -  // Libs can be part of any target and get recursively pushed up the chain, | 
| -  // so always display them, even for groups and such. | 
| -  PrintLibs(target, true); | 
| -  PrintLibDirs(target, true); | 
| - | 
| -  PrintDeps(target, true); | 
| - | 
| return 0; | 
| } | 
|  | 
|  |