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 <stddef.h> 6 7#include <map> 8#include <set> 9 10#include "base/command_line.h" 11#include "base/files/file_util.h" 12#include "base/strings/string_split.h" 13#include "base/strings/string_util.h" 14#include "gn/commands.h" 15#include "gn/config_values_extractors.h" 16#include "gn/deps_iterator.h" 17#include "gn/filesystem_utils.h" 18#include "gn/input_file.h" 19#include "gn/item.h" 20#include "gn/setup.h" 21#include "gn/standard_out.h" 22#include "gn/switches.h" 23#include "gn/target.h" 24 25namespace commands { 26 27namespace { 28 29using TargetSet = TargetSet; 30using TargetVector = std::vector<const Target*>; 31 32// Maps targets to the list of targets that depend on them. 33using DepMap = std::multimap<const Target*, const Target*>; 34 35// Populates the reverse dependency map for the targets in the Setup. 36void FillDepMap(Setup* setup, DepMap* dep_map) { 37 for (auto* target : setup->builder().GetAllResolvedTargets()) { 38 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) 39 dep_map->insert(std::make_pair(dep_pair.ptr, target)); 40 } 41} 42 43// Forward declaration for function below. 44size_t RecursivePrintTargetDeps(const DepMap& dep_map, 45 const Target* target, 46 TargetSet* seen_targets, 47 int indent_level); 48 49// Prints the target and its dependencies in tree form. If the set is non-null, 50// new targets encountered will be added to the set, and if a ref is in the set 51// already, it will not be recused into. When the set is null, all refs will be 52// printed. 53// 54// Returns the number of items printed. 55size_t RecursivePrintTarget(const DepMap& dep_map, 56 const Target* target, 57 TargetSet* seen_targets, 58 int indent_level) { 59 std::string indent(indent_level * 2, ' '); 60 size_t count = 1; 61 62 // Only print the toolchain for non-default-toolchain targets. 63 OutputString(indent + target->label().GetUserVisibleName( 64 !target->settings()->is_default())); 65 66 bool print_children = true; 67 if (seen_targets) { 68 if (!seen_targets->add(target)) { 69 // Already seen. 70 print_children = false; 71 // Only print "..." if something is actually elided, which means that 72 // the current target has children. 73 if (dep_map.lower_bound(target) != dep_map.upper_bound(target)) 74 OutputString("..."); 75 } 76 } 77 78 OutputString("\n"); 79 if (print_children) { 80 count += RecursivePrintTargetDeps(dep_map, target, seen_targets, 81 indent_level + 1); 82 } 83 return count; 84} 85 86// Prints refs of the given target (not the target itself). See 87// RecursivePrintTarget. 88size_t RecursivePrintTargetDeps(const DepMap& dep_map, 89 const Target* target, 90 TargetSet* seen_targets, 91 int indent_level) { 92 DepMap::const_iterator dep_begin = dep_map.lower_bound(target); 93 DepMap::const_iterator dep_end = dep_map.upper_bound(target); 94 size_t count = 0; 95 for (DepMap::const_iterator cur_dep = dep_begin; cur_dep != dep_end; 96 cur_dep++) { 97 count += RecursivePrintTarget(dep_map, cur_dep->second, seen_targets, 98 indent_level); 99 } 100 return count; 101} 102 103void RecursiveCollectChildRefs(const DepMap& dep_map, 104 const Target* target, 105 TargetSet* results); 106 107// Recursively finds all targets that reference the given one, and additionally 108// adds the current one to the list. 109void RecursiveCollectRefs(const DepMap& dep_map, 110 const Target* target, 111 TargetSet* results) { 112 if (!results->add(target)) 113 return; // Already found this target. 114 RecursiveCollectChildRefs(dep_map, target, results); 115} 116 117// Recursively finds all targets that reference the given one. 118void RecursiveCollectChildRefs(const DepMap& dep_map, 119 const Target* target, 120 TargetSet* results) { 121 DepMap::const_iterator dep_begin = dep_map.lower_bound(target); 122 DepMap::const_iterator dep_end = dep_map.upper_bound(target); 123 for (DepMap::const_iterator cur_dep = dep_begin; cur_dep != dep_end; 124 cur_dep++) 125 RecursiveCollectRefs(dep_map, cur_dep->second, results); 126} 127 128bool TargetReferencesConfig(const Target* target, const Config* config) { 129 for (const LabelConfigPair& cur : target->configs()) { 130 if (cur.ptr == config) 131 return true; 132 } 133 for (const LabelConfigPair& cur : target->public_configs()) { 134 if (cur.ptr == config) 135 return true; 136 } 137 return false; 138} 139 140void GetTargetsReferencingConfig(Setup* setup, 141 const std::vector<const Target*>& all_targets, 142 const Config* config, 143 bool default_toolchain_only, 144 UniqueVector<const Target*>* matches) { 145 Label default_toolchain = setup->loader()->default_toolchain_label(); 146 for (auto* target : all_targets) { 147 if (default_toolchain_only) { 148 // Only check targets in the default toolchain. 149 if (target->label().GetToolchainLabel() != default_toolchain) 150 continue; 151 } 152 if (TargetReferencesConfig(target, config)) 153 matches->push_back(target); 154 } 155} 156 157// Returns the number of matches printed. 158size_t DoTreeOutput(const DepMap& dep_map, 159 const UniqueVector<const Target*>& implicit_target_matches, 160 const UniqueVector<const Target*>& explicit_target_matches, 161 bool all) { 162 TargetSet seen_targets; 163 size_t count = 0; 164 165 // Implicit targets don't get printed themselves. 166 for (const Target* target : implicit_target_matches) { 167 if (all) 168 count += RecursivePrintTargetDeps(dep_map, target, nullptr, 0); 169 else 170 count += RecursivePrintTargetDeps(dep_map, target, &seen_targets, 0); 171 } 172 173 // Explicit targets appear in the output. 174 for (const Target* target : implicit_target_matches) { 175 if (all) 176 count += RecursivePrintTarget(dep_map, target, nullptr, 0); 177 else 178 count += RecursivePrintTarget(dep_map, target, &seen_targets, 0); 179 } 180 181 return count; 182} 183 184// Returns the number of matches printed. 185size_t DoAllListOutput( 186 const DepMap& dep_map, 187 const UniqueVector<const Target*>& implicit_target_matches, 188 const UniqueVector<const Target*>& explicit_target_matches) { 189 // Output recursive dependencies, uniquified and flattened. 190 TargetSet results; 191 192 for (const Target* target : implicit_target_matches) 193 RecursiveCollectChildRefs(dep_map, target, &results); 194 for (const Target* target : explicit_target_matches) { 195 // Explicit targets also get added to the output themselves. 196 results.insert(target); 197 RecursiveCollectChildRefs(dep_map, target, &results); 198 } 199 200 FilterAndPrintTargetSet(false, results); 201 return results.size(); 202} 203 204// Returns the number of matches printed. 205size_t DoDirectListOutput( 206 const DepMap& dep_map, 207 const UniqueVector<const Target*>& implicit_target_matches, 208 const UniqueVector<const Target*>& explicit_target_matches) { 209 TargetSet results; 210 211 // Output everything that refers to the implicit ones. 212 for (const Target* target : implicit_target_matches) { 213 DepMap::const_iterator dep_begin = dep_map.lower_bound(target); 214 DepMap::const_iterator dep_end = dep_map.upper_bound(target); 215 for (DepMap::const_iterator cur_dep = dep_begin; cur_dep != dep_end; 216 cur_dep++) 217 results.insert(cur_dep->second); 218 } 219 220 // And just output the explicit ones directly (these are the target matches 221 // when referring to what references a file or config). 222 for (const Target* target : explicit_target_matches) 223 results.insert(target); 224 225 FilterAndPrintTargetSet(false, results); 226 return results.size(); 227} 228 229} // namespace 230 231const char kRefs[] = "refs"; 232const char kRefs_HelpShort[] = "refs: Find stuff referencing a target or file."; 233const char kRefs_Help[] = 234 R"(gn refs 235 236 gn refs <out_dir> (<label_pattern>|<label>|<file>|@<response_file>)* [--all] 237 [--default-toolchain] [--as=...] [--testonly=...] [--type=...] 238 239 Finds reverse dependencies (which targets reference something). The input is 240 a list containing: 241 242 - Target label: The result will be which targets depend on it. 243 244 - Config label: The result will be which targets list the given config in 245 its "configs" or "public_configs" list. 246 247 - Label pattern: The result will be which targets depend on any target 248 matching the given pattern. Patterns will not match configs. These are not 249 general regular expressions, see "gn help label_pattern" for details. 250 251 - File name: The result will be which targets list the given file in its 252 "inputs", "sources", "public", "data", or "outputs". Any input that does 253 not contain wildcards and does not match a target or a config will be 254 treated as a file. 255 256 - Response file: If the input starts with an "@", it will be interpreted as 257 a path to a file containing a list of labels or file names, one per line. 258 This allows us to handle long lists of inputs without worrying about 259 command line limits. 260 261Options 262 263 --all 264 When used without --tree, will recurse and display all unique 265 dependencies of the given targets. For example, if the input is a target, 266 this will output all targets that depend directly or indirectly on the 267 input. If the input is a file, this will output all targets that depend 268 directly or indirectly on that file. 269 270 When used with --tree, turns off eliding to show a complete tree. 271 272)" 273 274 TARGET_PRINTING_MODE_COMMAND_LINE_HELP "\n" DEFAULT_TOOLCHAIN_SWITCH_HELP 275 276 R"( 277 -q 278 Quiet. If nothing matches, don't print any output. Without this option, if 279 there are no matches there will be an informational message printed which 280 might interfere with scripts processing the output. 281 282)" 283 284 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP 285 286 R"( 287 --tree 288 Outputs a reverse dependency tree from the given target. Duplicates will 289 be elided. Combine with --all to see a full dependency tree. 290 291 Tree output can not be used with the filtering or output flags: --as, 292 --type, --testonly. 293 294)" 295 296 TARGET_TYPE_FILTER_COMMAND_LINE_HELP 297 298 R"( 299 300Examples (target input) 301 302 gn refs out/Debug //gn:gn 303 Find all targets depending on the given exact target name. 304 305 gn refs out/Debug //base:i18n --as=buildfile | xargs gvim 306 Edit all .gn files containing references to //base:i18n 307 308 gn refs out/Debug //base --all 309 List all targets depending directly or indirectly on //base:base. 310 311 gn refs out/Debug "//base/*" 312 List all targets depending directly on any target in //base or 313 its subdirectories. 314 315 gn refs out/Debug "//base:*" 316 List all targets depending directly on any target in 317 //base/BUILD.gn. 318 319 gn refs out/Debug //base --tree 320 Print a reverse dependency tree of //base:base 321 322Examples (file input) 323 324 gn refs out/Debug //base/macros.h 325 Print target(s) listing //base/macros.h as a source. 326 327 gn refs out/Debug //base/macros.h --tree 328 Display a reverse dependency tree to get to the given file. This 329 will show how dependencies will reference that file. 330 331 gn refs out/Debug //base/macros.h //base/at_exit.h --all 332 Display all unique targets with some dependency path to a target 333 containing either of the given files as a source. 334 335 gn refs out/Debug //base/macros.h --testonly=true --type=executable 336 --all --as=output 337 Display the executable file names of all test executables 338 potentially affected by a change to the given file. 339)"; 340 341int RunRefs(const std::vector<std::string>& args) { 342 if (args.size() <= 1) { 343 Err(Location(), "Unknown command format. See \"gn help refs\"", 344 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)*\"") 345 .PrintToStdout(); 346 return 1; 347 } 348 349 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); 350 bool tree = cmdline->HasSwitch("tree"); 351 bool all = cmdline->HasSwitch("all"); 352 bool default_toolchain_only = cmdline->HasSwitch(switches::kDefaultToolchain); 353 354 // Deliberately leaked to avoid expensive process teardown. 355 Setup* setup = new Setup; 356 if (!setup->DoSetup(args[0], false) || !setup->Run()) 357 return 1; 358 359 // The inputs are everything but the first arg (which is the build dir). 360 std::vector<std::string> inputs; 361 for (size_t i = 1; i < args.size(); i++) { 362 if (args[i][0] == '@') { 363 // The argument is as a path to a response file. 364 std::string contents; 365 bool ret = 366 base::ReadFileToString(UTF8ToFilePath(args[i].substr(1)), &contents); 367 if (!ret) { 368 Err(Location(), "Response file " + args[i].substr(1) + " not found.") 369 .PrintToStdout(); 370 return 1; 371 } 372 for (const std::string& line : base::SplitString( 373 contents, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { 374 if (!line.empty()) 375 inputs.push_back(line); 376 } 377 } else { 378 // The argument is a label or a path. 379 inputs.push_back(args[i]); 380 } 381 } 382 383 // Get the matches for the command-line input. 384 UniqueVector<const Target*> target_matches; 385 UniqueVector<const Config*> config_matches; 386 UniqueVector<const Toolchain*> toolchain_matches; 387 UniqueVector<SourceFile> file_matches; 388 if (!ResolveFromCommandLineInput(setup, inputs, default_toolchain_only, 389 &target_matches, &config_matches, 390 &toolchain_matches, &file_matches)) 391 return 1; 392 393 // When you give a file or config as an input, you want the targets that are 394 // associated with it. We don't want to just append this to the 395 // target_matches, however, since these targets should actually be listed in 396 // the output, while for normal targets you don't want to see the inputs, 397 // only what refers to them. 398 std::vector<const Target*> all_targets = 399 setup->builder().GetAllResolvedTargets(); 400 UniqueVector<const Target*> explicit_target_matches; 401 for (const auto& file : file_matches) { 402 std::vector<TargetContainingFile> target_containing; 403 GetTargetsContainingFile(setup, all_targets, file, default_toolchain_only, 404 &target_containing); 405 406 // Extract just the Target*. 407 for (const TargetContainingFile& pair : target_containing) 408 explicit_target_matches.push_back(pair.first); 409 } 410 for (auto* config : config_matches) { 411 GetTargetsReferencingConfig(setup, all_targets, config, 412 default_toolchain_only, 413 &explicit_target_matches); 414 } 415 416 // Tell the user if their input matches no files or labels. We need to check 417 // both that it matched no targets and no configs. File input will already 418 // have been converted to targets at this point. Configs will have been 419 // converted to targets also, but there could be no targets referencing the 420 // config, which is different than no config with that name. 421 bool quiet = cmdline->HasSwitch("q"); 422 if (!quiet && config_matches.empty() && explicit_target_matches.empty() && 423 target_matches.empty()) { 424 OutputString("The input matches no targets, configs, or files.\n", 425 DECORATION_YELLOW); 426 return 1; 427 } 428 429 // Construct the reverse dependency tree. 430 DepMap dep_map; 431 FillDepMap(setup, &dep_map); 432 433 size_t cnt = 0; 434 if (tree) 435 cnt = DoTreeOutput(dep_map, target_matches, explicit_target_matches, all); 436 else if (all) 437 cnt = DoAllListOutput(dep_map, target_matches, explicit_target_matches); 438 else 439 cnt = DoDirectListOutput(dep_map, target_matches, explicit_target_matches); 440 441 // If you ask for the references of a valid target, but that target has 442 // nothing referencing it, we'll get here without having printed anything. 443 if (!quiet && cnt == 0) 444 OutputString("Nothing references this.\n", DECORATION_YELLOW); 445 446 return 0; 447} 448 449} // namespace commands 450