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.
8 #include "base/command_line.h"
9 #include "tools/gn/commands.h"
10 #include "tools/gn/deps_iterator.h"
11 #include "tools/gn/filesystem_utils.h"
12 #include "tools/gn/input_file.h"
13 #include "tools/gn/item.h"
14 #include "tools/gn/setup.h"
15 #include "tools/gn/standard_out.h"
16 #include "tools/gn/target.h"
22 typedef std::set
<const Target
*> TargetSet
;
23 typedef std::vector
<const Target
*> TargetVector
;
25 // Maps targets to the list of targets that depend on them.
26 typedef std::multimap
<const Target
*, const Target
*> DepMap
;
28 // Populates the reverse dependency map for the targets in the Setup.
29 void FillDepMap(Setup
* setup
, DepMap
* dep_map
) {
30 for (const auto& target
: setup
->builder()->GetAllResolvedTargets()) {
31 for (const auto& dep_pair
: target
->GetDeps(Target::DEPS_ALL
))
32 dep_map
->insert(std::make_pair(dep_pair
.ptr
, target
));
36 // Returns the file path generating this item.
37 base::FilePath
FilePathForItem(const Item
* item
) {
38 return item
->defined_from()->GetRange().begin().file()->physical_name();
41 // Prints the targets which are the result of a query. This list is sorted
42 // and, if as_files is set, the unique filenames matching those targets will
44 void OutputResultSet(const TargetSet
& results
, bool as_files
) {
49 // Output the set of unique source files.
50 std::set
<std::string
> unique_files
;
51 for (const auto& cur
: results
)
52 unique_files
.insert(FilePathToUTF8(FilePathForItem(cur
)));
54 for (const auto& cur
: unique_files
)
55 OutputString(cur
+ "\n");
57 // Output sorted and uniquified list of labels. The set will sort the
59 std::set
<Label
> unique_labels
;
60 for (const auto& cur
: results
)
61 unique_labels
.insert(cur
->label());
63 // Grab the label of the default toolchain from a random target.
64 Label default_tc_label
=
65 (*results
.begin())->settings()->default_toolchain_label();
67 for (const auto& cur
: unique_labels
) {
68 // Print toolchain only for ones not in the default toolchain.
69 OutputString(cur
.GetUserVisibleName(
70 cur
.GetToolchainLabel() != default_tc_label
));
76 // Prints refs of the given target (not the target itself). If the set is
77 // non-null, new targets encountered will be added to the set, and if a ref is
78 // in the set already, it will not be recused into. When the set is null, all
79 // refs will be printed.
80 void RecursivePrintTree(const DepMap
& dep_map
,
82 TargetSet
* seen_targets
,
84 std::string
indent(indent_level
* 2, ' ');
86 DepMap::const_iterator dep_begin
= dep_map
.lower_bound(target
);
87 DepMap::const_iterator dep_end
= dep_map
.upper_bound(target
);
88 for (DepMap::const_iterator cur_dep
= dep_begin
;
89 cur_dep
!= dep_end
; cur_dep
++) {
90 const Target
* cur_target
= cur_dep
->second
;
92 // Only print the toolchain for non-default-toolchain targets.
93 OutputString(indent
+ cur_target
->label().GetUserVisibleName(
94 !cur_target
->settings()->is_default()));
96 bool print_children
= true;
98 if (seen_targets
->find(cur_target
) == seen_targets
->end()) {
99 // New target, mark it visited.
100 seen_targets
->insert(cur_target
);
103 print_children
= false;
104 // Only print "..." if something is actually elided, which means that
105 // the current target has children.
106 if (dep_map
.lower_bound(cur_target
) != dep_map
.upper_bound(cur_target
))
113 RecursivePrintTree(dep_map
, cur_target
, seen_targets
, indent_level
+ 1);
117 void RecursiveCollectChildRefs(const DepMap
& dep_map
,
118 const Target
* target
,
121 // Recursively finds all targets that reference the given one, and additionally
122 // adds the current one to the list.
123 void RecursiveCollectRefs(const DepMap
& dep_map
,
124 const Target
* target
,
125 TargetSet
* results
) {
126 if (results
->find(target
) != results
->end())
127 return; // Already found this target.
128 results
->insert(target
);
129 RecursiveCollectChildRefs(dep_map
, target
, results
);
132 // Recursively finds all targets that reference the given one.
133 void RecursiveCollectChildRefs(const DepMap
& dep_map
,
134 const Target
* target
,
135 TargetSet
* results
) {
136 DepMap::const_iterator dep_begin
= dep_map
.lower_bound(target
);
137 DepMap::const_iterator dep_end
= dep_map
.upper_bound(target
);
138 for (DepMap::const_iterator cur_dep
= dep_begin
;
139 cur_dep
!= dep_end
; cur_dep
++)
140 RecursiveCollectRefs(dep_map
, cur_dep
->second
, results
);
145 const char kRefs
[] = "refs";
146 const char kRefs_HelpShort
[] =
147 "refs: Find stuff referencing a target, directory, or config.";
148 const char kRefs_Help
[] =
149 "gn refs <build_dir> <label_pattern> [--files] [--tree] [--all]\n"
150 " [--all-toolchains]\n"
152 " Finds which targets reference a given target or targets (reverse\n"
155 " The <label_pattern> can take exact labels or patterns that match more\n"
156 " than one (although not general regular expressions).\n"
157 " See \"gn help label_pattern\" for details.\n"
160 " When used without --tree, will recurse and display all unique\n"
161 " dependencies of the given targets. When used with --tree, turns\n"
162 " off eliding to show a complete tree.\n"
164 " --all-toolchains\n"
165 " Make the label pattern matche all toolchains. If the label pattern\n"
166 " does not specify an explicit toolchain, labels from all toolchains\n"
167 " will be matched (normally only the default toolchain is matched\n"
168 " when no toolchain is specified).\n"
171 " Output unique filenames referencing a matched target or config.\n"
172 " These will be relative to the source root directory such that they\n"
173 " are suitable for piping to other commands.\n"
176 " Outputs a reverse dependency tree from the given target. The label\n"
177 " pattern must match one target exactly. Duplicates will be elided.\n"
178 " Combine with --all to see a full dependency tree.\n"
182 " gn refs out/Debug //tools/gn:gn\n"
183 " Find all targets depending on the given exact target name.\n"
185 " gn refs out/Debug //base:i18n --files | xargs gvim\n"
186 " Edit all files containing references to //base:i18n\n"
188 " gn refs out/Debug //base --all\n"
189 " List all targets depending directly or indirectly on //base:base.\n"
191 " gn refs out/Debug \"//base/*\"\n"
192 " List all targets depending directly on any target in //base or\n"
193 " its subdirectories.\n"
195 " gn refs out/Debug \"//base:*\"\n"
196 " List all targets depending directly on any target in\n"
197 " //base/BUILD.gn.\n"
199 " gn refs out/Debug //base --tree\n"
200 " Print a reverse dependency tree of //base:base\n";
202 int RunRefs(const std::vector
<std::string
>& args
) {
203 if (args
.size() != 2) {
204 Err(Location(), "You're holding it wrong.",
205 "Usage: \"gn refs <build_dir> <label_pattern>\"").PrintToStdout();
209 const CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
210 bool tree
= cmdline
->HasSwitch("tree");
211 bool all
= cmdline
->HasSwitch("all");
212 bool all_toolchains
= cmdline
->HasSwitch("all-toolchains");
213 bool files
= cmdline
->HasSwitch("files");
215 Setup
* setup
= new Setup
;
216 setup
->set_check_for_bad_items(false);
217 if (!setup
->DoSetup(args
[0], false) || !setup
->Run())
220 // Figure out the target or targets that the user is querying.
221 std::vector
<const Target
*> query
;
222 if (!ResolveTargetsFromCommandLinePattern(setup
, args
[1], all_toolchains
,
226 OutputString("\"" + args
[1] + "\" matches no targets.\n");
230 // Construct the reverse dependency tree.
232 FillDepMap(setup
, &dep_map
);
235 // Output dependency tree.
237 Err(NULL
, "--files option can't be used with --tree option.")
241 if (query
.size() != 1) {
242 Err(NULL
, "Query matches more than one target.",
243 "--tree only supports a single target as input.").PrintToStdout();
247 // Recursively print all targets.
248 RecursivePrintTree(dep_map
, query
[0], NULL
, 0);
250 // Recursively print unique targets.
251 TargetSet seen_targets
;
252 RecursivePrintTree(dep_map
, query
[0], &seen_targets
, 0);
255 // Output recursive dependencies, uniquified and flattened.
257 for (const auto& cur_query
: query
)
258 RecursiveCollectChildRefs(dep_map
, cur_query
, &results
);
259 OutputResultSet(results
, files
);
261 // Output direct references of everything in the query.
263 for (const auto& cur_query
: query
) {
264 DepMap::const_iterator dep_begin
= dep_map
.lower_bound(cur_query
);
265 DepMap::const_iterator dep_end
= dep_map
.upper_bound(cur_query
);
266 for (DepMap::const_iterator cur_dep
= dep_begin
;
267 cur_dep
!= dep_end
; cur_dep
++)
268 results
.insert(cur_dep
->second
);
270 OutputResultSet(results
, files
);
276 } // namespace commands