// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include "base/command_line.h" #include "base/json/json_writer.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "gn/commands.h" #include "gn/config.h" #include "gn/desc_builder.h" #include "gn/rust_variables.h" #include "gn/setup.h" #include "gn/standard_out.h" #include "gn/swift_variables.h" #include "gn/switches.h" #include "gn/target.h" #include "gn/variables.h" namespace commands { namespace { // Desc-specific command line switches. const char kBlame[] = "blame"; const char kTree[] = "tree"; const char kAll[] = "all"; void PrintDictValue(const base::Value* value, int indentLevel, bool use_first_indent) { std::string indent(indentLevel * 2, ' '); const base::ListValue* list_value = nullptr; const base::DictionaryValue* dict_value = nullptr; std::string string_value; bool bool_value = false; int int_value = 0; if (use_first_indent) OutputString(indent); if (value->GetAsList(&list_value)) { OutputString("[\n"); bool first = true; for (const auto& v : *list_value) { if (!first) OutputString(",\n"); PrintDictValue(&v, indentLevel + 1, true); first = false; } OutputString("\n" + indent + "]"); } else if (value->GetAsString(&string_value)) { OutputString("\"" + string_value + "\""); } else if (value->GetAsBoolean(&bool_value)) { OutputString(bool_value ? "true" : "false"); } else if (value->GetAsDictionary(&dict_value)) { OutputString("{\n"); std::string indent_plus_one((indentLevel + 1) * 2, ' '); base::DictionaryValue::Iterator iter(*dict_value); bool first = true; while (!iter.IsAtEnd()) { if (!first) OutputString(",\n"); OutputString(indent_plus_one + iter.key() + " = "); PrintDictValue(&iter.value(), indentLevel + 1, false); iter.Advance(); first = false; } OutputString("\n" + indent + "}"); } else if (value->GetAsInteger(&int_value)) { OutputString(base::IntToString(int_value)); } else if (value->is_none()) { OutputString(""); } } // Prints value with specified indentation level void PrintValue(const base::Value* value, int indentLevel) { std::string indent(indentLevel * 2, ' '); const base::ListValue* list_value = nullptr; const base::DictionaryValue* dict_value = nullptr; std::string string_value; bool bool_value = false; int int_value = 0; if (value->GetAsList(&list_value)) { for (const auto& v : *list_value) { PrintValue(&v, indentLevel); } } else if (value->GetAsString(&string_value)) { OutputString(indent); OutputString(string_value); OutputString("\n"); } else if (value->GetAsBoolean(&bool_value)) { OutputString(indent); OutputString(bool_value ? "true" : "false"); OutputString("\n"); } else if (value->GetAsDictionary(&dict_value)) { base::DictionaryValue::Iterator iter(*dict_value); while (!iter.IsAtEnd()) { OutputString(indent + iter.key() + "\n"); PrintValue(&iter.value(), indentLevel + 1); iter.Advance(); } } else if (value->GetAsInteger(&int_value)) { OutputString(indent); OutputString(base::IntToString(int_value)); OutputString("\n"); } else if (value->is_none()) { OutputString(indent + "\n"); } } // Default handler for property void DefaultHandler(const std::string& name, const base::Value* value, bool value_only) { if (value_only) { PrintValue(value, 0); return; } OutputString("\n"); OutputString(name); OutputString("\n"); PrintValue(value, 1); } // Specific handler for properties that need different treatment // Prints the dict in GN scope-sytle. void MetadataHandler(const std::string& name, const base::Value* value, bool value_only) { if (value_only) { PrintDictValue(value, 0, true); OutputString("\n"); return; } OutputString("\n"); OutputString(name); OutputString("\n"); PrintDictValue(value, 1, true); OutputString("\n"); } // Prints label and property value on one line, capitalizing the label. void LabelHandler(const std::string& name, const base::Value* value, bool value_only) { if (value_only) { PrintValue(value, 0); return; } std::string label = name; label[0] = base::ToUpperASCII(label[0]); std::string string_value; if (value->GetAsString(&string_value)) { OutputString(name + ": ", DECORATION_YELLOW); OutputString(string_value + "\n"); } } void VisibilityHandler(const std::string& name, const base::Value* value, bool value_only) { if (value_only) { PrintValue(value, 0); return; } const base::ListValue* list; if (value->GetAsList(&list)) { if (list->empty()) { base::Value str("(no visibility)"); DefaultHandler(name, &str, value_only); } else { DefaultHandler(name, value, value_only); } } } void PublicHandler(const std::string& name, const base::Value* value, bool value_only) { if (value_only) { PrintValue(value, 0); return; } std::string p; if (value->GetAsString(&p)) { if (p == "*") { base::Value str("[All headers listed in the sources are public.]"); DefaultHandler(name, &str, value_only); return; } } DefaultHandler(name, value, value_only); } void ConfigsHandler(const std::string& name, const base::Value* value, bool value_only) { bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); if (tree) DefaultHandler(name + " tree (in order applying)", value, value_only); else DefaultHandler(name + " (in order applying, try also --tree)", value, value_only); } void DepsHandler(const std::string& name, const base::Value* value, bool value_only) { bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); if (tree) { DefaultHandler("Dependency tree", value, value_only); } else { if (!all) { DefaultHandler( "Direct dependencies " "(try also \"--all\", \"--tree\", or even \"--all --tree\")", value, value_only); } else { DefaultHandler("All recursive dependencies", value, value_only); } } } // Outputs need special processing when output patterns are present. void ProcessOutputs(base::DictionaryValue* target, bool files_only) { base::ListValue* patterns = nullptr; base::ListValue* outputs = nullptr; target->GetList("output_patterns", &patterns); target->GetList(variables::kOutputs, &outputs); int indent = 0; if (outputs || patterns) { if (!files_only) { OutputString("\noutputs\n"); indent = 1; } if (patterns) { if (!files_only) { OutputString(" Output patterns\n"); indent = 2; } PrintValue(patterns, indent); if (!files_only) OutputString("\n Resolved output file list\n"); } if (outputs) PrintValue(outputs, indent); target->Remove("output_patterns", nullptr); target->Remove(variables::kOutputs, nullptr); } } using DescHandlerFunc = void (*)(const std::string& name, const base::Value* value, bool value_only); std::map GetHandlers() { return {{"type", LabelHandler}, {"toolchain", LabelHandler}, {variables::kVisibility, VisibilityHandler}, {variables::kMetadata, MetadataHandler}, {variables::kTestonly, DefaultHandler}, {variables::kCheckIncludes, DefaultHandler}, {variables::kAllowCircularIncludesFrom, DefaultHandler}, {variables::kSources, DefaultHandler}, {variables::kPublic, PublicHandler}, {variables::kInputs, DefaultHandler}, {variables::kConfigs, ConfigsHandler}, {variables::kPublicConfigs, ConfigsHandler}, {variables::kAllDependentConfigs, ConfigsHandler}, {variables::kScript, DefaultHandler}, {variables::kArgs, DefaultHandler}, {variables::kDepfile, DefaultHandler}, {"bundle_data", DefaultHandler}, {variables::kArflags, DefaultHandler}, {variables::kAsmflags, DefaultHandler}, {variables::kCflags, DefaultHandler}, {variables::kCflagsC, DefaultHandler}, {variables::kCflagsCC, DefaultHandler}, {variables::kCflagsObjC, DefaultHandler}, {variables::kCflagsObjCC, DefaultHandler}, {variables::kDefines, DefaultHandler}, {variables::kFrameworkDirs, DefaultHandler}, {variables::kFrameworks, DefaultHandler}, {variables::kIncludeDirs, DefaultHandler}, {variables::kLdflags, DefaultHandler}, {variables::kPrecompiledHeader, DefaultHandler}, {variables::kPrecompiledSource, DefaultHandler}, {variables::kDeps, DepsHandler}, {variables::kGenDeps, DefaultHandler}, {variables::kLibs, DefaultHandler}, {variables::kLibDirs, DefaultHandler}, {variables::kDataKeys, DefaultHandler}, {variables::kRebase, DefaultHandler}, {variables::kWalkKeys, DefaultHandler}, {variables::kWeakFrameworks, DefaultHandler}, {variables::kWriteOutputConversion, DefaultHandler}, {variables::kRustCrateName, DefaultHandler}, {variables::kRustCrateRoot, DefaultHandler}, {variables::kRustflags, DefaultHandler}, {variables::kSwiftModuleName, DefaultHandler}, {variables::kSwiftBridgeHeader, DefaultHandler}, {variables::kMnemonic, DefaultHandler}, {"runtime_deps", DefaultHandler}}; } void HandleProperty(const std::string& what, const std::map& handler_map, std::unique_ptr& v, std::unique_ptr& dict) { if (dict->Remove(what, &v)) { auto pair = handler_map.find(what); if (pair != handler_map.end()) pair->second(what, v.get(), false); } } bool PrintTarget(const Target* target, const std::string& what, bool single_target, const std::map& handler_map, bool all, bool tree, bool blame) { std::unique_ptr dict = DescBuilder::DescriptionForTarget(target, what, all, tree, blame); if (!what.empty() && dict->empty()) { OutputString("Don't know how to display \"" + what + "\" for \"" + Target::GetStringForOutputType(target->output_type()) + "\".\n"); return false; } // Print single value if (!what.empty() && dict->size() == 1 && single_target) { if (what == variables::kOutputs) { ProcessOutputs(dict.get(), true); return true; } base::DictionaryValue::Iterator iter(*dict); auto pair = handler_map.find(what); if (pair != handler_map.end()) pair->second(what, &iter.value(), true); return true; } OutputString("Target ", DECORATION_YELLOW); OutputString(target->label().GetUserVisibleName(false)); OutputString("\n"); std::unique_ptr v; // Entries with DefaultHandler are present to enforce order HandleProperty("type", handler_map, v, dict); HandleProperty("toolchain", handler_map, v, dict); HandleProperty(variables::kSwiftModuleName, handler_map, v, dict); HandleProperty(variables::kRustCrateName, handler_map, v, dict); HandleProperty(variables::kRustCrateRoot, handler_map, v, dict); HandleProperty(variables::kVisibility, handler_map, v, dict); HandleProperty(variables::kMetadata, handler_map, v, dict); HandleProperty(variables::kTestonly, handler_map, v, dict); HandleProperty(variables::kCheckIncludes, handler_map, v, dict); HandleProperty(variables::kAllowCircularIncludesFrom, handler_map, v, dict); HandleProperty(variables::kSources, handler_map, v, dict); HandleProperty(variables::kSwiftBridgeHeader, handler_map, v, dict); HandleProperty(variables::kPublic, handler_map, v, dict); HandleProperty(variables::kInputs, handler_map, v, dict); HandleProperty(variables::kConfigs, handler_map, v, dict); HandleProperty(variables::kPublicConfigs, handler_map, v, dict); HandleProperty(variables::kAllDependentConfigs, handler_map, v, dict); HandleProperty(variables::kScript, handler_map, v, dict); HandleProperty(variables::kArgs, handler_map, v, dict); HandleProperty(variables::kDepfile, handler_map, v, dict); ProcessOutputs(dict.get(), false); HandleProperty("bundle_data", handler_map, v, dict); HandleProperty(variables::kArflags, handler_map, v, dict); HandleProperty(variables::kAsmflags, handler_map, v, dict); HandleProperty(variables::kCflags, handler_map, v, dict); HandleProperty(variables::kCflagsC, handler_map, v, dict); HandleProperty(variables::kCflagsCC, handler_map, v, dict); HandleProperty(variables::kCflagsObjC, handler_map, v, dict); HandleProperty(variables::kCflagsObjCC, handler_map, v, dict); HandleProperty(variables::kSwiftflags, handler_map, v, dict); HandleProperty(variables::kDefines, handler_map, v, dict); HandleProperty(variables::kFrameworkDirs, handler_map, v, dict); HandleProperty(variables::kFrameworks, handler_map, v, dict); HandleProperty(variables::kIncludeDirs, handler_map, v, dict); HandleProperty(variables::kLdflags, handler_map, v, dict); HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict); HandleProperty(variables::kPrecompiledSource, handler_map, v, dict); HandleProperty(variables::kDeps, handler_map, v, dict); HandleProperty(variables::kLibs, handler_map, v, dict); HandleProperty(variables::kLibDirs, handler_map, v, dict); HandleProperty(variables::kDataKeys, handler_map, v, dict); HandleProperty(variables::kRebase, handler_map, v, dict); HandleProperty(variables::kRustflags, handler_map, v, dict); HandleProperty(variables::kWalkKeys, handler_map, v, dict); HandleProperty(variables::kWeakFrameworks, handler_map, v, dict); HandleProperty(variables::kWriteOutputConversion, handler_map, v, dict); #undef HandleProperty // Process the rest (if any) base::DictionaryValue::Iterator iter(*dict); while (!iter.IsAtEnd()) { DefaultHandler(iter.key(), &iter.value(), false); iter.Advance(); } return true; } bool PrintConfig(const Config* config, const std::string& what, bool single_config, const std::map& handler_map) { std::unique_ptr dict = DescBuilder::DescriptionForConfig(config, what); if (!what.empty() && dict->empty()) { OutputString("Don't know how to display \"" + what + "\" for a config.\n"); return false; } // Print single value if (!what.empty() && dict->size() == 1 && single_config) { base::DictionaryValue::Iterator iter(*dict); auto pair = handler_map.find(what); if (pair != handler_map.end()) pair->second(what, &iter.value(), true); return true; } OutputString("Config: ", DECORATION_YELLOW); OutputString(config->label().GetUserVisibleName(false)); OutputString("\n"); std::unique_ptr v; HandleProperty("toolchain", handler_map, v, dict); if (!config->configs().empty()) { OutputString( "(This is a composite config, the values below are after the\n" "expansion of the child configs.)\n"); } HandleProperty(variables::kArflags, handler_map, v, dict); HandleProperty(variables::kAsmflags, handler_map, v, dict); HandleProperty(variables::kCflags, handler_map, v, dict); HandleProperty(variables::kCflagsC, handler_map, v, dict); HandleProperty(variables::kCflagsCC, handler_map, v, dict); HandleProperty(variables::kCflagsObjC, handler_map, v, dict); HandleProperty(variables::kCflagsObjCC, handler_map, v, dict); HandleProperty(variables::kSwiftflags, handler_map, v, dict); HandleProperty(variables::kDefines, handler_map, v, dict); HandleProperty(variables::kFrameworkDirs, handler_map, v, dict); HandleProperty(variables::kFrameworks, handler_map, v, dict); HandleProperty(variables::kIncludeDirs, handler_map, v, dict); HandleProperty(variables::kInputs, handler_map, v, dict); HandleProperty(variables::kLdflags, handler_map, v, dict); HandleProperty(variables::kLibs, handler_map, v, dict); HandleProperty(variables::kLibDirs, handler_map, v, dict); HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict); HandleProperty(variables::kPrecompiledSource, handler_map, v, dict); HandleProperty(variables::kRustflags, handler_map, v, dict); HandleProperty(variables::kWeakFrameworks, handler_map, v, dict); #undef HandleProperty return true; } } // namespace // desc ------------------------------------------------------------------------ const char kDesc[] = "desc"; const char kDesc_HelpShort[] = "desc: Show lots of insightful information about a target or config."; const char kDesc_Help[] = R"(gn desc gn desc