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/file_template.h" 14 #include "tools/gn/filesystem_utils.h" 15 #include "tools/gn/item.h" 16 #include "tools/gn/label.h" 17 #include "tools/gn/setup.h" 18 #include "tools/gn/standard_out.h" 19 #include "tools/gn/target.h" 20 21 namespace commands { 22 23 namespace { 24 25 // Prints the given directory in a nice way for the user to view. 26 std::string FormatSourceDir(const SourceDir& dir) { 27 #if defined(OS_WIN) 28 // On Windows we fix up system absolute paths to look like native ones. 29 // Internally, they'll look like "/C:\foo\bar/" 30 if (dir.is_system_absolute()) { 31 std::string buf = dir.value(); 32 if (buf.size() > 3 && buf[2] == ':') { 33 buf.erase(buf.begin()); // Erase beginning slash. 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 // Don't print groups. Groups are flattened such that the deps of the 74 // group are added directly to the target that depended on the group. 75 // Printing and recursing into groups here will cause such targets to be 76 // duplicated. 77 // 78 // It would be much more intuitive to do the opposite and not display the 79 // deps that were copied from the group to the target and instead display 80 // the group, but the source of those dependencies is not tracked. 81 if (sorted_deps[i].ptr->output_type() == Target::GROUP) 82 continue; 83 84 OutputString(indent + 85 sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n"); 86 RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1); 87 } 88 } 89 90 void PrintDeps(const Target* target, bool display_header) { 91 const CommandLine* cmdline = CommandLine::ForCurrentProcess(); 92 Label toolchain_label = target->label().GetToolchainLabel(); 93 94 // Tree mode is separate. 95 if (cmdline->HasSwitch("tree")) { 96 if (display_header) 97 OutputString("\nDependency tree:\n"); 98 RecursivePrintDeps(target, toolchain_label, 1); 99 return; 100 } 101 102 // Collect the deps to display. 103 std::vector<Label> deps; 104 if (cmdline->HasSwitch("all")) { 105 if (display_header) 106 OutputString("\nAll recursive dependencies:\n"); 107 108 std::set<Label> all_deps; 109 RecursiveCollectChildDeps(target, &all_deps); 110 for (std::set<Label>::iterator i = all_deps.begin(); 111 i != all_deps.end(); ++i) 112 deps.push_back(*i); 113 } else { 114 if (display_header) { 115 OutputString("\nDirect dependencies " 116 "(try also \"--all\" and \"--tree\"):\n"); 117 } 118 119 const LabelTargetVector& target_deps = target->deps(); 120 for (size_t i = 0; i < target_deps.size(); i++) 121 deps.push_back(target_deps[i].label); 122 123 const LabelTargetVector& target_datadeps = target->datadeps(); 124 for (size_t i = 0; i < target_datadeps.size(); i++) 125 deps.push_back(target_datadeps[i].label); 126 } 127 128 std::sort(deps.begin(), deps.end()); 129 for (size_t i = 0; i < deps.size(); i++) 130 OutputString(" " + deps[i].GetUserVisibleName(toolchain_label) + "\n"); 131 } 132 133 void PrintForwardDependentConfigsFrom(const Target* target, 134 bool display_header) { 135 if (target->forward_dependent_configs().empty()) 136 return; 137 138 if (display_header) 139 OutputString("\nforward_dependent_configs_from:\n"); 140 141 // Collect the sorted list of deps. 142 std::vector<Label> forward; 143 for (size_t i = 0; i < target->forward_dependent_configs().size(); i++) 144 forward.push_back(target->forward_dependent_configs()[i].label); 145 std::sort(forward.begin(), forward.end()); 146 147 Label toolchain_label = target->label().GetToolchainLabel(); 148 for (size_t i = 0; i < forward.size(); i++) 149 OutputString(" " + forward[i].GetUserVisibleName(toolchain_label) + "\n"); 150 } 151 152 // libs and lib_dirs are special in that they're inherited. We don't currently 153 // implement a blame feature for this since the bottom-up inheritance makes 154 // this difficult. 155 void PrintLibDirs(const Target* target, bool display_header) { 156 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs(); 157 if (lib_dirs.empty()) 158 return; 159 160 if (display_header) 161 OutputString("\nlib_dirs\n"); 162 163 for (size_t i = 0; i < lib_dirs.size(); i++) 164 OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n"); 165 } 166 167 void PrintLibs(const Target* target, bool display_header) { 168 const OrderedSet<std::string>& libs = target->all_libs(); 169 if (libs.empty()) 170 return; 171 172 if (display_header) 173 OutputString("\nlibs\n"); 174 175 for (size_t i = 0; i < libs.size(); i++) 176 OutputString(" " + libs[i] + "\n"); 177 } 178 179 void PrintPublic(const Target* target, bool display_header) { 180 if (display_header) 181 OutputString("\npublic:\n"); 182 183 if (target->all_headers_public()) { 184 OutputString(" [All headers listed in the sources are public.]\n"); 185 return; 186 } 187 188 Target::FileList public_headers = target->public_headers(); 189 std::sort(public_headers.begin(), public_headers.end()); 190 for (size_t i = 0; i < public_headers.size(); i++) 191 OutputString(" " + public_headers[i].value() + "\n"); 192 } 193 194 void PrintVisibility(const Target* target, bool display_header) { 195 if (display_header) 196 OutputString("\nvisibility:\n"); 197 198 OutputString(target->visibility().Describe(2, false)); 199 } 200 201 void PrintConfigsVector(const Target* target, 202 const LabelConfigVector& configs, 203 const std::string& heading, 204 bool display_header) { 205 if (configs.empty()) 206 return; 207 208 // Don't sort since the order determines how things are processed. 209 if (display_header) 210 OutputString("\n" + heading + " (in order applying):\n"); 211 212 Label toolchain_label = target->label().GetToolchainLabel(); 213 for (size_t i = 0; i < configs.size(); i++) { 214 OutputString(" " + 215 configs[i].label.GetUserVisibleName(toolchain_label) + "\n"); 216 } 217 } 218 219 void PrintConfigs(const Target* target, bool display_header) { 220 PrintConfigsVector(target, target->configs(), "configs", display_header); 221 } 222 223 void PrintDirectDependentConfigs(const Target* target, bool display_header) { 224 PrintConfigsVector(target, target->direct_dependent_configs(), 225 "direct_dependent_configs", display_header); 226 } 227 228 void PrintAllDependentConfigs(const Target* target, bool display_header) { 229 PrintConfigsVector(target, target->all_dependent_configs(), 230 "all_dependent_configs", display_header); 231 } 232 233 void PrintFileList(const Target::FileList& files, 234 const std::string& header, 235 bool indent_extra, 236 bool display_header) { 237 if (files.empty()) 238 return; 239 240 if (display_header) 241 OutputString("\n" + header + ":\n"); 242 243 std::string indent = indent_extra ? " " : " "; 244 245 Target::FileList sorted = files; 246 std::sort(sorted.begin(), sorted.end()); 247 for (size_t i = 0; i < sorted.size(); i++) 248 OutputString(indent + sorted[i].value() + "\n"); 249 } 250 251 void PrintSources(const Target* target, bool display_header) { 252 PrintFileList(target->sources(), "sources", false, display_header); 253 } 254 255 void PrintInputs(const Target* target, bool display_header) { 256 PrintFileList(target->inputs(), "inputs", false, display_header); 257 } 258 259 void PrintOutputs(const Target* target, bool display_header) { 260 if (target->output_type() == Target::ACTION) { 261 // Just display the outputs directly. 262 PrintFileList(target->action_values().outputs(), "outputs", false, 263 display_header); 264 } else if (target->output_type() == Target::ACTION_FOREACH) { 265 // Display both the output pattern and resolved list. 266 if (display_header) 267 OutputString("\noutputs:\n"); 268 269 // Display the pattern. 270 OutputString(" Output pattern:\n"); 271 PrintFileList(target->action_values().outputs(), "", true, false); 272 273 // Now display what that resolves to given the sources. 274 OutputString("\n Resolved output file list:\n"); 275 276 std::vector<std::string> output_strings; 277 FileTemplate file_template = FileTemplate::GetForTargetOutputs(target); 278 for (size_t i = 0; i < target->sources().size(); i++) 279 file_template.Apply(target->sources()[i], &output_strings); 280 281 std::sort(output_strings.begin(), output_strings.end()); 282 for (size_t i = 0; i < output_strings.size(); i++) { 283 OutputString(" " + output_strings[i] + "\n"); 284 } 285 } 286 } 287 288 void PrintScript(const Target* target, bool display_header) { 289 if (display_header) 290 OutputString("\nscript:\n"); 291 OutputString(" " + target->action_values().script().value() + "\n"); 292 } 293 294 void PrintArgs(const Target* target, bool display_header) { 295 if (display_header) 296 OutputString("\nargs:\n"); 297 for (size_t i = 0; i < target->action_values().args().size(); i++) 298 OutputString(" " + target->action_values().args()[i] + "\n"); 299 } 300 301 void PrintDepfile(const Target* target, bool display_header) { 302 if (target->action_values().depfile().value().empty()) 303 return; 304 if (display_header) 305 OutputString("\ndepfile:\n"); 306 OutputString(" " + target->action_values().depfile().value() + "\n"); 307 } 308 309 // Attribute the origin for attributing from where a target came from. Does 310 // nothing if the input is null or it does not have a location. 311 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) { 312 if (!origin) 313 return; 314 Location location = origin->GetRange().begin(); 315 out << " (Added by " + location.file()->name().value() << ":" 316 << location.line_number() << ")\n"; 317 } 318 319 // Templatized writer for writing out different config value types. 320 template<typename T> struct DescValueWriter {}; 321 template<> struct DescValueWriter<std::string> { 322 void operator()(const std::string& str, std::ostream& out) const { 323 out << " " << str << "\n"; 324 } 325 }; 326 template<> struct DescValueWriter<SourceDir> { 327 void operator()(const SourceDir& dir, std::ostream& out) const { 328 out << " " << FormatSourceDir(dir) << "\n"; 329 } 330 }; 331 332 // Writes a given config value type to the string, optionally with attribution. 333 // This should match RecursiveTargetConfigToStream in the order it traverses. 334 template<typename T> void OutputRecursiveTargetConfig( 335 const Target* target, 336 const char* header_name, 337 const std::vector<T>& (ConfigValues::* getter)() const) { 338 bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame"); 339 340 DescValueWriter<T> writer; 341 std::ostringstream out; 342 343 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) { 344 if ((iter.cur().*getter)().empty()) 345 continue; 346 347 // Optional blame sub-head. 348 if (display_blame) { 349 const Config* config = iter.GetCurrentConfig(); 350 if (config) { 351 // Source of this value is a config. 352 out << " From " << config->label().GetUserVisibleName(false) << "\n"; 353 OutputSourceOfDep(iter.origin(), out); 354 } else { 355 // Source of this value is the target itself. 356 out << " From " << target->label().GetUserVisibleName(false) << "\n"; 357 } 358 } 359 360 // Actual values. 361 ConfigValuesToStream(iter.cur(), getter, writer, out); 362 } 363 364 std::string out_str = out.str(); 365 if (!out_str.empty()) { 366 OutputString("\n" + std::string(header_name) + "\n"); 367 OutputString(out_str); 368 } 369 } 370 371 } // namespace 372 373 // desc ------------------------------------------------------------------------ 374 375 const char kDesc[] = "desc"; 376 const char kDesc_HelpShort[] = 377 "desc: Show lots of insightful information about a target."; 378 const char kDesc_Help[] = 379 "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n" 380 " Displays information about a given labeled target.\n" 381 "\n" 382 "Possibilities for <what to show>:\n" 383 " (If unspecified an overall summary will be displayed.)\n" 384 "\n" 385 " sources\n" 386 " Source files.\n" 387 "\n" 388 " inputs\n" 389 " Additional input dependencies.\n" 390 "\n" 391 " public\n" 392 " Public header files.\n" 393 "\n" 394 " visibility\n" 395 " Prints which targets can depend on this one.\n" 396 "\n" 397 " configs\n" 398 " Shows configs applied to the given target, sorted in the order\n" 399 " they're specified. This includes both configs specified in the\n" 400 " \"configs\" variable, as well as configs pushed onto this target\n" 401 " via dependencies specifying \"all\" or \"direct\" dependent\n" 402 " configs.\n" 403 "\n" 404 " deps [--all | --tree]\n" 405 " Show immediate (or, when \"--all\" or \"--tree\" is specified,\n" 406 " recursive) dependencies of the given target. \"--tree\" shows them\n" 407 " in a tree format. Otherwise, they will be sorted alphabetically.\n" 408 " Both \"deps\" and \"datadeps\" will be included.\n" 409 "\n" 410 " direct_dependent_configs\n" 411 " all_dependent_configs\n" 412 " Shows the labels of configs applied to targets that depend on this\n" 413 " one (either directly or all of them).\n" 414 "\n" 415 " forward_dependent_configs_from\n" 416 " Shows the labels of dependencies for which dependent configs will\n" 417 " be pushed to targets depending on the current one.\n" 418 "\n" 419 " script\n" 420 " args\n" 421 " depfile\n" 422 " Actions only. The script and related values.\n" 423 "\n" 424 " outputs\n" 425 " Outputs for script and copy target types.\n" 426 "\n" 427 " defines [--blame]\n" 428 " include_dirs [--blame]\n" 429 " cflags [--blame]\n" 430 " cflags_cc [--blame]\n" 431 " cflags_cxx [--blame]\n" 432 " ldflags [--blame]\n" 433 " lib_dirs\n" 434 " libs\n" 435 " Shows the given values taken from the target and all configs\n" 436 " applying. See \"--blame\" below.\n" 437 "\n" 438 " --blame\n" 439 " Used with any value specified by a config, this will name\n" 440 " the config that specified the value. This doesn't currently work\n" 441 " for libs and lib_dirs because those are inherited and are more\n" 442 " complicated to figure out the blame (patches welcome).\n" 443 "\n" 444 "Note:\n" 445 " This command will show the full name of directories and source files,\n" 446 " but when directories and source paths are written to the build file,\n" 447 " they will be adjusted to be relative to the build directory. So the\n" 448 " values for paths displayed by this command won't match (but should\n" 449 " mean the same thing).\n" 450 "\n" 451 "Examples:\n" 452 " gn desc //base:base\n" 453 " Summarizes the given target.\n" 454 "\n" 455 " gn desc :base_unittests deps --tree\n" 456 " Shows a dependency tree of the \"base_unittests\" project in\n" 457 " the current directory.\n" 458 "\n" 459 " gn desc //base defines --blame\n" 460 " Shows defines set for the //base:base target, annotated by where\n" 461 " each one was set from.\n"; 462 463 #define OUTPUT_CONFIG_VALUE(name, type) \ 464 OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name); 465 466 int RunDesc(const std::vector<std::string>& args) { 467 if (args.size() != 1 && args.size() != 2) { 468 Err(Location(), "You're holding it wrong.", 469 "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout(); 470 return 1; 471 } 472 473 const Target* target = GetTargetForDesc(args); 474 if (!target) 475 return 1; 476 477 #define CONFIG_VALUE_HANDLER(name, type) \ 478 } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type) 479 480 if (args.size() == 2) { 481 // User specified one thing to display. 482 const std::string& what = args[1]; 483 if (what == "configs") { 484 PrintConfigs(target, false); 485 } else if (what == "direct_dependent_configs") { 486 PrintDirectDependentConfigs(target, false); 487 } else if (what == "all_dependent_configs") { 488 PrintAllDependentConfigs(target, false); 489 } else if (what == "forward_dependent_configs_from") { 490 PrintForwardDependentConfigsFrom(target, false); 491 } else if (what == "sources") { 492 PrintSources(target, false); 493 } else if (what == "public") { 494 PrintPublic(target, false); 495 } else if (what == "visibility") { 496 PrintVisibility(target, false); 497 } else if (what == "inputs") { 498 PrintInputs(target, false); 499 } else if (what == "script") { 500 PrintScript(target, false); 501 } else if (what == "args") { 502 PrintArgs(target, false); 503 } else if (what == "depfile") { 504 PrintDepfile(target, false); 505 } else if (what == "outputs") { 506 PrintOutputs(target, false); 507 } else if (what == "deps") { 508 PrintDeps(target, false); 509 } else if (what == "lib_dirs") { 510 PrintLibDirs(target, false); 511 } else if (what == "libs") { 512 PrintLibs(target, false); 513 514 CONFIG_VALUE_HANDLER(defines, std::string) 515 CONFIG_VALUE_HANDLER(include_dirs, SourceDir) 516 CONFIG_VALUE_HANDLER(cflags, std::string) 517 CONFIG_VALUE_HANDLER(cflags_c, std::string) 518 CONFIG_VALUE_HANDLER(cflags_cc, std::string) 519 CONFIG_VALUE_HANDLER(cflags_objc, std::string) 520 CONFIG_VALUE_HANDLER(cflags_objcc, std::string) 521 CONFIG_VALUE_HANDLER(ldflags, std::string) 522 523 } else { 524 OutputString("Don't know how to display \"" + what + "\".\n"); 525 return 1; 526 } 527 528 #undef CONFIG_VALUE_HANDLER 529 return 0; 530 } 531 532 // Display summary. 533 534 // Display this only applicable to binary targets. 535 bool is_binary_output = 536 target->output_type() != Target::GROUP && 537 target->output_type() != Target::COPY_FILES && 538 target->output_type() != Target::ACTION && 539 target->output_type() != Target::ACTION_FOREACH; 540 541 // Generally we only want to display toolchains on labels when the toolchain 542 // is different than the default one for this target (which we always print 543 // in the header). 544 Label target_toolchain = target->label().GetToolchainLabel(); 545 546 // Header. 547 OutputString("Target: ", DECORATION_YELLOW); 548 OutputString(target->label().GetUserVisibleName(false) + "\n"); 549 OutputString("Type: ", DECORATION_YELLOW); 550 OutputString(std::string( 551 Target::GetStringForOutputType(target->output_type())) + "\n"); 552 OutputString("Toolchain: ", DECORATION_YELLOW); 553 OutputString(target_toolchain.GetUserVisibleName(false) + "\n"); 554 555 PrintSources(target, true); 556 if (is_binary_output) 557 PrintPublic(target, true); 558 PrintVisibility(target, true); 559 if (is_binary_output) 560 PrintConfigs(target, true); 561 562 PrintDirectDependentConfigs(target, true); 563 PrintAllDependentConfigs(target, true); 564 PrintForwardDependentConfigsFrom(target, true); 565 566 PrintInputs(target, true); 567 568 if (is_binary_output) { 569 OUTPUT_CONFIG_VALUE(defines, std::string) 570 OUTPUT_CONFIG_VALUE(include_dirs, SourceDir) 571 OUTPUT_CONFIG_VALUE(cflags, std::string) 572 OUTPUT_CONFIG_VALUE(cflags_c, std::string) 573 OUTPUT_CONFIG_VALUE(cflags_cc, std::string) 574 OUTPUT_CONFIG_VALUE(cflags_objc, std::string) 575 OUTPUT_CONFIG_VALUE(cflags_objcc, std::string) 576 OUTPUT_CONFIG_VALUE(ldflags, std::string) 577 } 578 579 if (target->output_type() == Target::ACTION || 580 target->output_type() == Target::ACTION_FOREACH) { 581 PrintScript(target, true); 582 PrintArgs(target, true); 583 PrintDepfile(target, true); 584 } 585 586 if (target->output_type() == Target::ACTION || 587 target->output_type() == Target::ACTION_FOREACH || 588 target->output_type() == Target::COPY_FILES) { 589 PrintOutputs(target, true); 590 } 591 592 // Libs can be part of any target and get recursively pushed up the chain, 593 // so always display them, even for groups and such. 594 PrintLibs(target, true); 595 PrintLibDirs(target, true); 596 597 PrintDeps(target, true); 598 599 return 0; 600 } 601 602 } // namespace commands 603