// 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_util.h" #include "tools/gn/commands.h" #include "tools/gn/config.h" #include "tools/gn/desc_builder.h" #include "tools/gn/setup.h" #include "tools/gn/standard_out.h" #include "tools/gn/switches.h" #include "tools/gn/target.h" #include "tools/gn/variables.h" namespace commands { namespace { // Desc-specific command line switches. const char kBlame[] = "blame"; const char kTree[] = "tree"; const char kAll[] = "all"; // 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; 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->IsType(base::Value::Type::NONE)) { OutputString(indent + "\n"); } } // Default handler for property void DefaultHandler(const std::string& name, const base::Value* value) { OutputString("\n"); OutputString(name); OutputString("\n"); PrintValue(value, 1); } // Specific handler for properties that need different treatment // Prints label and property value on one line, capitalizing the label. void LabelHandler(std::string name, const base::Value* value) { name[0] = base::ToUpperASCII(name[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) { const base::ListValue* list; if (value->GetAsList(&list)) { if (list->empty()) { base::Value str("(no visibility)"); DefaultHandler(name, &str); } else { DefaultHandler(name, value); } } } void PublicHandler(const std::string& name, const base::Value* value) { std::string p; if (value->GetAsString(&p)) { if (p == "*") { base::Value str("[All headers listed in the sources are public.]"); DefaultHandler(name, &str); return; } } DefaultHandler(name, value); } void ConfigsHandler(const std::string& name, const base::Value* value) { bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); if (tree) DefaultHandler(name + " tree (in order applying)", value); else DefaultHandler(name + " (in order applying, try also --tree)", value); } void DepsHandler(const std::string& name, const base::Value* value) { bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree); if (tree) { DefaultHandler("Dependency tree", value); } else { if (!all) { DefaultHandler( "Direct dependencies " "(try also \"--all\", \"--tree\", or even \"--all --tree\")", value); } else { DefaultHandler("All recursive dependencies", value); } } } // Outputs need special processing when output patterns are present. void ProcessOutputs(base::DictionaryValue* target) { base::ListValue* patterns = nullptr; base::ListValue* outputs = nullptr; target->GetList("output_patterns", &patterns); target->GetList(variables::kOutputs, &outputs); if (outputs || patterns) { OutputString("\noutputs\n"); int indent = 1; if (patterns) { OutputString(" Output patterns\n"); indent = 2; PrintValue(patterns, indent); OutputString("\n Resolved output file list\n"); } if (outputs) PrintValue(outputs, indent); target->Remove("output_patterns", nullptr); target->Remove(variables::kOutputs, nullptr); } } bool PrintTarget(const Target* target, const std::string& what, bool single_target, 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, without any headers if (!what.empty() && dict->size() == 1 && single_target) { base::DictionaryValue::Iterator iter(*dict); PrintValue(&iter.value(), 0); return true; } OutputString("Target ", DECORATION_YELLOW); OutputString(target->label().GetUserVisibleName(false)); OutputString("\n"); std::unique_ptr v; #define HANDLER(property, handler_name) \ if (dict->Remove(property, &v)) { \ handler_name(property, v.get()); \ } // Entries with DefaultHandler are present to enforce order HANDLER("type", LabelHandler); HANDLER("toolchain", LabelHandler); HANDLER(variables::kVisibility, VisibilityHandler); HANDLER(variables::kTestonly, DefaultHandler); HANDLER(variables::kCheckIncludes, DefaultHandler); HANDLER(variables::kAllowCircularIncludesFrom, DefaultHandler); HANDLER(variables::kSources, DefaultHandler); HANDLER(variables::kPublic, PublicHandler); HANDLER(variables::kInputs, DefaultHandler); HANDLER(variables::kConfigs, ConfigsHandler); HANDLER(variables::kPublicConfigs, ConfigsHandler); HANDLER(variables::kAllDependentConfigs, ConfigsHandler); HANDLER(variables::kScript, DefaultHandler); HANDLER(variables::kArgs, DefaultHandler); HANDLER(variables::kDepfile, DefaultHandler); ProcessOutputs(dict.get()); HANDLER("bundle_data", DefaultHandler); HANDLER(variables::kArflags, DefaultHandler); HANDLER(variables::kAsmflags, DefaultHandler); HANDLER(variables::kCflags, DefaultHandler); HANDLER(variables::kCflagsC, DefaultHandler); HANDLER(variables::kCflagsCC, DefaultHandler); HANDLER(variables::kCflagsObjC, DefaultHandler); HANDLER(variables::kCflagsObjCC, DefaultHandler); HANDLER(variables::kDefines, DefaultHandler); HANDLER(variables::kIncludeDirs, DefaultHandler); HANDLER(variables::kLdflags, DefaultHandler); HANDLER(variables::kPrecompiledHeader, DefaultHandler); HANDLER(variables::kPrecompiledSource, DefaultHandler); HANDLER(variables::kDeps, DepsHandler); HANDLER(variables::kLibs, DefaultHandler); HANDLER(variables::kLibDirs, DefaultHandler); #undef HANDLER // Process the rest (if any) base::DictionaryValue::Iterator iter(*dict); while (!iter.IsAtEnd()) { DefaultHandler(iter.key(), &iter.value()); iter.Advance(); } return true; } bool PrintConfig(const Config* config, const std::string& what, bool single_config) { 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, without any headers if (!what.empty() && dict->size() == 1 && single_config) { base::DictionaryValue::Iterator iter(*dict); PrintValue(&iter.value(), 0); return true; } OutputString("Config: ", DECORATION_YELLOW); OutputString(config->label().GetUserVisibleName(false)); OutputString("\n"); std::unique_ptr v; #define HANDLER(property, handler_name) \ if (dict->Remove(property, &v)) { \ handler_name(property, v.get()); \ } HANDLER("toolchain", LabelHandler); if (!config->configs().empty()) { OutputString( "(This is a composite config, the values below are after the\n" "expansion of the child configs.)\n"); } HANDLER(variables::kArflags, DefaultHandler); HANDLER(variables::kAsmflags, DefaultHandler); HANDLER(variables::kCflags, DefaultHandler); HANDLER(variables::kCflagsC, DefaultHandler); HANDLER(variables::kCflagsCC, DefaultHandler); HANDLER(variables::kCflagsObjC, DefaultHandler); HANDLER(variables::kCflagsObjCC, DefaultHandler); HANDLER(variables::kDefines, DefaultHandler); HANDLER(variables::kIncludeDirs, DefaultHandler); HANDLER(variables::kLdflags, DefaultHandler); HANDLER(variables::kLibs, DefaultHandler); HANDLER(variables::kLibDirs, DefaultHandler); HANDLER(variables::kPrecompiledHeader, DefaultHandler); HANDLER(variables::kPrecompiledSource, DefaultHandler); #undef HANDLER 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