• 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/file_template.h"
14 #include "tools/gn/filesystem_utils.h"
15 #include "tools/gn/item.h"
16 #include "tools/gn/label.h"
17 #include "tools/gn/setup.h"
18 #include "tools/gn/standard_out.h"
19 #include "tools/gn/target.h"
20 
21 namespace commands {
22 
23 namespace {
24 
25 // Prints the given directory in a nice way for the user to view.
FormatSourceDir(const SourceDir & dir)26 std::string FormatSourceDir(const SourceDir& dir) {
27 #if defined(OS_WIN)
28   // On Windows we fix up system absolute paths to look like native ones.
29   // Internally, they'll look like "/C:\foo\bar/"
30   if (dir.is_system_absolute()) {
31     std::string buf = dir.value();
32     if (buf.size() > 3 && buf[2] == ':') {
33       buf.erase(buf.begin());  // Erase beginning slash.
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     // Don't print groups. Groups are flattened such that the deps of the
74     // group are added directly to the target that depended on the group.
75     // Printing and recursing into groups here will cause such targets to be
76     // duplicated.
77     //
78     // It would be much more intuitive to do the opposite and not display the
79     // deps that were copied from the group to the target and instead display
80     // the group, but the source of those dependencies is not tracked.
81     if (sorted_deps[i].ptr->output_type() == Target::GROUP)
82       continue;
83 
84     OutputString(indent +
85         sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
86     RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
87   }
88 }
89 
PrintDeps(const Target * target,bool display_header)90 void PrintDeps(const Target* target, bool display_header) {
91   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
92   Label toolchain_label = target->label().GetToolchainLabel();
93 
94   // Tree mode is separate.
95   if (cmdline->HasSwitch("tree")) {
96     if (display_header)
97       OutputString("\nDependency tree:\n");
98     RecursivePrintDeps(target, toolchain_label, 1);
99     return;
100   }
101 
102   // Collect the deps to display.
103   std::vector<Label> deps;
104   if (cmdline->HasSwitch("all")) {
105     if (display_header)
106       OutputString("\nAll recursive dependencies:\n");
107 
108     std::set<Label> all_deps;
109     RecursiveCollectChildDeps(target, &all_deps);
110     for (std::set<Label>::iterator i = all_deps.begin();
111          i != all_deps.end(); ++i)
112       deps.push_back(*i);
113   } else {
114     if (display_header) {
115       OutputString("\nDirect dependencies "
116                    "(try also \"--all\" and \"--tree\"):\n");
117     }
118 
119     const LabelTargetVector& target_deps = target->deps();
120     for (size_t i = 0; i < target_deps.size(); i++)
121       deps.push_back(target_deps[i].label);
122 
123     const LabelTargetVector& target_datadeps = target->datadeps();
124     for (size_t i = 0; i < target_datadeps.size(); i++)
125       deps.push_back(target_datadeps[i].label);
126   }
127 
128   std::sort(deps.begin(), deps.end());
129   for (size_t i = 0; i < deps.size(); i++)
130     OutputString("  " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
131 }
132 
PrintForwardDependentConfigsFrom(const Target * target,bool display_header)133 void PrintForwardDependentConfigsFrom(const Target* target,
134                                       bool display_header) {
135   if (target->forward_dependent_configs().empty())
136     return;
137 
138   if (display_header)
139     OutputString("\nforward_dependent_configs_from:\n");
140 
141   // Collect the sorted list of deps.
142   std::vector<Label> forward;
143   for (size_t i = 0; i < target->forward_dependent_configs().size(); i++)
144     forward.push_back(target->forward_dependent_configs()[i].label);
145   std::sort(forward.begin(), forward.end());
146 
147   Label toolchain_label = target->label().GetToolchainLabel();
148   for (size_t i = 0; i < forward.size(); i++)
149     OutputString("  " + forward[i].GetUserVisibleName(toolchain_label) + "\n");
150 }
151 
152 // libs and lib_dirs are special in that they're inherited. We don't currently
153 // implement a blame feature for this since the bottom-up inheritance makes
154 // this difficult.
PrintLibDirs(const Target * target,bool display_header)155 void PrintLibDirs(const Target* target, bool display_header) {
156   const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
157   if (lib_dirs.empty())
158     return;
159 
160   if (display_header)
161     OutputString("\nlib_dirs\n");
162 
163   for (size_t i = 0; i < lib_dirs.size(); i++)
164     OutputString("    " + FormatSourceDir(lib_dirs[i]) + "\n");
165 }
166 
PrintLibs(const Target * target,bool display_header)167 void PrintLibs(const Target* target, bool display_header) {
168   const OrderedSet<std::string>& libs = target->all_libs();
169   if (libs.empty())
170     return;
171 
172   if (display_header)
173     OutputString("\nlibs\n");
174 
175   for (size_t i = 0; i < libs.size(); i++)
176     OutputString("    " + libs[i] + "\n");
177 }
178 
PrintPublic(const Target * target,bool display_header)179 void PrintPublic(const Target* target, bool display_header) {
180   if (display_header)
181     OutputString("\npublic:\n");
182 
183   if (target->all_headers_public()) {
184     OutputString("  [All headers listed in the sources are public.]\n");
185     return;
186   }
187 
188   Target::FileList public_headers = target->public_headers();
189   std::sort(public_headers.begin(), public_headers.end());
190   for (size_t i = 0; i < public_headers.size(); i++)
191     OutputString("  " + public_headers[i].value() + "\n");
192 }
193 
PrintVisibility(const Target * target,bool display_header)194 void PrintVisibility(const Target* target, bool display_header) {
195   if (display_header)
196     OutputString("\nvisibility:\n");
197 
198   OutputString(target->visibility().Describe(2, false));
199 }
200 
PrintConfigsVector(const Target * target,const LabelConfigVector & configs,const std::string & heading,bool display_header)201 void PrintConfigsVector(const Target* target,
202                         const LabelConfigVector& configs,
203                         const std::string& heading,
204                         bool display_header) {
205   if (configs.empty())
206     return;
207 
208   // Don't sort since the order determines how things are processed.
209   if (display_header)
210     OutputString("\n" + heading + " (in order applying):\n");
211 
212   Label toolchain_label = target->label().GetToolchainLabel();
213   for (size_t i = 0; i < configs.size(); i++) {
214     OutputString("  " +
215         configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
216   }
217 }
218 
PrintConfigs(const Target * target,bool display_header)219 void PrintConfigs(const Target* target, bool display_header) {
220   PrintConfigsVector(target, target->configs(), "configs", display_header);
221 }
222 
PrintDirectDependentConfigs(const Target * target,bool display_header)223 void PrintDirectDependentConfigs(const Target* target, bool display_header) {
224   PrintConfigsVector(target, target->direct_dependent_configs(),
225                      "direct_dependent_configs", display_header);
226 }
227 
PrintAllDependentConfigs(const Target * target,bool display_header)228 void PrintAllDependentConfigs(const Target* target, bool display_header) {
229   PrintConfigsVector(target, target->all_dependent_configs(),
230                      "all_dependent_configs", display_header);
231 }
232 
PrintFileList(const Target::FileList & files,const std::string & header,bool indent_extra,bool display_header)233 void PrintFileList(const Target::FileList& files,
234                    const std::string& header,
235                    bool indent_extra,
236                    bool display_header) {
237   if (files.empty())
238     return;
239 
240   if (display_header)
241     OutputString("\n" + header + ":\n");
242 
243   std::string indent = indent_extra ? "    " : "  ";
244 
245   Target::FileList sorted = files;
246   std::sort(sorted.begin(), sorted.end());
247   for (size_t i = 0; i < sorted.size(); i++)
248     OutputString(indent + sorted[i].value() + "\n");
249 }
250 
PrintSources(const Target * target,bool display_header)251 void PrintSources(const Target* target, bool display_header) {
252   PrintFileList(target->sources(), "sources", false, display_header);
253 }
254 
PrintInputs(const Target * target,bool display_header)255 void PrintInputs(const Target* target, bool display_header) {
256   PrintFileList(target->inputs(), "inputs", false, display_header);
257 }
258 
PrintOutputs(const Target * target,bool display_header)259 void PrintOutputs(const Target* target, bool display_header) {
260   if (target->output_type() == Target::ACTION) {
261     // Just display the outputs directly.
262     PrintFileList(target->action_values().outputs(), "outputs", false,
263                   display_header);
264   } else if (target->output_type() == Target::ACTION_FOREACH) {
265     // Display both the output pattern and resolved list.
266     if (display_header)
267       OutputString("\noutputs:\n");
268 
269     // Display the pattern.
270     OutputString("  Output pattern:\n");
271     PrintFileList(target->action_values().outputs(), "", true, false);
272 
273     // Now display what that resolves to given the sources.
274     OutputString("\n  Resolved output file list:\n");
275 
276     std::vector<std::string> output_strings;
277     FileTemplate file_template = FileTemplate::GetForTargetOutputs(target);
278     for (size_t i = 0; i < target->sources().size(); i++)
279       file_template.Apply(target->sources()[i], &output_strings);
280 
281     std::sort(output_strings.begin(), output_strings.end());
282     for (size_t i = 0; i < output_strings.size(); i++) {
283       OutputString("    " + output_strings[i] + "\n");
284     }
285   }
286 }
287 
PrintScript(const Target * target,bool display_header)288 void PrintScript(const Target* target, bool display_header) {
289   if (display_header)
290     OutputString("\nscript:\n");
291   OutputString("  " + target->action_values().script().value() + "\n");
292 }
293 
PrintArgs(const Target * target,bool display_header)294 void PrintArgs(const Target* target, bool display_header) {
295   if (display_header)
296     OutputString("\nargs:\n");
297   for (size_t i = 0; i < target->action_values().args().size(); i++)
298     OutputString("  " + target->action_values().args()[i] + "\n");
299 }
300 
PrintDepfile(const Target * target,bool display_header)301 void PrintDepfile(const Target* target, bool display_header) {
302   if (target->action_values().depfile().value().empty())
303     return;
304   if (display_header)
305     OutputString("\ndepfile:\n");
306   OutputString("  " + target->action_values().depfile().value() + "\n");
307 }
308 
309 // Attribute the origin for attributing from where a target came from. Does
310 // nothing if the input is null or it does not have a location.
OutputSourceOfDep(const ParseNode * origin,std::ostream & out)311 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
312   if (!origin)
313     return;
314   Location location = origin->GetRange().begin();
315   out << "       (Added by " + location.file()->name().value() << ":"
316       << location.line_number() << ")\n";
317 }
318 
319 // Templatized writer for writing out different config value types.
320 template<typename T> struct DescValueWriter {};
321 template<> struct DescValueWriter<std::string> {
operator ()commands::__anon9f63c4840111::DescValueWriter322   void operator()(const std::string& str, std::ostream& out) const {
323     out << "    " << str << "\n";
324   }
325 };
326 template<> struct DescValueWriter<SourceDir> {
operator ()commands::__anon9f63c4840111::DescValueWriter327   void operator()(const SourceDir& dir, std::ostream& out) const {
328     out << "    " << FormatSourceDir(dir) << "\n";
329   }
330 };
331 
332 // Writes a given config value type to the string, optionally with attribution.
333 // This should match RecursiveTargetConfigToStream in the order it traverses.
OutputRecursiveTargetConfig(const Target * target,const char * header_name,const std::vector<T> & (ConfigValues::* getter)()const)334 template<typename T> void OutputRecursiveTargetConfig(
335     const Target* target,
336     const char* header_name,
337     const std::vector<T>& (ConfigValues::* getter)() const) {
338   bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
339 
340   DescValueWriter<T> writer;
341   std::ostringstream out;
342 
343   for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
344     if ((iter.cur().*getter)().empty())
345       continue;
346 
347     // Optional blame sub-head.
348     if (display_blame) {
349       const Config* config = iter.GetCurrentConfig();
350       if (config) {
351         // Source of this value is a config.
352         out << "  From " << config->label().GetUserVisibleName(false) << "\n";
353         OutputSourceOfDep(iter.origin(), out);
354       } else {
355         // Source of this value is the target itself.
356         out << "  From " << target->label().GetUserVisibleName(false) << "\n";
357       }
358     }
359 
360     // Actual values.
361     ConfigValuesToStream(iter.cur(), getter, writer, out);
362   }
363 
364   std::string out_str = out.str();
365   if (!out_str.empty()) {
366     OutputString("\n" + std::string(header_name) + "\n");
367     OutputString(out_str);
368   }
369 }
370 
371 }  // namespace
372 
373 // desc ------------------------------------------------------------------------
374 
375 const char kDesc[] = "desc";
376 const char kDesc_HelpShort[] =
377     "desc: Show lots of insightful information about a target.";
378 const char kDesc_Help[] =
379     "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
380     "  Displays information about a given labeled target.\n"
381     "\n"
382     "Possibilities for <what to show>:\n"
383     "  (If unspecified an overall summary will be displayed.)\n"
384     "\n"
385     "  sources\n"
386     "      Source files.\n"
387     "\n"
388     "  inputs\n"
389     "      Additional input dependencies.\n"
390     "\n"
391     "  public\n"
392     "      Public header files.\n"
393     "\n"
394     "  visibility\n"
395     "      Prints which targets can depend on this one.\n"
396     "\n"
397     "  configs\n"
398     "      Shows configs applied to the given target, sorted in the order\n"
399     "      they're specified. This includes both configs specified in the\n"
400     "      \"configs\" variable, as well as configs pushed onto this target\n"
401     "      via dependencies specifying \"all\" or \"direct\" dependent\n"
402     "      configs.\n"
403     "\n"
404     "  deps [--all | --tree]\n"
405     "      Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
406     "      recursive) dependencies of the given target. \"--tree\" shows them\n"
407     "      in a tree format.  Otherwise, they will be sorted alphabetically.\n"
408     "      Both \"deps\" and \"datadeps\" will be included.\n"
409     "\n"
410     "  direct_dependent_configs\n"
411     "  all_dependent_configs\n"
412     "      Shows the labels of configs applied to targets that depend on this\n"
413     "      one (either directly or all of them).\n"
414     "\n"
415     "  forward_dependent_configs_from\n"
416     "      Shows the labels of dependencies for which dependent configs will\n"
417     "      be pushed to targets depending on the current one.\n"
418     "\n"
419     "  script\n"
420     "  args\n"
421     "  depfile\n"
422     "      Actions only. The script and related values.\n"
423     "\n"
424     "  outputs\n"
425     "      Outputs for script and copy target types.\n"
426     "\n"
427     "  defines       [--blame]\n"
428     "  include_dirs  [--blame]\n"
429     "  cflags        [--blame]\n"
430     "  cflags_cc     [--blame]\n"
431     "  cflags_cxx    [--blame]\n"
432     "  ldflags       [--blame]\n"
433     "  lib_dirs\n"
434     "  libs\n"
435     "      Shows the given values taken from the target and all configs\n"
436     "      applying. See \"--blame\" below.\n"
437     "\n"
438     "  --blame\n"
439     "      Used with any value specified by a config, this will name\n"
440     "      the config that specified the value. This doesn't currently work\n"
441     "      for libs and lib_dirs because those are inherited and are more\n"
442     "      complicated to figure out the blame (patches welcome).\n"
443     "\n"
444     "Note:\n"
445     "  This command will show the full name of directories and source files,\n"
446     "  but when directories and source paths are written to the build file,\n"
447     "  they will be adjusted to be relative to the build directory. So the\n"
448     "  values for paths displayed by this command won't match (but should\n"
449     "  mean the same thing).\n"
450     "\n"
451     "Examples:\n"
452     "  gn desc //base:base\n"
453     "      Summarizes the given target.\n"
454     "\n"
455     "  gn desc :base_unittests deps --tree\n"
456     "      Shows a dependency tree of the \"base_unittests\" project in\n"
457     "      the current directory.\n"
458     "\n"
459     "  gn desc //base defines --blame\n"
460     "      Shows defines set for the //base:base target, annotated by where\n"
461     "      each one was set from.\n";
462 
463 #define OUTPUT_CONFIG_VALUE(name, type) \
464     OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
465 
RunDesc(const std::vector<std::string> & args)466 int RunDesc(const std::vector<std::string>& args) {
467   if (args.size() != 1 && args.size() != 2) {
468     Err(Location(), "You're holding it wrong.",
469         "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
470     return 1;
471   }
472 
473   const Target* target = GetTargetForDesc(args);
474   if (!target)
475     return 1;
476 
477 #define CONFIG_VALUE_HANDLER(name, type) \
478     } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
479 
480   if (args.size() == 2) {
481     // User specified one thing to display.
482     const std::string& what = args[1];
483     if (what == "configs") {
484       PrintConfigs(target, false);
485     } else if (what == "direct_dependent_configs") {
486       PrintDirectDependentConfigs(target, false);
487     } else if (what == "all_dependent_configs") {
488       PrintAllDependentConfigs(target, false);
489     } else if (what == "forward_dependent_configs_from") {
490       PrintForwardDependentConfigsFrom(target, false);
491     } else if (what == "sources") {
492       PrintSources(target, false);
493     } else if (what == "public") {
494       PrintPublic(target, false);
495     } else if (what == "visibility") {
496       PrintVisibility(target, false);
497     } else if (what == "inputs") {
498       PrintInputs(target, false);
499     } else if (what == "script") {
500       PrintScript(target, false);
501     } else if (what == "args") {
502       PrintArgs(target, false);
503     } else if (what == "depfile") {
504       PrintDepfile(target, false);
505     } else if (what == "outputs") {
506       PrintOutputs(target, false);
507     } else if (what == "deps") {
508       PrintDeps(target, false);
509     } else if (what == "lib_dirs") {
510       PrintLibDirs(target, false);
511     } else if (what == "libs") {
512       PrintLibs(target, false);
513 
514     CONFIG_VALUE_HANDLER(defines, std::string)
515     CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
516     CONFIG_VALUE_HANDLER(cflags, std::string)
517     CONFIG_VALUE_HANDLER(cflags_c, std::string)
518     CONFIG_VALUE_HANDLER(cflags_cc, std::string)
519     CONFIG_VALUE_HANDLER(cflags_objc, std::string)
520     CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
521     CONFIG_VALUE_HANDLER(ldflags, std::string)
522 
523     } else {
524       OutputString("Don't know how to display \"" + what + "\".\n");
525       return 1;
526     }
527 
528 #undef CONFIG_VALUE_HANDLER
529     return 0;
530   }
531 
532   // Display summary.
533 
534   // Display this only applicable to binary targets.
535   bool is_binary_output =
536     target->output_type() != Target::GROUP &&
537     target->output_type() != Target::COPY_FILES &&
538     target->output_type() != Target::ACTION &&
539     target->output_type() != Target::ACTION_FOREACH;
540 
541   // Generally we only want to display toolchains on labels when the toolchain
542   // is different than the default one for this target (which we always print
543   // in the header).
544   Label target_toolchain = target->label().GetToolchainLabel();
545 
546   // Header.
547   OutputString("Target: ", DECORATION_YELLOW);
548   OutputString(target->label().GetUserVisibleName(false) + "\n");
549   OutputString("Type: ", DECORATION_YELLOW);
550   OutputString(std::string(
551       Target::GetStringForOutputType(target->output_type())) + "\n");
552   OutputString("Toolchain: ", DECORATION_YELLOW);
553   OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
554 
555   PrintSources(target, true);
556   if (is_binary_output)
557     PrintPublic(target, true);
558   PrintVisibility(target, true);
559   if (is_binary_output)
560     PrintConfigs(target, true);
561 
562   PrintDirectDependentConfigs(target, true);
563   PrintAllDependentConfigs(target, true);
564   PrintForwardDependentConfigsFrom(target, true);
565 
566   PrintInputs(target, true);
567 
568   if (is_binary_output) {
569     OUTPUT_CONFIG_VALUE(defines, std::string)
570     OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
571     OUTPUT_CONFIG_VALUE(cflags, std::string)
572     OUTPUT_CONFIG_VALUE(cflags_c, std::string)
573     OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
574     OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
575     OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
576     OUTPUT_CONFIG_VALUE(ldflags, std::string)
577   }
578 
579   if (target->output_type() == Target::ACTION ||
580       target->output_type() == Target::ACTION_FOREACH) {
581     PrintScript(target, true);
582     PrintArgs(target, true);
583     PrintDepfile(target, true);
584   }
585 
586   if (target->output_type() == Target::ACTION ||
587       target->output_type() == Target::ACTION_FOREACH ||
588       target->output_type() == Target::COPY_FILES) {
589     PrintOutputs(target, true);
590   }
591 
592   // Libs can be part of any target and get recursively pushed up the chain,
593   // so always display them, even for groups and such.
594   PrintLibs(target, true);
595   PrintLibDirs(target, true);
596 
597   PrintDeps(target, true);
598 
599   return 0;
600 }
601 
602 }  // namespace commands
603