cc: Remove noisy UpdateTiles traces.
[chromium-blink-merge.git] / tools / gn / command_refs.cc
blob86fed874a64846adce3953a6f55ca88d6651335c
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.
5 #include <map>
6 #include <set>
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"
18 namespace commands {
20 namespace {
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
43 // be used.
44 void OutputResultSet(const TargetSet& results, bool as_files) {
45 if (results.empty())
46 return;
48 if (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");
56 } else {
57 // Output sorted and uniquified list of labels. The set will sort the
58 // labels.
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));
71 OutputString("\n");
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,
81 const Target* target,
82 TargetSet* seen_targets,
83 int indent_level) {
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;
97 if (seen_targets) {
98 if (seen_targets->find(cur_target) == seen_targets->end()) {
99 // New target, mark it visited.
100 seen_targets->insert(cur_target);
101 } else {
102 // Already seen.
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))
107 OutputString("...");
111 OutputString("\n");
112 if (print_children)
113 RecursivePrintTree(dep_map, cur_target, seen_targets, indent_level + 1);
117 void RecursiveCollectChildRefs(const DepMap& dep_map,
118 const Target* target,
119 TargetSet* results);
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);
143 } // namespace
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"
151 "\n"
152 " Finds which targets reference a given target or targets (reverse\n"
153 " dependencies).\n"
154 "\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"
158 "\n"
159 " --all\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"
163 "\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"
169 "\n"
170 " --files\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"
174 "\n"
175 " --tree\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"
179 "\n"
180 "Examples\n"
181 "\n"
182 " gn refs out/Debug //tools/gn:gn\n"
183 " Find all targets depending on the given exact target name.\n"
184 "\n"
185 " gn refs out/Debug //base:i18n --files | xargs gvim\n"
186 " Edit all files containing references to //base:i18n\n"
187 "\n"
188 " gn refs out/Debug //base --all\n"
189 " List all targets depending directly or indirectly on //base:base.\n"
190 "\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"
194 "\n"
195 " gn refs out/Debug \"//base:*\"\n"
196 " List all targets depending directly on any target in\n"
197 " //base/BUILD.gn.\n"
198 "\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();
206 return 1;
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())
218 return 1;
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,
223 &query))
224 return 1;
225 if (query.empty()) {
226 OutputString("\"" + args[1] + "\" matches no targets.\n");
227 return 0;
230 // Construct the reverse dependency tree.
231 DepMap dep_map;
232 FillDepMap(setup, &dep_map);
234 if (tree) {
235 // Output dependency tree.
236 if (files) {
237 Err(NULL, "--files option can't be used with --tree option.")
238 .PrintToStdout();
239 return 1;
241 if (query.size() != 1) {
242 Err(NULL, "Query matches more than one target.",
243 "--tree only supports a single target as input.").PrintToStdout();
244 return 1;
246 if (all) {
247 // Recursively print all targets.
248 RecursivePrintTree(dep_map, query[0], NULL, 0);
249 } else {
250 // Recursively print unique targets.
251 TargetSet seen_targets;
252 RecursivePrintTree(dep_map, query[0], &seen_targets, 0);
254 } else if (all) {
255 // Output recursive dependencies, uniquified and flattened.
256 TargetSet results;
257 for (const auto& cur_query : query)
258 RecursiveCollectChildRefs(dep_map, cur_query, &results);
259 OutputResultSet(results, files);
260 } else {
261 // Output direct references of everything in the query.
262 TargetSet results;
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);
273 return 0;
276 } // namespace commands