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
25 namespace commands {
26
27 namespace {
28
29 using TargetSet = TargetSet;
30 using TargetVector = std::vector<const Target*>;
31
32 // Maps targets to the list of targets that depend on them.
33 using DepMap = std::multimap<const Target*, const Target*>;
34
35 // Populates the reverse dependency map for the targets in the Setup.
FillDepMap(Setup * setup,DepMap * dep_map)36 void 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.
44 size_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.
RecursivePrintTarget(const DepMap & dep_map,const Target * target,TargetSet * seen_targets,int indent_level)55 size_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.
RecursivePrintTargetDeps(const DepMap & dep_map,const Target * target,TargetSet * seen_targets,int indent_level)88 size_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
103 void 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.
RecursiveCollectRefs(const DepMap & dep_map,const Target * target,TargetSet * results)109 void 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.
RecursiveCollectChildRefs(const DepMap & dep_map,const Target * target,TargetSet * results)118 void 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
TargetReferencesConfig(const Target * target,const Config * config)128 bool 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
GetTargetsReferencingConfig(Setup * setup,const std::vector<const Target * > & all_targets,const Config * config,bool default_toolchain_only,UniqueVector<const Target * > * matches)140 void 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.
DoTreeOutput(const DepMap & dep_map,const UniqueVector<const Target * > & implicit_target_matches,const UniqueVector<const Target * > & explicit_target_matches,bool all)158 size_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.
DoAllListOutput(const DepMap & dep_map,const UniqueVector<const Target * > & implicit_target_matches,const UniqueVector<const Target * > & explicit_target_matches)185 size_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.
DoDirectListOutput(const DepMap & dep_map,const UniqueVector<const Target * > & implicit_target_matches,const UniqueVector<const Target * > & explicit_target_matches)205 size_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
231 const char kRefs[] = "refs";
232 const char kRefs_HelpShort[] = "refs: Find stuff referencing a target or file.";
233 const 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
261 Options
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
300 Examples (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=buildfiles | 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
322 Examples (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
RunRefs(const std::vector<std::string> & args)341 int 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