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/filesystem_utils.h" 14 #include "tools/gn/item.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 20 namespace commands { 21 22 namespace { 23 24 // Prints the given directory in a nice way for the user to view. 25 std::string FormatSourceDir(const SourceDir& dir) { 26 #if defined(OS_WIN) 27 // On Windows we fix up system absolute paths to look like native ones. 28 // Internally, they'll look like "/C:\foo\bar/" 29 if (dir.is_system_absolute()) { 30 std::string buf = dir.value(); 31 if (buf.size() > 3 && buf[2] == ':') { 32 buf.erase(buf.begin()); // Erase beginning slash. 33 ConvertPathToSystem(&buf); // Convert to backslashes. 34 return buf; 35 } 36 } 37 #endif 38 return dir.value(); 39 } 40 41 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result); 42 43 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) { 44 if (result->find(target->label()) != result->end()) 45 return; // Already did this target. 46 result->insert(target->label()); 47 48 RecursiveCollectChildDeps(target, result); 49 } 50 51 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) { 52 const LabelTargetVector& deps = target->deps(); 53 for (size_t i = 0; i < deps.size(); i++) 54 RecursiveCollectDeps(deps[i].ptr, result); 55 56 const LabelTargetVector& datadeps = target->datadeps(); 57 for (size_t i = 0; i < datadeps.size(); i++) 58 RecursiveCollectDeps(datadeps[i].ptr, result); 59 } 60 61 // Prints dependencies of the given target (not the target itself). 62 void RecursivePrintDeps(const Target* target, 63 const Label& default_toolchain, 64 int indent_level) { 65 LabelTargetVector sorted_deps = target->deps(); 66 const LabelTargetVector& datadeps = target->datadeps(); 67 sorted_deps.insert(sorted_deps.end(), datadeps.begin(), datadeps.end()); 68 std::sort(sorted_deps.begin(), sorted_deps.end(), 69 LabelPtrLabelLess<Target>()); 70 71 std::string indent(indent_level * 2, ' '); 72 for (size_t i = 0; i < sorted_deps.size(); i++) { 73 OutputString(indent + 74 sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n"); 75 RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1); 76 } 77 } 78 79 void PrintDeps(const Target* target, bool display_header) { 80 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 81 Label toolchain_label = target->label().GetToolchainLabel(); 82 83 // Tree mode is separate. 84 if (cmdline->HasSwitch("tree")) { 85 if (display_header) 86 OutputString("\nDependency tree:\n"); 87 RecursivePrintDeps(target, toolchain_label, 1); 88 return; 89 } 90 91 // Collect the deps to display. 92 std::vector<Label> deps; 93 if (cmdline->HasSwitch("all")) { 94 if (display_header) 95 OutputString("\nAll recursive dependencies:\n"); 96 97 std::set<Label> all_deps; 98 RecursiveCollectChildDeps(target, &all_deps); 99 for (std::set<Label>::iterator i = all_deps.begin(); 100 i != all_deps.end(); ++i) 101 deps.push_back(*i); 102 } else { 103 if (display_header) { 104 OutputString("\nDirect dependencies " 105 "(try also \"--all\" and \"--tree\"):\n"); 106 } 107 108 const LabelTargetVector& target_deps = target->deps(); 109 for (size_t i = 0; i < target_deps.size(); i++) 110 deps.push_back(target_deps[i].label); 111 112 const LabelTargetVector& target_datadeps = target->datadeps(); 113 for (size_t i = 0; i < target_datadeps.size(); i++) 114 deps.push_back(target_datadeps[i].label); 115 } 116 117 std::sort(deps.begin(), deps.end()); 118 for (size_t i = 0; i < deps.size(); i++) 119 OutputString(" " + deps[i].GetUserVisibleName(toolchain_label) + "\n"); 120 } 121 122 // libs and lib_dirs are special in that they're inherited. We don't currently 123 // implement a blame feature for this since the bottom-up inheritance makes 124 // this difficult. 125 void PrintLibDirs(const Target* target, bool display_header) { 126 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs(); 127 if (lib_dirs.empty()) 128 return; 129 130 if (display_header) 131 OutputString("\nlib_dirs\n"); 132 133 for (size_t i = 0; i < lib_dirs.size(); i++) 134 OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n"); 135 } 136 137 void PrintLibs(const Target* target, bool display_header) { 138 const OrderedSet<std::string>& libs = target->all_libs(); 139 if (libs.empty()) 140 return; 141 142 if (display_header) 143 OutputString("\nlibs\n"); 144 145 for (size_t i = 0; i < libs.size(); i++) 146 OutputString(" " + libs[i] + "\n"); 147 } 148 149 void PrintConfigs(const Target* target, bool display_header) { 150 // Configs (don't sort since the order determines how things are processed). 151 if (display_header) 152 OutputString("\nConfigs (in order applying):\n"); 153 154 Label toolchain_label = target->label().GetToolchainLabel(); 155 const LabelConfigVector& configs = target->configs(); 156 for (size_t i = 0; i < configs.size(); i++) { 157 OutputString(" " + 158 configs[i].label.GetUserVisibleName(toolchain_label) + "\n"); 159 } 160 } 161 162 void PrintSources(const Target* target, bool display_header) { 163 if (display_header) 164 OutputString("\nSources:\n"); 165 166 Target::FileList sources = target->sources(); 167 std::sort(sources.begin(), sources.end()); 168 for (size_t i = 0; i < sources.size(); i++) 169 OutputString(" " + sources[i].value() + "\n"); 170 } 171 172 // Attribute the origin for attributing from where a target came from. Does 173 // nothing if the input is null or it does not have a location. 174 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) { 175 if (!origin) 176 return; 177 Location location = origin->GetRange().begin(); 178 out << " (Added by " + location.file()->name().value() << ":" 179 << location.line_number() << ")\n"; 180 } 181 182 // Templatized writer for writing out different config value types. 183 template<typename T> struct DescValueWriter {}; 184 template<> struct DescValueWriter<std::string> { 185 void operator()(const std::string& str, std::ostream& out) const { 186 out << " " << str << "\n"; 187 } 188 }; 189 template<> struct DescValueWriter<SourceFile> { 190 void operator()(const SourceFile& file, std::ostream& out) const { 191 out << " " << file.value() << "\n"; 192 } 193 }; 194 template<> struct DescValueWriter<SourceDir> { 195 void operator()(const SourceDir& dir, std::ostream& out) const { 196 out << " " << FormatSourceDir(dir) << "\n"; 197 } 198 }; 199 200 // Writes a given config value type to the string, optionally with attribution. 201 // This should match RecursiveTargetConfigToStream in the order it traverses. 202 template<typename T> void OutputRecursiveTargetConfig( 203 const Target* target, 204 const char* header_name, 205 const std::vector<T>& (ConfigValues::* getter)() const) { 206 bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame"); 207 208 DescValueWriter<T> writer; 209 std::ostringstream out; 210 211 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { 212 if ((iter.cur().*getter)().empty()) 213 continue; 214 215 // Optional blame sub-head. 216 if (display_blame) { 217 const Config* config = iter.GetCurrentConfig(); 218 if (config) { 219 // Source of this value is a config. 220 out << " From " << config->label().GetUserVisibleName(false) << "\n"; 221 OutputSourceOfDep(iter.origin(), out); 222 } else { 223 // Source of this value is the target itself. 224 out << " From " << target->label().GetUserVisibleName(false) << "\n"; 225 } 226 } 227 228 // Actual values. 229 ConfigValuesToStream(iter.cur(), getter, writer, out); 230 } 231 232 std::string out_str = out.str(); 233 if (!out_str.empty()) { 234 OutputString("\n" + std::string(header_name) + "\n"); 235 OutputString(out_str); 236 } 237 } 238 239 } // namespace 240 241 // desc ------------------------------------------------------------------------ 242 243 const char kDesc[] = "desc"; 244 const char kDesc_HelpShort[] = 245 "desc: Show lots of insightful information about a target."; 246 const char kDesc_Help[] = 247 "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n" 248 " Displays information about a given labeled target.\n" 249 "\n" 250 "Possibilities for <what to show>:\n" 251 " (If unspecified an overall summary will be displayed.)\n" 252 "\n" 253 " sources\n" 254 " Source files.\n" 255 "\n" 256 " configs\n" 257 " Shows configs applied to the given target, sorted in the order\n" 258 " they're specified. This includes both configs specified in the\n" 259 " \"configs\" variable, as well as configs pushed onto this target\n" 260 " via dependencies specifying \"all\" or \"direct\" dependent\n" 261 " configs.\n" 262 "\n" 263 " deps [--all | --tree]\n" 264 " Show immediate (or, when \"--all\" or \"--tree\" is specified,\n" 265 " recursive) dependencies of the given target. \"--tree\" shows them\n" 266 " in a tree format. Otherwise, they will be sorted alphabetically.\n" 267 " Both \"deps\" and \"datadeps\" will be included.\n" 268 "\n" 269 " defines [--blame]\n" 270 " include_dirs [--blame]\n" 271 " cflags [--blame]\n" 272 " cflags_cc [--blame]\n" 273 " cflags_cxx [--blame]\n" 274 " ldflags [--blame]\n" 275 " lib_dirs\n" 276 " libs\n" 277 " Shows the given values taken from the target and all configs\n" 278 " applying. See \"--blame\" below.\n" 279 "\n" 280 " --blame\n" 281 " Used with any value specified by a config, this will name\n" 282 " the config that specified the value. This doesn't currently work\n" 283 " for libs and lib_dirs because those are inherited and are more\n" 284 " complicated to figure out the blame (patches welcome).\n" 285 "\n" 286 "Note:\n" 287 " This command will show the full name of directories and source files,\n" 288 " but when directories and source paths are written to the build file,\n" 289 " they will be adjusted to be relative to the build directory. So the\n" 290 " values for paths displayed by this command won't match (but should\n" 291 " mean the same thing.\n" 292 "\n" 293 "Examples:\n" 294 " gn desc //base:base\n" 295 " Summarizes the given target.\n" 296 "\n" 297 " gn desc :base_unittests deps --tree\n" 298 " Shows a dependency tree of the \"base_unittests\" project in\n" 299 " the current directory.\n" 300 "\n" 301 " gn desc //base defines --blame\n" 302 " Shows defines set for the //base:base target, annotated by where\n" 303 " each one was set from.\n"; 304 305 #define OUTPUT_CONFIG_VALUE(name, type) \ 306 OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name); 307 308 int RunDesc(const std::vector<std::string>& args) { 309 if (args.size() != 1 && args.size() != 2) { 310 Err(Location(), "You're holding it wrong.", 311 "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout(); 312 return 1; 313 } 314 315 const Target* target = GetTargetForDesc(args); 316 if (!target) 317 return 1; 318 319 #define CONFIG_VALUE_HANDLER(name, type) \ 320 } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type) 321 322 if (args.size() == 2) { 323 // User specified one thing to display. 324 const std::string& what = args[1]; 325 if (what == "configs") { 326 PrintConfigs(target, false); 327 } else if (what == "sources") { 328 PrintSources(target, false); 329 } else if (what == "deps") { 330 PrintDeps(target, false); 331 } else if (what == "lib_dirs") { 332 PrintLibDirs(target, false); 333 } else if (what == "libs") { 334 PrintLibs(target, false); 335 336 CONFIG_VALUE_HANDLER(defines, std::string) 337 CONFIG_VALUE_HANDLER(include_dirs, SourceDir) 338 CONFIG_VALUE_HANDLER(cflags, std::string) 339 CONFIG_VALUE_HANDLER(cflags_c, std::string) 340 CONFIG_VALUE_HANDLER(cflags_cc, std::string) 341 CONFIG_VALUE_HANDLER(cflags_objc, std::string) 342 CONFIG_VALUE_HANDLER(cflags_objcc, std::string) 343 CONFIG_VALUE_HANDLER(ldflags, std::string) 344 345 } else { 346 OutputString("Don't know how to display \"" + what + "\".\n"); 347 return 1; 348 } 349 350 #undef CONFIG_VALUE_HANDLER 351 return 0; 352 } 353 354 // Display summary. 355 356 // Generally we only want to display toolchains on labels when the toolchain 357 // is different than the default one for this target (which we always print 358 // in the header). 359 Label target_toolchain = target->label().GetToolchainLabel(); 360 361 // Header. 362 OutputString("Target: ", DECORATION_YELLOW); 363 OutputString(target->label().GetUserVisibleName(false) + "\n"); 364 OutputString("Type: ", DECORATION_YELLOW); 365 OutputString(std::string( 366 Target::GetStringForOutputType(target->output_type())) + "\n"); 367 OutputString("Toolchain: ", DECORATION_YELLOW); 368 OutputString(target_toolchain.GetUserVisibleName(false) + "\n"); 369 370 PrintSources(target, true); 371 PrintConfigs(target, true); 372 373 OUTPUT_CONFIG_VALUE(defines, std::string) 374 OUTPUT_CONFIG_VALUE(include_dirs, SourceDir) 375 OUTPUT_CONFIG_VALUE(cflags, std::string) 376 OUTPUT_CONFIG_VALUE(cflags_c, std::string) 377 OUTPUT_CONFIG_VALUE(cflags_cc, std::string) 378 OUTPUT_CONFIG_VALUE(cflags_objc, std::string) 379 OUTPUT_CONFIG_VALUE(cflags_objcc, std::string) 380 OUTPUT_CONFIG_VALUE(ldflags, std::string) 381 PrintLibs(target, true); 382 PrintLibDirs(target, true); 383 384 PrintDeps(target, true); 385 386 return 0; 387 } 388 389 } // namespace commands 390