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 <algorithm>
6#include <set>
7#include <sstream>
8
9#include "base/command_line.h"
10#include "tools/gn/commands.h"
11#include "tools/gn/config.h"
12#include "tools/gn/config_values_extractors.h"
13#include "tools/gn/item.h"
14#include "tools/gn/item_node.h"
15#include "tools/gn/label.h"
16#include "tools/gn/setup.h"
17#include "tools/gn/standard_out.h"
18#include "tools/gn/target.h"
19
20namespace commands {
21
22namespace {
23
24struct CompareTargetLabel {
25  bool operator()(const Target* a, const Target* b) const {
26    return a->label() < b->label();
27  }
28};
29
30void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
31  if (result->find(target->label()) != result->end())
32    return;  // Already did this target.
33  result->insert(target->label());
34
35  const std::vector<const Target*>& deps = target->deps();
36  for (size_t i = 0; i < deps.size(); i++)
37    RecursiveCollectDeps(deps[i], result);
38
39  const std::vector<const Target*>& datadeps = target->datadeps();
40  for (size_t i = 0; i < datadeps.size(); i++)
41    RecursiveCollectDeps(datadeps[i], result);
42}
43
44// Prints dependencies of the given target (not the target itself).
45void RecursivePrintDeps(const Target* target,
46                        const Label& default_toolchain,
47                        int indent_level) {
48  std::vector<const Target*> sorted_deps = target->deps();
49  const std::vector<const Target*> datadeps = target->datadeps();
50  for (size_t i = 0; i < datadeps.size(); i++)
51    sorted_deps.push_back(datadeps[i]);
52  std::sort(sorted_deps.begin(), sorted_deps.end(), CompareTargetLabel());
53
54  std::string indent(indent_level * 2, ' ');
55  for (size_t i = 0; i < sorted_deps.size(); i++) {
56    OutputString(indent +
57        sorted_deps[i]->label().GetUserVisibleName(default_toolchain) + "\n");
58    RecursivePrintDeps(sorted_deps[i], default_toolchain, indent_level + 1);
59  }
60}
61
62void PrintDeps(const Target* target, bool display_header) {
63  const CommandLine* cmdline = CommandLine::ForCurrentProcess();
64  Label toolchain_label = target->label().GetToolchainLabel();
65
66  // Tree mode is separate.
67  if (cmdline->HasSwitch("tree")) {
68    if (display_header)
69      OutputString("\nDependency tree:\n");
70    RecursivePrintDeps(target, toolchain_label, 1);
71    return;
72  }
73
74  // Collect the deps to display.
75  std::vector<Label> deps;
76  if (cmdline->HasSwitch("all")) {
77    if (display_header)
78      OutputString("\nAll recursive dependencies:\n");
79
80    std::set<Label> all_deps;
81    RecursiveCollectDeps(target, &all_deps);
82    for (std::set<Label>::iterator i = all_deps.begin();
83         i != all_deps.end(); ++i)
84      deps.push_back(*i);
85  } else {
86    if (display_header) {
87      OutputString("\nDirect dependencies "
88                   "(try also \"--all\" and \"--tree\"):\n");
89    }
90
91    const std::vector<const Target*>& target_deps = target->deps();
92    for (size_t i = 0; i < target_deps.size(); i++)
93      deps.push_back(target_deps[i]->label());
94
95    const std::vector<const Target*>& target_datadeps = target->datadeps();
96    for (size_t i = 0; i < target_datadeps.size(); i++)
97      deps.push_back(target_datadeps[i]->label());
98  }
99
100  std::sort(deps.begin(), deps.end());
101  for (size_t i = 0; i < deps.size(); i++)
102    OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
103}
104
105void PrintConfigs(const Target* target, bool display_header) {
106  // Configs (don't sort since the order determines how things are processed).
107  if (display_header)
108    OutputString("\nConfigs (in order applying):\n");
109
110  Label toolchain_label = target->label().GetToolchainLabel();
111  const std::vector<const Config*>& configs = target->configs();
112  for (size_t i = 0; i < configs.size(); i++) {
113    OutputString("  " +
114        configs[i]->label().GetUserVisibleName(toolchain_label) + "\n");
115  }
116}
117
118void PrintSources(const Target* target, bool display_header) {
119  if (display_header)
120    OutputString("\nSources:\n");
121
122  Target::FileList sources = target->sources();
123  std::sort(sources.begin(), sources.end());
124  for (size_t i = 0; i < sources.size(); i++)
125    OutputString("  " + sources[i].value() + "\n");
126}
127
128// Attempts to attribute the gen dependency of the given target to some source
129// code and outputs the string to the output stream.
130//
131// The attribution of the source of the dependencies is stored in the ItemNode
132// which is the parallel structure to the target dependency map, so we have
133// to jump through a few loops to find everything.
134void OutputSourceOfDep(const Target* target,
135                       const Label& dep_label,
136                       std::ostream& out) {
137  ItemTree& item_tree = target->settings()->build_settings()->item_tree();
138  base::AutoLock lock(item_tree.lock());
139
140  ItemNode* target_node = item_tree.GetExistingNodeLocked(target->label());
141  CHECK(target_node);
142  ItemNode* dep_node = item_tree.GetExistingNodeLocked(dep_label);
143  CHECK(dep_node);
144
145  const ItemNode::ItemNodeMap& direct_deps = target_node->direct_dependencies();
146  ItemNode::ItemNodeMap::const_iterator found = direct_deps.find(dep_node);
147  if (found == direct_deps.end())
148    return;
149
150  const Location& location = found->second.begin();
151  out << "       (Added by " + location.file()->name().value() << ":"
152      << location.line_number() << ")\n";
153}
154
155// Templatized writer for writing out different config value types.
156template<typename T> struct DescValueWriter {};
157template<> struct DescValueWriter<std::string> {
158  void operator()(const std::string& str, std::ostream& out) const {
159    out << "    " << str << "\n";
160  }
161};
162template<> struct DescValueWriter<SourceFile> {
163  void operator()(const SourceFile& file, std::ostream& out) const {
164    out << "    " << file.value() << "\n";
165  }
166};
167template<> struct DescValueWriter<SourceDir> {
168  void operator()(const SourceDir& dir, std::ostream& out) const {
169    out << "    " << dir.value() << "\n";
170  }
171};
172
173// Writes a given config value type to the string, optionally with attribution.
174// This should match RecursiveTargetConfigToStream in the order it traverses.
175template<typename T> void OutputRecursiveTargetConfig(
176    const Target* target,
177    const char* header_name,
178    const std::vector<T>& (ConfigValues::* getter)() const) {
179  bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
180
181  DescValueWriter<T> writer;
182  std::ostringstream out;
183
184  // First write the values from the config itself.
185  if (!(target->config_values().*getter)().empty()) {
186    if (display_blame)
187      out << "  From " << target->label().GetUserVisibleName(false) << "\n";
188    ConfigValuesToStream(target->config_values(), getter, writer, out);
189  }
190
191  // TODO(brettw) annotate where forced config includes came from!
192
193  // Then write the configs in order.
194  for (size_t i = 0; i < target->configs().size(); i++) {
195    const Config* config = target->configs()[i];
196    const ConfigValues& values = config->config_values();
197
198    if (!(values.*getter)().empty()) {
199      if (display_blame) {
200        out << "  From " << config->label().GetUserVisibleName(false) << "\n";
201        OutputSourceOfDep(target, config->label(), out);
202      }
203      ConfigValuesToStream(values, getter, writer, out);
204    }
205  }
206
207  std::string out_str = out.str();
208  if (!out_str.empty()) {
209    OutputString(std::string(header_name) + "\n");
210    OutputString(out_str);
211  }
212}
213
214}  // namespace
215
216// desc ------------------------------------------------------------------------
217
218const char kDesc[] = "desc";
219const char kDesc_HelpShort[] =
220    "desc: Show lots of insightful information about a target.";
221const char kDesc_Help[] =
222    "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
223    "  Displays information about a given labeled target.\n"
224    "\n"
225    "Possibilities for <what to show>:\n"
226    "  (If unspecified an overall summary will be displayed.)\n"
227    "\n"
228    "  sources\n"
229    "      Source files.\n"
230    "\n"
231    "  configs\n"
232    "      Shows configs applied to the given target, sorted in the order\n"
233    "      they're specified. This includes both configs specified in the\n"
234    "      \"configs\" variable, as well as configs pushed onto this target\n"
235    "      via dependencies specifying \"all\" or \"direct\" dependent\n"
236    "      configs.\n"
237    "\n"
238    "  deps [--all | --tree]\n"
239    "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
240    "      recursive) dependencies of the given target. \"--tree\" shows them\n"
241    "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
242    "      Both \"deps\" and \"datadeps\" will be included.\n"
243    "\n"
244    "  defines    [--blame]\n"
245    "  includes   [--blame]\n"
246    "  cflags     [--blame]\n"
247    "  cflags_cc  [--blame]\n"
248    "  cflags_cxx [--blame]\n"
249    "  ldflags    [--blame]\n"
250    "      Shows the given values taken from the target and all configs\n"
251    "      applying. See \"--blame\" below.\n"
252    "\n"
253    "  --blame\n"
254    "      Used with any value specified by a config, this will name\n"
255    "      the config that specified the value.\n"
256    "\n"
257    "Note:\n"
258    "  This command will show the full name of directories and source files,\n"
259    "  but when directories and source paths are written to the build file,\n"
260    "  they will be adjusted to be relative to the build directory. So the\n"
261    "  values for paths displayed by this command won't match (but should\n"
262    "  mean the same thing.\n"
263    "\n"
264    "Examples:\n"
265    "  gn desc //base:base\n"
266    "      Summarizes the given target.\n"
267    "\n"
268    "  gn desc :base_unittests deps --tree\n"
269    "      Shows a dependency tree of the \"base_unittests\" project in\n"
270    "      the current directory.\n"
271    "\n"
272    "  gn desc //base defines --blame\n"
273    "      Shows defines set for the //base:base target, annotated by where\n"
274    "      each one was set from.\n";
275
276int RunDesc(const std::vector<std::string>& args) {
277  if (args.size() != 1 && args.size() != 2) {
278    Err(Location(), "You're holding it wrong.",
279        "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
280    return 1;
281  }
282
283  const Target* target = GetTargetForDesc(args);
284  if (!target)
285    return 1;
286
287#define CONFIG_VALUE_HANDLER(name) \
288    } else if (what == #name) { \
289      OutputRecursiveTargetConfig(target, #name, &ConfigValues::name);
290
291  if (args.size() == 2) {
292    // User specified one thing to display.
293    const std::string& what = args[1];
294    if (what == "configs") {
295      PrintConfigs(target, false);
296    } else if (what == "sources") {
297      PrintSources(target, false);
298    } else if (what == "deps") {
299      PrintDeps(target, false);
300
301    CONFIG_VALUE_HANDLER(defines)
302    CONFIG_VALUE_HANDLER(includes)
303    CONFIG_VALUE_HANDLER(cflags)
304    CONFIG_VALUE_HANDLER(cflags_c)
305    CONFIG_VALUE_HANDLER(cflags_cc)
306    CONFIG_VALUE_HANDLER(ldflags)
307
308    } else {
309      OutputString("Don't know how to display \"" + what + "\".\n");
310      return 1;
311    }
312
313#undef CONFIG_VALUE_HANDLER
314    return 0;
315  }
316
317  // Display summary.
318
319  // Generally we only want to display toolchains on labels when the toolchain
320  // is different than the default one for this target (which we always print
321  // in the header).
322  Label target_toolchain = target->label().GetToolchainLabel();
323
324  // Header.
325  std::string title_target =
326      "Target: " + target->label().GetUserVisibleName(false);
327  std::string title_toolchain =
328      "Toolchain: " + target_toolchain.GetUserVisibleName(false);
329  OutputString(title_target + "\n", DECORATION_YELLOW);
330  OutputString(title_toolchain + "\n", DECORATION_YELLOW);
331  OutputString(std::string(
332      std::max(title_target.size(), title_toolchain.size()), '=') + "\n");
333
334  PrintSources(target, true);
335  PrintConfigs(target, true);
336  OutputString("\n  (Use \"gn desc <label> <thing you want to see>\" to show "
337               "the actual values\n   applied by the different configs. "
338               "See \"gn help desc\" for more.)\n");
339  PrintDeps(target, true);
340
341  return 0;
342}
343
344}  // namespace commands
345