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/item.h" 14#include "tools/gn/item_node.h" 15#include "tools/gn/label.h" 16#include "tools/gn/setup.h" 17#include "tools/gn/standard_out.h" 18#include "tools/gn/target.h" 19 20namespace commands { 21 22namespace { 23 24struct CompareTargetLabel { 25 bool operator()(const Target* a, const Target* b) const { 26 return a->label() < b->label(); 27 } 28}; 29 30void RecursiveCollectDeps(const Target* target, std::set<Label>* result) { 31 if (result->find(target->label()) != result->end()) 32 return; // Already did this target. 33 result->insert(target->label()); 34 35 const std::vector<const Target*>& deps = target->deps(); 36 for (size_t i = 0; i < deps.size(); i++) 37 RecursiveCollectDeps(deps[i], result); 38 39 const std::vector<const Target*>& datadeps = target->datadeps(); 40 for (size_t i = 0; i < datadeps.size(); i++) 41 RecursiveCollectDeps(datadeps[i], result); 42} 43 44// Prints dependencies of the given target (not the target itself). 45void RecursivePrintDeps(const Target* target, 46 const Label& default_toolchain, 47 int indent_level) { 48 std::vector<const Target*> sorted_deps = target->deps(); 49 const std::vector<const Target*> datadeps = target->datadeps(); 50 for (size_t i = 0; i < datadeps.size(); i++) 51 sorted_deps.push_back(datadeps[i]); 52 std::sort(sorted_deps.begin(), sorted_deps.end(), CompareTargetLabel()); 53 54 std::string indent(indent_level * 2, ' '); 55 for (size_t i = 0; i < sorted_deps.size(); i++) { 56 OutputString(indent + 57 sorted_deps[i]->label().GetUserVisibleName(default_toolchain) + "\n"); 58 RecursivePrintDeps(sorted_deps[i], default_toolchain, indent_level + 1); 59 } 60} 61 62void PrintDeps(const Target* target, bool display_header) { 63 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 64 Label toolchain_label = target->label().GetToolchainLabel(); 65 66 // Tree mode is separate. 67 if (cmdline->HasSwitch("tree")) { 68 if (display_header) 69 OutputString("\nDependency tree:\n"); 70 RecursivePrintDeps(target, toolchain_label, 1); 71 return; 72 } 73 74 // Collect the deps to display. 75 std::vector<Label> deps; 76 if (cmdline->HasSwitch("all")) { 77 if (display_header) 78 OutputString("\nAll recursive dependencies:\n"); 79 80 std::set<Label> all_deps; 81 RecursiveCollectDeps(target, &all_deps); 82 for (std::set<Label>::iterator i = all_deps.begin(); 83 i != all_deps.end(); ++i) 84 deps.push_back(*i); 85 } else { 86 if (display_header) { 87 OutputString("\nDirect dependencies " 88 "(try also \"--all\" and \"--tree\"):\n"); 89 } 90 91 const std::vector<const Target*>& target_deps = target->deps(); 92 for (size_t i = 0; i < target_deps.size(); i++) 93 deps.push_back(target_deps[i]->label()); 94 95 const std::vector<const Target*>& target_datadeps = target->datadeps(); 96 for (size_t i = 0; i < target_datadeps.size(); i++) 97 deps.push_back(target_datadeps[i]->label()); 98 } 99 100 std::sort(deps.begin(), deps.end()); 101 for (size_t i = 0; i < deps.size(); i++) 102 OutputString(" " + deps[i].GetUserVisibleName(toolchain_label) + "\n"); 103} 104 105void PrintConfigs(const Target* target, bool display_header) { 106 // Configs (don't sort since the order determines how things are processed). 107 if (display_header) 108 OutputString("\nConfigs (in order applying):\n"); 109 110 Label toolchain_label = target->label().GetToolchainLabel(); 111 const std::vector<const Config*>& configs = target->configs(); 112 for (size_t i = 0; i < configs.size(); i++) { 113 OutputString(" " + 114 configs[i]->label().GetUserVisibleName(toolchain_label) + "\n"); 115 } 116} 117 118void PrintSources(const Target* target, bool display_header) { 119 if (display_header) 120 OutputString("\nSources:\n"); 121 122 Target::FileList sources = target->sources(); 123 std::sort(sources.begin(), sources.end()); 124 for (size_t i = 0; i < sources.size(); i++) 125 OutputString(" " + sources[i].value() + "\n"); 126} 127 128// Attempts to attribute the gen dependency of the given target to some source 129// code and outputs the string to the output stream. 130// 131// The attribution of the source of the dependencies is stored in the ItemNode 132// which is the parallel structure to the target dependency map, so we have 133// to jump through a few loops to find everything. 134void OutputSourceOfDep(const Target* target, 135 const Label& dep_label, 136 std::ostream& out) { 137 ItemTree& item_tree = target->settings()->build_settings()->item_tree(); 138 base::AutoLock lock(item_tree.lock()); 139 140 ItemNode* target_node = item_tree.GetExistingNodeLocked(target->label()); 141 CHECK(target_node); 142 ItemNode* dep_node = item_tree.GetExistingNodeLocked(dep_label); 143 CHECK(dep_node); 144 145 const ItemNode::ItemNodeMap& direct_deps = target_node->direct_dependencies(); 146 ItemNode::ItemNodeMap::const_iterator found = direct_deps.find(dep_node); 147 if (found == direct_deps.end()) 148 return; 149 150 const Location& location = found->second.begin(); 151 out << " (Added by " + location.file()->name().value() << ":" 152 << location.line_number() << ")\n"; 153} 154 155// Templatized writer for writing out different config value types. 156template<typename T> struct DescValueWriter {}; 157template<> struct DescValueWriter<std::string> { 158 void operator()(const std::string& str, std::ostream& out) const { 159 out << " " << str << "\n"; 160 } 161}; 162template<> struct DescValueWriter<SourceFile> { 163 void operator()(const SourceFile& file, std::ostream& out) const { 164 out << " " << file.value() << "\n"; 165 } 166}; 167template<> struct DescValueWriter<SourceDir> { 168 void operator()(const SourceDir& dir, std::ostream& out) const { 169 out << " " << dir.value() << "\n"; 170 } 171}; 172 173// Writes a given config value type to the string, optionally with attribution. 174// This should match RecursiveTargetConfigToStream in the order it traverses. 175template<typename T> void OutputRecursiveTargetConfig( 176 const Target* target, 177 const char* header_name, 178 const std::vector<T>& (ConfigValues::* getter)() const) { 179 bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame"); 180 181 DescValueWriter<T> writer; 182 std::ostringstream out; 183 184 // First write the values from the config itself. 185 if (!(target->config_values().*getter)().empty()) { 186 if (display_blame) 187 out << " From " << target->label().GetUserVisibleName(false) << "\n"; 188 ConfigValuesToStream(target->config_values(), getter, writer, out); 189 } 190 191 // TODO(brettw) annotate where forced config includes came from! 192 193 // Then write the configs in order. 194 for (size_t i = 0; i < target->configs().size(); i++) { 195 const Config* config = target->configs()[i]; 196 const ConfigValues& values = config->config_values(); 197 198 if (!(values.*getter)().empty()) { 199 if (display_blame) { 200 out << " From " << config->label().GetUserVisibleName(false) << "\n"; 201 OutputSourceOfDep(target, config->label(), out); 202 } 203 ConfigValuesToStream(values, getter, writer, out); 204 } 205 } 206 207 std::string out_str = out.str(); 208 if (!out_str.empty()) { 209 OutputString(std::string(header_name) + "\n"); 210 OutputString(out_str); 211 } 212} 213 214} // namespace 215 216// desc ------------------------------------------------------------------------ 217 218const char kDesc[] = "desc"; 219const char kDesc_HelpShort[] = 220 "desc: Show lots of insightful information about a target."; 221const char kDesc_Help[] = 222 "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n" 223 " Displays information about a given labeled target.\n" 224 "\n" 225 "Possibilities for <what to show>:\n" 226 " (If unspecified an overall summary will be displayed.)\n" 227 "\n" 228 " sources\n" 229 " Source files.\n" 230 "\n" 231 " configs\n" 232 " Shows configs applied to the given target, sorted in the order\n" 233 " they're specified. This includes both configs specified in the\n" 234 " \"configs\" variable, as well as configs pushed onto this target\n" 235 " via dependencies specifying \"all\" or \"direct\" dependent\n" 236 " configs.\n" 237 "\n" 238 " deps [--all | --tree]\n" 239 " Show immediate (or, when \"--all\" or \"--tree\" is specified,\n" 240 " recursive) dependencies of the given target. \"--tree\" shows them\n" 241 " in a tree format. Otherwise, they will be sorted alphabetically.\n" 242 " Both \"deps\" and \"datadeps\" will be included.\n" 243 "\n" 244 " defines [--blame]\n" 245 " includes [--blame]\n" 246 " cflags [--blame]\n" 247 " cflags_cc [--blame]\n" 248 " cflags_cxx [--blame]\n" 249 " ldflags [--blame]\n" 250 " Shows the given values taken from the target and all configs\n" 251 " applying. See \"--blame\" below.\n" 252 "\n" 253 " --blame\n" 254 " Used with any value specified by a config, this will name\n" 255 " the config that specified the value.\n" 256 "\n" 257 "Note:\n" 258 " This command will show the full name of directories and source files,\n" 259 " but when directories and source paths are written to the build file,\n" 260 " they will be adjusted to be relative to the build directory. So the\n" 261 " values for paths displayed by this command won't match (but should\n" 262 " mean the same thing.\n" 263 "\n" 264 "Examples:\n" 265 " gn desc //base:base\n" 266 " Summarizes the given target.\n" 267 "\n" 268 " gn desc :base_unittests deps --tree\n" 269 " Shows a dependency tree of the \"base_unittests\" project in\n" 270 " the current directory.\n" 271 "\n" 272 " gn desc //base defines --blame\n" 273 " Shows defines set for the //base:base target, annotated by where\n" 274 " each one was set from.\n"; 275 276int RunDesc(const std::vector<std::string>& args) { 277 if (args.size() != 1 && args.size() != 2) { 278 Err(Location(), "You're holding it wrong.", 279 "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout(); 280 return 1; 281 } 282 283 const Target* target = GetTargetForDesc(args); 284 if (!target) 285 return 1; 286 287#define CONFIG_VALUE_HANDLER(name) \ 288 } else if (what == #name) { \ 289 OutputRecursiveTargetConfig(target, #name, &ConfigValues::name); 290 291 if (args.size() == 2) { 292 // User specified one thing to display. 293 const std::string& what = args[1]; 294 if (what == "configs") { 295 PrintConfigs(target, false); 296 } else if (what == "sources") { 297 PrintSources(target, false); 298 } else if (what == "deps") { 299 PrintDeps(target, false); 300 301 CONFIG_VALUE_HANDLER(defines) 302 CONFIG_VALUE_HANDLER(includes) 303 CONFIG_VALUE_HANDLER(cflags) 304 CONFIG_VALUE_HANDLER(cflags_c) 305 CONFIG_VALUE_HANDLER(cflags_cc) 306 CONFIG_VALUE_HANDLER(ldflags) 307 308 } else { 309 OutputString("Don't know how to display \"" + what + "\".\n"); 310 return 1; 311 } 312 313#undef CONFIG_VALUE_HANDLER 314 return 0; 315 } 316 317 // Display summary. 318 319 // Generally we only want to display toolchains on labels when the toolchain 320 // is different than the default one for this target (which we always print 321 // in the header). 322 Label target_toolchain = target->label().GetToolchainLabel(); 323 324 // Header. 325 std::string title_target = 326 "Target: " + target->label().GetUserVisibleName(false); 327 std::string title_toolchain = 328 "Toolchain: " + target_toolchain.GetUserVisibleName(false); 329 OutputString(title_target + "\n", DECORATION_YELLOW); 330 OutputString(title_toolchain + "\n", DECORATION_YELLOW); 331 OutputString(std::string( 332 std::max(title_target.size(), title_toolchain.size()), '=') + "\n"); 333 334 PrintSources(target, true); 335 PrintConfigs(target, true); 336 OutputString("\n (Use \"gn desc <label> <thing you want to see>\" to show " 337 "the actual values\n applied by the different configs. " 338 "See \"gn help desc\" for more.)\n"); 339 PrintDeps(target, true); 340 341 return 0; 342} 343 344} // namespace commands 345