Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: tools/gn/command_refs.cc

Issue 937003002: Enhance GN introspection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/gn/command_ls.cc ('k') | tools/gn/commands.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <map> 5 #include <map>
6 #include <set> 6 #include <set>
7 7
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "tools/gn/commands.h" 9 #include "tools/gn/commands.h"
10 #include "tools/gn/deps_iterator.h" 10 #include "tools/gn/deps_iterator.h"
(...skipping 15 matching lines...) Expand all
26 typedef std::multimap<const Target*, const Target*> DepMap; 26 typedef std::multimap<const Target*, const Target*> DepMap;
27 27
28 // Populates the reverse dependency map for the targets in the Setup. 28 // Populates the reverse dependency map for the targets in the Setup.
29 void FillDepMap(Setup* setup, DepMap* dep_map) { 29 void FillDepMap(Setup* setup, DepMap* dep_map) {
30 for (const auto& target : setup->builder()->GetAllResolvedTargets()) { 30 for (const auto& target : setup->builder()->GetAllResolvedTargets()) {
31 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL)) 31 for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL))
32 dep_map->insert(std::make_pair(dep_pair.ptr, target)); 32 dep_map->insert(std::make_pair(dep_pair.ptr, target));
33 } 33 }
34 } 34 }
35 35
36 // Returns the file path generating this item. 36 // Forward declaration for function below.
37 base::FilePath FilePathForItem(const Item* item) {
38 return item->defined_from()->GetRange().begin().file()->physical_name();
39 }
40
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;
47
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)));
53
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());
62
63 // Grab the label of the default toolchain from a random target.
64 Label default_tc_label =
65 (*results.begin())->settings()->default_toolchain_label();
66
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");
72 }
73 }
74 }
75
76 // Forward declatation for function below.
77 void RecursivePrintTargetDeps(const DepMap& dep_map, 37 void RecursivePrintTargetDeps(const DepMap& dep_map,
78 const Target* target, 38 const Target* target,
79 TargetSet* seen_targets, 39 TargetSet* seen_targets,
80 int indent_level); 40 int indent_level);
81 41
82 // Prints the target and its dependencies in tree form. If the set is non-null, 42 // Prints the target and its dependencies in tree form. If the set is non-null,
83 // new targets encountered will be added to the set, and if a ref is in the set 43 // new targets encountered will be added to the set, and if a ref is in the set
84 // already, it will not be recused into. When the set is null, all refs will be 44 // already, it will not be recused into. When the set is null, all refs will be
85 // printed. 45 // printed.
86 void RecursivePrintTarget(const DepMap& dep_map, 46 void RecursivePrintTarget(const DepMap& dep_map,
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 return true; 127 return true;
168 } 128 }
169 for (const auto& cur_file : target->data()) { 129 for (const auto& cur_file : target->data()) {
170 if (cur_file == file) 130 if (cur_file == file)
171 return true; 131 return true;
172 } 132 }
173 return false; 133 return false;
174 } 134 }
175 135
176 void GetTargetsContainingFile(Setup* setup, 136 void GetTargetsContainingFile(Setup* setup,
177 const std::string& input, 137 const std::vector<const Target*>& all_targets,
138 const SourceFile& file,
178 bool all_toolchains, 139 bool all_toolchains,
179 std::vector<const Target*>* matches) { 140 UniqueVector<const Target*>* matches) {
180 SourceDir cur_dir =
181 SourceDirForCurrentDirectory(setup->build_settings().root_path());
182 SourceFile file = cur_dir.ResolveRelativeFile(
183 input, setup->build_settings().root_path_utf8());
184
185 Label default_toolchain = setup->loader()->default_toolchain_label(); 141 Label default_toolchain = setup->loader()->default_toolchain_label();
186
187 std::vector<const Target*> all_targets =
188 setup->builder()->GetAllResolvedTargets();
189
190 for (const auto& target : all_targets) { 142 for (const auto& target : all_targets) {
191 if (!all_toolchains) { 143 if (!all_toolchains) {
192 // Only check targets in the default toolchain. 144 // Only check targets in the default toolchain.
193 if (target->label().GetToolchainLabel() != default_toolchain) 145 if (target->label().GetToolchainLabel() != default_toolchain)
194 continue; 146 continue;
195 } 147 }
196 if (TargetContainsFile(target, file)) 148 if (TargetContainsFile(target, file))
197 matches->push_back(target); 149 matches->push_back(target);
198 } 150 }
199 } 151 }
200 152
153 bool TargetReferencesConfig(const Target* target, const Config* config) {
154 for (const LabelConfigPair& cur : target->configs()) {
155 if (cur.ptr == config)
156 return true;
157 }
158 for (const LabelConfigPair& cur : target->public_configs()) {
159 if (cur.ptr == config)
160 return true;
161 }
162 return false;
163 }
164
165 void GetTargetsReferencingConfig(Setup* setup,
166 const std::vector<const Target*>& all_targets,
167 const Config* config,
168 bool all_toolchains,
169 UniqueVector<const Target*>* matches) {
170 Label default_toolchain = setup->loader()->default_toolchain_label();
171 for (const auto& target : all_targets) {
172 if (!all_toolchains) {
173 // Only check targets in the default toolchain.
174 if (target->label().GetToolchainLabel() != default_toolchain)
175 continue;
176 }
177 if (TargetReferencesConfig(target, config))
178 matches->push_back(target);
179 }
180 }
181
182 void DoTreeOutput(const DepMap& dep_map,
183 const UniqueVector<const Target*>& implicit_target_matches,
184 const UniqueVector<const Target*>& explicit_target_matches,
185 bool all) {
186 TargetSet seen_targets;
187
188 // Implicit targets don't get printed themselves.
189 for (const Target* target : implicit_target_matches) {
190 if (all)
191 RecursivePrintTargetDeps(dep_map, target, nullptr, 0);
192 else
193 RecursivePrintTargetDeps(dep_map, target, &seen_targets, 0);
194 }
195
196 // Explicit targets appear in the output.
197 for (const Target* target : implicit_target_matches) {
198 if (all)
199 RecursivePrintTarget(dep_map, target, nullptr, 0);
200 else
201 RecursivePrintTarget(dep_map, target, &seen_targets, 0);
202 }
203 }
204
205 void DoAllListOutput(
206 const DepMap& dep_map,
207 const UniqueVector<const Target*>& implicit_target_matches,
208 const UniqueVector<const Target*>& explicit_target_matches) {
209 // Output recursive dependencies, uniquified and flattened.
210 TargetSet results;
211
212 for (const Target* target : implicit_target_matches)
213 RecursiveCollectChildRefs(dep_map, target, &results);
214 for (const Target* target : explicit_target_matches) {
215 // Explicit targets also get added to the output themselves.
216 results.insert(target);
217 RecursiveCollectChildRefs(dep_map, target, &results);
218 }
219
220 FilterAndPrintTargetSet(false, results);
221 }
222
223 void DoDirectListOutput(
224 const DepMap& dep_map,
225 const UniqueVector<const Target*>& implicit_target_matches,
226 const UniqueVector<const Target*>& explicit_target_matches) {
227 TargetSet results;
228
229 // Output everything that refers to the implicit ones.
230 for (const Target* target : implicit_target_matches) {
231 DepMap::const_iterator dep_begin = dep_map.lower_bound(target);
232 DepMap::const_iterator dep_end = dep_map.upper_bound(target);
233 for (DepMap::const_iterator cur_dep = dep_begin;
234 cur_dep != dep_end; cur_dep++)
235 results.insert(cur_dep->second);
236 }
237
238 // And just output the explicit ones directly (these are the target matches
239 // when referring to what references a file or config).
240 for (const Target* target : explicit_target_matches)
241 results.insert(target);
242
243 FilterAndPrintTargetSet(false, results);
244 }
245
201 } // namespace 246 } // namespace
202 247
203 const char kRefs[] = "refs"; 248 const char kRefs[] = "refs";
204 const char kRefs_HelpShort[] = 249 const char kRefs_HelpShort[] =
205 "refs: Find stuff referencing a target or file."; 250 "refs: Find stuff referencing a target or file.";
206 const char kRefs_Help[] = 251 const char kRefs_Help[] =
207 "gn refs <out_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n" 252 "gn refs <out_dir> (<label_pattern>|<label>|<file>)* [--all]\n"
208 " [--all-toolchains]\n" 253 " [--all-toolchains] [--as=...] [--testonly=...] [--type=...]\n"
209 "\n" 254 "\n"
210 " Finds reverse dependencies (which targets reference something). The\n" 255 " Finds reverse dependencies (which targets reference something). The\n"
211 " input is either a target label, a target label pattern, or a file\n" 256 " input is a list containing:\n"
212 " name.\n"
213 "\n" 257 "\n"
214 " The <label_pattern> can take exact labels or patterns that match more\n" 258 " - Target label: The result will be which targets depend on it.\n"
215 " than one (although not general regular expressions).\n"
216 " See \"gn help label_pattern\" for details.\n"
217 "\n" 259 "\n"
218 " If the input is a file name, the output will be the target(s)\n" 260 " - Config label: The result will be which targets list the given\n"
219 " referencing that file (potentially recursively if used with --tree\n" 261 " config in its \"configs\" or \"public_configs\" list.\n"
220 " or --all). By default, only targets from the default toolchain that\n" 262 "\n"
221 " reference the file will be listed.\n" 263 " - Label pattern: The result will be which targets depend on any\n"
264 " target matching the given pattern. Patterns will not match\n"
265 " configs. These are not general regular expressions, see\n"
266 " \"gn help label_pattern\" for details.\n"
267 "\n"
268 " - File name: The result will be which targets list the given file in\n"
269 " its \"inputs\", \"sources\", \"public\", or \"data\". Any input\n"
270 " that does not contain wildcards and does not match a target or a\n"
271 " config will be treated as a file.\n"
272 "\n"
273 "Options\n"
222 "\n" 274 "\n"
223 " --all\n" 275 " --all\n"
224 " When used without --tree, will recurse and display all unique\n" 276 " When used without --tree, will recurse and display all unique\n"
225 " dependencies of the given targets. When used with --tree, turns\n" 277 " dependencies of the given targets. For example, if the input is\n"
226 " off eliding to show a complete tree.\n" 278 " a target, this will output all targets that depend directly or\n"
279 " indirectly on the input. If the input is a file, this will output\n"
280 " all targets that depend directly or indirectly on that file.\n"
281 "\n"
282 " When used with --tree, turns off eliding to show a complete tree.\n"
227 "\n" 283 "\n"
228 " --all-toolchains\n" 284 " --all-toolchains\n"
229 " For target patterns, make the label pattern match all toolchains.\n" 285 " Normally only inputs in the default toolchain will be included.\n"
230 " If the label pattern does not specify an explicit toolchain,\n" 286 " This switch will turn on matching all toolchains.\n"
231 " labels from all toolchains will be matched (normally only the\n"
232 " default toolchain is matched when no toolchain is specified).\n"
233 "\n" 287 "\n"
234 " For filename inputs, lists targets from all toolchains that\n" 288 " For example, a file is in a target might be compiled twice:\n"
235 " include the file.\n" 289 " once in the default toolchain and once in a secondary one. Without\n"
290 " this flag, only the default toolchain one will be matched and\n"
291 " printed (potentially with its recursive dependencies, depending on\n"
292 " the other options). With this flag, both will be printed\n"
293 " (potentially with both of their recursive dependencies).\n"
236 "\n" 294 "\n"
237 " --files\n" 295 TARGET_PRINTING_MODE_COMMAND_LINE_HELP
238 " Output unique filenames referencing a matched target or config.\n" 296 "\n"
239 " These will be relative to the source root directory such that they\n" 297 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP
240 " are suitable for piping to other commands.\n"
241 "\n" 298 "\n"
242 " --tree\n" 299 " --tree\n"
243 " Outputs a reverse dependency tree from the given target.\n" 300 " Outputs a reverse dependency tree from the given target.\n"
244 " Duplicates will be elided. Combine with --all to see a full\n" 301 " Duplicates will be elided. Combine with --all to see a full\n"
245 " dependency tree.\n" 302 " dependency tree.\n"
246 "\n" 303 "\n"
304 " Tree output can not be used with the filtering or output flags:\n"
305 " --as, --type, --testonly.\n"
306 "\n"
307 TARGET_TYPE_FILTER_COMMAND_LINE_HELP
308 "\n"
247 "Examples (target input)\n" 309 "Examples (target input)\n"
248 "\n" 310 "\n"
249 " gn refs out/Debug //tools/gn:gn\n" 311 " gn refs out/Debug //tools/gn:gn\n"
250 " Find all targets depending on the given exact target name.\n" 312 " Find all targets depending on the given exact target name.\n"
251 "\n" 313 "\n"
252 " gn refs out/Debug //base:i18n --files | xargs gvim\n" 314 " gn refs out/Debug //base:i18n --as=buildfiles | xargs gvim\n"
253 " Edit all files containing references to //base:i18n\n" 315 " Edit all .gn files containing references to //base:i18n\n"
254 "\n" 316 "\n"
255 " gn refs out/Debug //base --all\n" 317 " gn refs out/Debug //base --all\n"
256 " List all targets depending directly or indirectly on //base:base.\n" 318 " List all targets depending directly or indirectly on //base:base.\n"
257 "\n" 319 "\n"
258 " gn refs out/Debug \"//base/*\"\n" 320 " gn refs out/Debug \"//base/*\"\n"
259 " List all targets depending directly on any target in //base or\n" 321 " List all targets depending directly on any target in //base or\n"
260 " its subdirectories.\n" 322 " its subdirectories.\n"
261 "\n" 323 "\n"
262 " gn refs out/Debug \"//base:*\"\n" 324 " gn refs out/Debug \"//base:*\"\n"
263 " List all targets depending directly on any target in\n" 325 " List all targets depending directly on any target in\n"
264 " //base/BUILD.gn.\n" 326 " //base/BUILD.gn.\n"
265 "\n" 327 "\n"
266 " gn refs out/Debug //base --tree\n" 328 " gn refs out/Debug //base --tree\n"
267 " Print a reverse dependency tree of //base:base\n" 329 " Print a reverse dependency tree of //base:base\n"
268 "\n" 330 "\n"
269 "Examples (file input)\n" 331 "Examples (file input)\n"
270 "\n" 332 "\n"
271 " gn refs out/Debug //base/macros.h\n" 333 " gn refs out/Debug //base/macros.h\n"
272 " Print targets listing //base/macros.h as a source.\n" 334 " Print target(s) listing //base/macros.h as a source.\n"
273 "\n" 335 "\n"
274 " gn refs out/Debug //base/macros.h --tree\n" 336 " gn refs out/Debug //base/macros.h --tree\n"
275 " Display a reverse dependency tree to get to the given file. This\n" 337 " Display a reverse dependency tree to get to the given file. This\n"
276 " will show how dependencies will reference that file.\n" 338 " will show how dependencies will reference that file.\n"
277 "\n" 339 "\n"
278 " gn refs out/Debug //base/macros.h --all\n" 340 " gn refs out/Debug //base/macros.h //base/basictypes.h --all\n"
279 " Display all unique targets with some dependency path to a target\n" 341 " Display all unique targets with some dependency path to a target\n"
280 " containing the given file as a source.\n"; 342 " containing either of the given files as a source.\n"
343 "\n"
344 " gn refs out/Debug //base/macros.h --testonly=true --type=executable\n"
345 " --all --as=output\n"
346 " Display the executable file names of all test executables\n"
347 " potentially affected by a change to the given file.\n";
281 348
282 int RunRefs(const std::vector<std::string>& args) { 349 int RunRefs(const std::vector<std::string>& args) {
283 if (args.size() != 2) { 350 if (args.size() != 2) {
284 Err(Location(), "You're holding it wrong.", 351 Err(Location(), "You're holding it wrong.",
285 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"") 352 "Usage: \"gn refs <out_dir> (<label_pattern>|<file>)\"")
286 .PrintToStdout(); 353 .PrintToStdout();
287 return 1; 354 return 1;
288 } 355 }
289 356
290 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); 357 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
291 bool tree = cmdline->HasSwitch("tree"); 358 bool tree = cmdline->HasSwitch("tree");
292 bool all = cmdline->HasSwitch("all"); 359 bool all = cmdline->HasSwitch("all");
293 bool all_toolchains = cmdline->HasSwitch("all-toolchains"); 360 bool all_toolchains = cmdline->HasSwitch("all-toolchains");
294 bool files = cmdline->HasSwitch("files");
295 361
296 Setup* setup = new Setup; 362 Setup* setup = new Setup;
297 setup->set_check_for_bad_items(false); 363 setup->set_check_for_bad_items(false);
298 if (!setup->DoSetup(args[0], false) || !setup->Run()) 364 if (!setup->DoSetup(args[0], false) || !setup->Run())
299 return 1; 365 return 1;
300 366
301 // Figure out the target or targets that the user is querying. 367 // The inputs are everything but the first arg (which is the build dir).
302 bool is_file_input = false; 368 std::vector<std::string> inputs(args.begin() + 1, args.end());
303 std::vector<const Target*> query; 369
304 if (!ResolveTargetsFromCommandLinePattern(setup, args[1], all_toolchains, 370 // Get the matches for the command-line input.
305 &query)) 371 UniqueVector<const Target*> target_matches;
372 UniqueVector<const Config*> config_matches;
373 UniqueVector<const Toolchain*> toolchain_matches;
374 UniqueVector<SourceFile> file_matches;
375 if (!ResolveFromCommandLineInput(setup, inputs, all_toolchains,
376 &target_matches, &config_matches,
377 &toolchain_matches, &file_matches))
306 return 1; 378 return 1;
307 if (query.empty()) { 379
308 // If it doesn't match any targets, assume input is file. 380 // When you give a file or config as an input, you want the targets that are
309 GetTargetsContainingFile(setup, args[1], all_toolchains, &query); 381 // associated with it. We don't want to just append this to the
310 if (query.empty()) { 382 // target_matches, however, since these targets should actually be listed in
311 OutputString("\"" + args[1] + "\" matches no targets.\n"); 383 // the output, while for normal targets you don't want to see the inputs,
312 return 0; 384 // only what refers to them.
313 } 385 std::vector<const Target*> all_targets =
314 is_file_input = true; 386 setup->builder()->GetAllResolvedTargets();
387 UniqueVector<const Target*> explicit_target_matches;
388 for (const auto& file : file_matches) {
389 GetTargetsContainingFile(setup, all_targets, file, all_toolchains,
390 &explicit_target_matches);
391 }
392 for (const auto& config : config_matches) {
393 GetTargetsReferencingConfig(setup, all_targets, config, all_toolchains,
394 &explicit_target_matches);
315 } 395 }
316 396
317 // Construct the reverse dependency tree. 397 // Construct the reverse dependency tree.
318 DepMap dep_map; 398 DepMap dep_map;
319 FillDepMap(setup, &dep_map); 399 FillDepMap(setup, &dep_map);
320 400
321 // When the input is a file, we want to print the targets in |query|, which 401 if (tree)
322 // are the things that directly reference the file, but when the input is a 402 DoTreeOutput(dep_map, target_matches, explicit_target_matches, all);
323 // target, we skip that since the user is asking for what reference those. 403 else if (all)
324 if (tree) { 404 DoAllListOutput(dep_map, target_matches, explicit_target_matches);
325 // Output dependency tree. 405 else
326 if (files) { 406 DoDirectListOutput(dep_map, target_matches, explicit_target_matches);
327 Err(nullptr, "--files option can't be used with --tree option.")
328 .PrintToStdout();
329 return 1;
330 }
331 if (query.size() != 1) {
332 Err(nullptr, "Query matches more than one target.",
333 "--tree only supports a single target as input.").PrintToStdout();
334 return 1;
335 }
336 if (all) {
337 // Recursively print all targets.
338 for (const auto& cur_query : query) {
339 if (is_file_input)
340 RecursivePrintTarget(dep_map, cur_query, nullptr, 0);
341 else
342 RecursivePrintTargetDeps(dep_map, cur_query, nullptr, 0);
343 }
344 } else {
345 // Recursively print unique targets.
346 TargetSet seen_targets;
347 for (const auto& cur_query : query) {
348 if (is_file_input)
349 RecursivePrintTarget(dep_map, cur_query, &seen_targets, 0);
350 else
351 RecursivePrintTargetDeps(dep_map, cur_query, &seen_targets, 0);
352 }
353 }
354 } else if (all) {
355 // Output recursive dependencies, uniquified and flattened.
356 TargetSet results;
357 for (const auto& cur_query : query) {
358 // File inputs also include the top level targets we found.
359 if (is_file_input)
360 results.insert(cur_query);
361 RecursiveCollectChildRefs(dep_map, cur_query, &results);
362 }
363 OutputResultSet(results, files);
364 } else {
365 TargetSet results;
366 for (const auto& cur_query : query) {
367 if (is_file_input) {
368 // When querying for a file, output the resolved list of targets only
369 // (don't need to track back any target dependencies).
370 results.insert(cur_query);
371 } else {
372 // When querying for a target, output direct references of everything
373 // in the query.
374 DepMap::const_iterator dep_begin = dep_map.lower_bound(cur_query);
375 DepMap::const_iterator dep_end = dep_map.upper_bound(cur_query);
376 for (DepMap::const_iterator cur_dep = dep_begin;
377 cur_dep != dep_end; cur_dep++)
378 results.insert(cur_dep->second);
379 }
380 }
381 OutputResultSet(results, files);
382 }
383 407
384 return 0; 408 return 0;
385 } 409 }
386 410
387 } // namespace commands 411 } // namespace commands
OLDNEW
« no previous file with comments | « tools/gn/command_ls.cc ('k') | tools/gn/commands.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698