• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/filesystem_utils.h"
14 #include "tools/gn/item.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 
20 namespace commands {
21 
22 namespace {
23 
24 // Prints the given directory in a nice way for the user to view.
FormatSourceDir(const SourceDir & dir)25 std::string FormatSourceDir(const SourceDir& dir) {
26 #if defined(OS_WIN)
27   // On Windows we fix up system absolute paths to look like native ones.
28   // Internally, they'll look like "/C:\foo\bar/"
29   if (dir.is_system_absolute()) {
30     std::string buf = dir.value();
31     if (buf.size() > 3 && buf[2] == ':') {
32       buf.erase(buf.begin());  // Erase beginning slash.
33       ConvertPathToSystem(&buf);  // Convert to backslashes.
34       return buf;
35     }
36   }
37 #endif
38   return dir.value();
39 }
40 
41 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result);
42 
RecursiveCollectDeps(const Target * target,std::set<Label> * result)43 void RecursiveCollectDeps(const Target* target, std::set<Label>* result) {
44   if (result->find(target->label()) != result->end())
45     return;  // Already did this target.
46   result->insert(target->label());
47 
48   RecursiveCollectChildDeps(target, result);
49 }
50 
RecursiveCollectChildDeps(const Target * target,std::set<Label> * result)51 void RecursiveCollectChildDeps(const Target* target, std::set<Label>* result) {
52   const LabelTargetVector& deps = target->deps();
53   for (size_t i = 0; i < deps.size(); i++)
54     RecursiveCollectDeps(deps[i].ptr, result);
55 
56   const LabelTargetVector& datadeps = target->datadeps();
57   for (size_t i = 0; i < datadeps.size(); i++)
58     RecursiveCollectDeps(datadeps[i].ptr, result);
59 }
60 
61 // Prints dependencies of the given target (not the target itself).
RecursivePrintDeps(const Target * target,const Label & default_toolchain,int indent_level)62 void RecursivePrintDeps(const Target* target,
63                         const Label& default_toolchain,
64                         int indent_level) {
65   LabelTargetVector sorted_deps = target->deps();
66   const LabelTargetVector& datadeps = target->datadeps();
67   sorted_deps.insert(sorted_deps.end(), datadeps.begin(), datadeps.end());
68   std::sort(sorted_deps.begin(), sorted_deps.end(),
69             LabelPtrLabelLess<Target>());
70 
71   std::string indent(indent_level * 2, ' ');
72   for (size_t i = 0; i < sorted_deps.size(); i++) {
73     OutputString(indent +
74         sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
75     RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
76   }
77 }
78 
PrintDeps(const Target * target,bool display_header)79 void PrintDeps(const Target* target, bool display_header) {
80   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
81   Label toolchain_label = target->label().GetToolchainLabel();
82 
83   // Tree mode is separate.
84   if (cmdline->HasSwitch("tree")) {
85     if (display_header)
86       OutputString("\nDependency tree:\n");
87     RecursivePrintDeps(target, toolchain_label, 1);
88     return;
89   }
90 
91   // Collect the deps to display.
92   std::vector<Label> deps;
93   if (cmdline->HasSwitch("all")) {
94     if (display_header)
95       OutputString("\nAll recursive dependencies:\n");
96 
97     std::set<Label> all_deps;
98     RecursiveCollectChildDeps(target, &all_deps);
99     for (std::set<Label>::iterator i = all_deps.begin();
100          i != all_deps.end(); ++i)
101       deps.push_back(*i);
102   } else {
103     if (display_header) {
104       OutputString("\nDirect dependencies "
105                    "(try also \"--all\" and \"--tree\"):\n");
106     }
107 
108     const LabelTargetVector& target_deps = target->deps();
109     for (size_t i = 0; i < target_deps.size(); i++)
110       deps.push_back(target_deps[i].label);
111 
112     const LabelTargetVector& target_datadeps = target->datadeps();
113     for (size_t i = 0; i < target_datadeps.size(); i++)
114       deps.push_back(target_datadeps[i].label);
115   }
116 
117   std::sort(deps.begin(), deps.end());
118   for (size_t i = 0; i < deps.size(); i++)
119     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
120 }
121 
122 // libs and lib_dirs are special in that they're inherited. We don't currently
123 // implement a blame feature for this since the bottom-up inheritance makes
124 // this difficult.
PrintLibDirs(const Target * target,bool display_header)125 void PrintLibDirs(const Target* target, bool display_header) {
126   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
127   if (lib_dirs.empty())
128     return;
129 
130   if (display_header)
131     OutputString("\nlib_dirs\n");
132 
133   for (size_t i = 0; i < lib_dirs.size(); i++)
134     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
135 }
136 
PrintLibs(const Target * target,bool display_header)137 void PrintLibs(const Target* target, bool display_header) {
138   const OrderedSet<std::string>& libs = target->all_libs();
139   if (libs.empty())
140     return;
141 
142   if (display_header)
143     OutputString("\nlibs\n");
144 
145   for (size_t i = 0; i < libs.size(); i++)
146     OutputString("    " + libs[i] + "\n");
147 }
148 
PrintConfigs(const Target * target,bool display_header)149 void PrintConfigs(const Target* target, bool display_header) {
150   // Configs (don't sort since the order determines how things are processed).
151   if (display_header)
152     OutputString("\nConfigs (in order applying):\n");
153 
154   Label toolchain_label = target->label().GetToolchainLabel();
155   const LabelConfigVector& configs = target->configs();
156   for (size_t i = 0; i < configs.size(); i++) {
157     OutputString("  " +
158         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
159   }
160 }
161 
PrintSources(const Target * target,bool display_header)162 void PrintSources(const Target* target, bool display_header) {
163   if (display_header)
164     OutputString("\nSources:\n");
165 
166   Target::FileList sources = target->sources();
167   std::sort(sources.begin(), sources.end());
168   for (size_t i = 0; i < sources.size(); i++)
169     OutputString("  " + sources[i].value() + "\n");
170 }
171 
172 // Attribute the origin for attributing from where a target came from. Does
173 // nothing if the input is null or it does not have a location.
OutputSourceOfDep(const ParseNode * origin,std::ostream & out)174 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
175   if (!origin)
176     return;
177   Location location = origin->GetRange().begin();
178   out << "       (Added by " + location.file()->name().value() << ":"
179       << location.line_number() << ")\n";
180 }
181 
182 // Templatized writer for writing out different config value types.
183 template<typename T> struct DescValueWriter {};
184 template<> struct DescValueWriter<std::string> {
operator ()commands::__anonfbb7da8a0111::DescValueWriter185   void operator()(const std::string& str, std::ostream& out) const {
186     out << "    " << str << "\n";
187   }
188 };
189 template<> struct DescValueWriter<SourceFile> {
operator ()commands::__anonfbb7da8a0111::DescValueWriter190   void operator()(const SourceFile& file, std::ostream& out) const {
191     out << "    " << file.value() << "\n";
192   }
193 };
194 template<> struct DescValueWriter<SourceDir> {
operator ()commands::__anonfbb7da8a0111::DescValueWriter195   void operator()(const SourceDir& dir, std::ostream& out) const {
196     out << "    " << FormatSourceDir(dir) << "\n";
197   }
198 };
199 
200 // Writes a given config value type to the string, optionally with attribution.
201 // This should match RecursiveTargetConfigToStream in the order it traverses.
OutputRecursiveTargetConfig(const Target * target,const char * header_name,const std::vector<T> & (ConfigValues::* getter)()const)202 template<typename T> void OutputRecursiveTargetConfig(
203     const Target* target,
204     const char* header_name,
205     const std::vector<T>& (ConfigValues::* getter)() const) {
206   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
207 
208   DescValueWriter<T> writer;
209   std::ostringstream out;
210 
211   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
212     if ((iter.cur().*getter)().empty())
213       continue;
214 
215     // Optional blame sub-head.
216     if (display_blame) {
217       const Config* config = iter.GetCurrentConfig();
218       if (config) {
219         // Source of this value is a config.
220         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
221         OutputSourceOfDep(iter.origin(), out);
222       } else {
223         // Source of this value is the target itself.
224         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
225       }
226     }
227 
228     // Actual values.
229     ConfigValuesToStream(iter.cur(), getter, writer, out);
230   }
231 
232   std::string out_str = out.str();
233   if (!out_str.empty()) {
234     OutputString("\n" + std::string(header_name) + "\n");
235     OutputString(out_str);
236   }
237 }
238 
239 }  // namespace
240 
241 // desc ------------------------------------------------------------------------
242 
243 const char kDesc[] = "desc";
244 const char kDesc_HelpShort[] =
245     "desc: Show lots of insightful information about a target.";
246 const char kDesc_Help[] =
247     "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
248     "  Displays information about a given labeled target.\n"
249     "\n"
250     "Possibilities for <what to show>:\n"
251     "  (If unspecified an overall summary will be displayed.)\n"
252     "\n"
253     "  sources\n"
254     "      Source files.\n"
255     "\n"
256     "  configs\n"
257     "      Shows configs applied to the given target, sorted in the order\n"
258     "      they're specified. This includes both configs specified in the\n"
259     "      \"configs\" variable, as well as configs pushed onto this target\n"
260     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
261     "      configs.\n"
262     "\n"
263     "  deps [--all | --tree]\n"
264     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
265     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
266     "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
267     "      Both \"deps\" and \"datadeps\" will be included.\n"
268     "\n"
269     "  defines       [--blame]\n"
270     "  include_dirs  [--blame]\n"
271     "  cflags        [--blame]\n"
272     "  cflags_cc     [--blame]\n"
273     "  cflags_cxx    [--blame]\n"
274     "  ldflags       [--blame]\n"
275     "  lib_dirs\n"
276     "  libs\n"
277     "      Shows the given values taken from the target and all configs\n"
278     "      applying. See \"--blame\" below.\n"
279     "\n"
280     "  --blame\n"
281     "      Used with any value specified by a config, this will name\n"
282     "      the config that specified the value. This doesn't currently work\n"
283     "      for libs and lib_dirs because those are inherited and are more\n"
284     "      complicated to figure out the blame (patches welcome).\n"
285     "\n"
286     "Note:\n"
287     "  This command will show the full name of directories and source files,\n"
288     "  but when directories and source paths are written to the build file,\n"
289     "  they will be adjusted to be relative to the build directory. So the\n"
290     "  values for paths displayed by this command won't match (but should\n"
291     "  mean the same thing.\n"
292     "\n"
293     "Examples:\n"
294     "  gn desc //base:base\n"
295     "      Summarizes the given target.\n"
296     "\n"
297     "  gn desc :base_unittests deps --tree\n"
298     "      Shows a dependency tree of the \"base_unittests\" project in\n"
299     "      the current directory.\n"
300     "\n"
301     "  gn desc //base defines --blame\n"
302     "      Shows defines set for the //base:base target, annotated by where\n"
303     "      each one was set from.\n";
304 
305 #define OUTPUT_CONFIG_VALUE(name, type) \
306     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
307 
RunDesc(const std::vector<std::string> & args)308 int RunDesc(const std::vector<std::string>& args) {
309   if (args.size() != 1 && args.size() != 2) {
310     Err(Location(), "You're holding it wrong.",
311         "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
312     return 1;
313   }
314 
315   const Target* target = GetTargetForDesc(args);
316   if (!target)
317     return 1;
318 
319 #define CONFIG_VALUE_HANDLER(name, type) \
320     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
321 
322   if (args.size() == 2) {
323     // User specified one thing to display.
324     const std::string& what = args[1];
325     if (what == "configs") {
326       PrintConfigs(target, false);
327     } else if (what == "sources") {
328       PrintSources(target, false);
329     } else if (what == "deps") {
330       PrintDeps(target, false);
331     } else if (what == "lib_dirs") {
332       PrintLibDirs(target, false);
333     } else if (what == "libs") {
334       PrintLibs(target, false);
335 
336     CONFIG_VALUE_HANDLER(defines, std::string)
337     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
338     CONFIG_VALUE_HANDLER(cflags, std::string)
339     CONFIG_VALUE_HANDLER(cflags_c, std::string)
340     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
341     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
342     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
343     CONFIG_VALUE_HANDLER(ldflags, std::string)
344 
345     } else {
346       OutputString("Don't know how to display \"" + what + "\".\n");
347       return 1;
348     }
349 
350 #undef CONFIG_VALUE_HANDLER
351     return 0;
352   }
353 
354   // Display summary.
355 
356   // Generally we only want to display toolchains on labels when the toolchain
357   // is different than the default one for this target (which we always print
358   // in the header).
359   Label target_toolchain = target->label().GetToolchainLabel();
360 
361   // Header.
362   OutputString("Target: ", DECORATION_YELLOW);
363   OutputString(target->label().GetUserVisibleName(false) + "\n");
364   OutputString("Type: ", DECORATION_YELLOW);
365   OutputString(std::string(
366       Target::GetStringForOutputType(target->output_type())) + "\n");
367   OutputString("Toolchain: ", DECORATION_YELLOW);
368   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
369 
370   PrintSources(target, true);
371   PrintConfigs(target, true);
372 
373   OUTPUT_CONFIG_VALUE(defines, std::string)
374   OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
375   OUTPUT_CONFIG_VALUE(cflags, std::string)
376   OUTPUT_CONFIG_VALUE(cflags_c, std::string)
377   OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
378   OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
379   OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
380   OUTPUT_CONFIG_VALUE(ldflags, std::string)
381   PrintLibs(target, true);
382   PrintLibDirs(target, true);
383 
384   PrintDeps(target, true);
385 
386   return 0;
387 }
388 
389 }  // namespace commands
390