Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / gn / command_refs.cc
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 <map>
6 #include <set>
7
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"
17
18 namespace commands {
19
20 namespace {
21
22 typedef std::set<const Target*> TargetSet;
23 typedef std::vector<const Target*> TargetVector;
24
25 // Maps targets to the list of targets that depend on them.
26 typedef std::multimap<const Target*, const Target*> DepMap;
27
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));
33   }
34 }
35
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();
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,
78                               const Target* target,
79                               TargetSet* seen_targets,
80                               int indent_level);
81
82 // 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
84 // already, it will not be recused into. When the set is null, all refs will be
85 // printed.
86 void RecursivePrintTarget(const DepMap& dep_map,
87                           const Target* target,
88                           TargetSet* seen_targets,
89                           int indent_level) {
90   std::string indent(indent_level * 2, ' ');
91
92   // Only print the toolchain for non-default-toolchain targets.
93   OutputString(indent + target->label().GetUserVisibleName(
94       !target->settings()->is_default()));
95
96   bool print_children = true;
97   if (seen_targets) {
98     if (seen_targets->find(target) == seen_targets->end()) {
99       // New target, mark it visited.
100       seen_targets->insert(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(target) != dep_map.upper_bound(target))
107         OutputString("...");
108     }
109   }
110
111   OutputString("\n");
112   if (print_children)
113     RecursivePrintTargetDeps(dep_map, target, seen_targets, indent_level + 1);
114 }
115
116 // Prints refs of the given target (not the target itself). See
117 // RecursivePrintTarget.
118 void RecursivePrintTargetDeps(const DepMap& dep_map,
119                               const Target* target,
120                               TargetSet* seen_targets,
121                               int indent_level) {
122   DepMap::const_iterator dep_begin = dep_map.lower_bound(target);
123   DepMap::const_iterator dep_end = dep_map.upper_bound(target);
124   for (DepMap::const_iterator cur_dep = dep_begin;
125        cur_dep != dep_end; cur_dep++) {
126     RecursivePrintTarget(dep_map, cur_dep->second, seen_targets, indent_level);
127   }
128 }
129
130 void RecursiveCollectChildRefs(const DepMap& dep_map,
131                                const Target* target,
132                                TargetSet* results);
133
134 // Recursively finds all targets that reference the given one, and additionally
135 // adds the current one to the list.
136 void RecursiveCollectRefs(const DepMap& dep_map,
137                           const Target* target,
138                           TargetSet* results) {
139   if (results->find(target) != results->end())
140     return;  // Already found this target.
141   results->insert(target);
142   RecursiveCollectChildRefs(dep_map, target, results);
143 }
144
145 // Recursively finds all targets that reference the given one.
146 void RecursiveCollectChildRefs(const DepMap& dep_map,
147                                const Target* target,
148                                TargetSet* results) {
149   DepMap::const_iterator dep_begin = dep_map.lower_bound(target);
150   DepMap::const_iterator dep_end = dep_map.upper_bound(target);
151   for (DepMap::const_iterator cur_dep = dep_begin;
152        cur_dep != dep_end; cur_dep++)
153     RecursiveCollectRefs(dep_map, cur_dep->second, results);
154 }
155
156 bool TargetContainsFile(const Target* target, const SourceFile& file) {
157   for (const auto& cur_file : target->sources()) {
158     if (cur_file == file)
159       return true;
160   }
161   for (const auto& cur_file : target->public_headers()) {
162     if (cur_file == file)
163       return true;
164   }
165   for (const auto& cur_file : target->inputs()) {
166     if (cur_file == file)
167       return true;
168   }
169   for (const auto& cur_file : target->data()) {
170     if (cur_file == file)
171       return true;
172   }
173   return false;
174 }
175
176 void GetTargetsContainingFile(Setup* setup,
177                               const std::string& input,
178                               bool all_toolchains,
179                               std::vector<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();
186
187   std::vector<const Target*> all_targets =
188       setup->builder()->GetAllResolvedTargets();
189
190   for (const auto& target : all_targets) {
191     if (!all_toolchains) {
192       // Only check targets in the default toolchain.
193       if (target->label().GetToolchainLabel() != default_toolchain)
194         continue;
195     }
196     if (TargetContainsFile(target, file))
197       matches->push_back(target);
198   }
199 }
200
201 }  // namespace
202
203 const char kRefs[] = "refs";
204 const char kRefs_HelpShort[] =
205     "refs: Find stuff referencing a target or file.";
206 const char kRefs_Help[] =
207     "gn refs <build_dir> (<label_pattern>|<file>) [--files] [--tree] [--all]\n"
208     "        [--all-toolchains]\n"
209     "\n"
210     "  Finds reverse dependencies (which targets reference something). The\n"
211     "  input is either a target label, a target label pattern, or a file\n"
212     "  name.\n"
213     "\n"
214     "  The <label_pattern> can take exact labels or patterns that match more\n"
215     "  than one (although not general regular expressions).\n"
216     "  See \"gn help label_pattern\" for details.\n"
217     "\n"
218     "  If the input is a file name, the output will be the target(s)\n"
219     "  referencing that file (potentially recursively if used with --tree\n"
220     "  or --all). By default, only targets from the default toolchain that\n"
221     "  reference the file will be listed.\n"
222     "\n"
223     "  --all\n"
224     "      When used without --tree, will recurse and display all unique\n"
225     "      dependencies of the given targets. When used with --tree, turns\n"
226     "      off eliding to show a complete tree.\n"
227     "\n"
228     "  --all-toolchains\n"
229     "      For target patterns, make the label pattern match all toolchains.\n"
230     "      If the label pattern does not specify an explicit toolchain,\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"
234     "      For filename inputs, lists targets from all toolchains that\n"
235     "      include the file.\n"
236     "\n"
237     "  --files\n"
238     "      Output unique filenames referencing a matched target or config.\n"
239     "      These will be relative to the source root directory such that they\n"
240     "      are suitable for piping to other commands.\n"
241     "\n"
242     "  --tree\n"
243     "      Outputs a reverse dependency tree from the given target.\n"
244     "      Duplicates will be elided. Combine with --all to see a full\n"
245     "      dependency tree.\n"
246     "\n"
247     "Examples (target input)\n"
248     "\n"
249     "  gn refs out/Debug //tools/gn:gn\n"
250     "      Find all targets depending on the given exact target name.\n"
251     "\n"
252     "  gn refs out/Debug //base:i18n --files | xargs gvim\n"
253     "      Edit all files containing references to //base:i18n\n"
254     "\n"
255     "  gn refs out/Debug //base --all\n"
256     "      List all targets depending directly or indirectly on //base:base.\n"
257     "\n"
258     "  gn refs out/Debug \"//base/*\"\n"
259     "      List all targets depending directly on any target in //base or\n"
260     "      its subdirectories.\n"
261     "\n"
262     "  gn refs out/Debug \"//base:*\"\n"
263     "      List all targets depending directly on any target in\n"
264     "      //base/BUILD.gn.\n"
265     "\n"
266     "  gn refs out/Debug //base --tree\n"
267     "      Print a reverse dependency tree of //base:base\n"
268     "\n"
269     "Examples (file input)\n"
270     "\n"
271     "  gn refs out/Debug //base/macros.h\n"
272     "      Print targets listing //base/macros.h as a source.\n"
273     "\n"
274     "  gn refs out/Debug //base/macros.h --tree\n"
275     "      Display a reverse dependency tree to get to the given file. This\n"
276     "      will show how dependencies will reference that file.\n"
277     "\n"
278     "  gn refs out/Debug //base/macros.h --all\n"
279     "      Display all unique targets with some dependency path to a target\n"
280     "      containing the given file as a source.\n";
281
282 int RunRefs(const std::vector<std::string>& args) {
283   if (args.size() != 2) {
284     Err(Location(), "You're holding it wrong.",
285         "Usage: \"gn refs <build_dir> (<label_pattern>|<file>)\"")
286         .PrintToStdout();
287     return 1;
288   }
289
290   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
291   bool tree = cmdline->HasSwitch("tree");
292   bool all = cmdline->HasSwitch("all");
293   bool all_toolchains = cmdline->HasSwitch("all-toolchains");
294   bool files = cmdline->HasSwitch("files");
295
296   Setup* setup = new Setup;
297   setup->set_check_for_bad_items(false);
298   if (!setup->DoSetup(args[0], false) || !setup->Run())
299     return 1;
300
301   // Figure out the target or targets that the user is querying.
302   bool is_file_input = false;
303   std::vector<const Target*> query;
304   if (!ResolveTargetsFromCommandLinePattern(setup, args[1], all_toolchains,
305                                             &query))
306     return 1;
307   if (query.empty()) {
308     // If it doesn't match any targets, assume input is file.
309     GetTargetsContainingFile(setup, args[1], all_toolchains, &query);
310     if (query.empty()) {
311       OutputString("\"" + args[1] + "\" matches no targets.\n");
312       return 0;
313     }
314     is_file_input = true;
315   }
316
317   // Construct the reverse dependency tree.
318   DepMap dep_map;
319   FillDepMap(setup, &dep_map);
320
321   // When the input is a file, we want to print the targets in |query|, which
322   // are the things that directly reference the file, but when the input is a
323   // target, we skip that since the user is asking for what reference those.
324   if (tree) {
325     // Output dependency tree.
326     if (files) {
327       Err(NULL, "--files option can't be used with --tree option.")
328           .PrintToStdout();
329       return 1;
330     }
331     if (query.size() != 1) {
332       Err(NULL, "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, NULL, 0);
341         else
342           RecursivePrintTargetDeps(dep_map, cur_query, NULL, 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
384   return 0;
385 }
386
387 }  // namespace commands