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.
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"
24 // Prints the given directory in a nice way for the user to view.
25 std::string
FormatSourceDir(const SourceDir
& dir
) {
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.
40 void RecursiveCollectChildDeps(const Target
* target
, std::set
<Label
>* result
);
42 void RecursiveCollectDeps(const Target
* target
, std::set
<Label
>* result
) {
43 if (result
->find(target
->label()) != result
->end())
44 return; // Already did this target.
45 result
->insert(target
->label());
47 RecursiveCollectChildDeps(target
, result
);
50 void RecursiveCollectChildDeps(const Target
* target
, std::set
<Label
>* result
) {
51 const LabelTargetVector
& deps
= target
->deps();
52 for (size_t i
= 0; i
< deps
.size(); i
++)
53 RecursiveCollectDeps(deps
[i
].ptr
, result
);
55 const LabelTargetVector
& datadeps
= target
->datadeps();
56 for (size_t i
= 0; i
< datadeps
.size(); i
++)
57 RecursiveCollectDeps(datadeps
[i
].ptr
, result
);
60 // Prints dependencies of the given target (not the target itself).
61 void RecursivePrintDeps(const Target
* target
,
62 const Label
& default_toolchain
,
64 LabelTargetVector sorted_deps
= target
->deps();
65 const LabelTargetVector
& datadeps
= target
->datadeps();
66 sorted_deps
.insert(sorted_deps
.end(), datadeps
.begin(), datadeps
.end());
67 std::sort(sorted_deps
.begin(), sorted_deps
.end(),
68 LabelPtrLabelLess
<Target
>());
70 std::string
indent(indent_level
* 2, ' ');
71 for (size_t i
= 0; i
< sorted_deps
.size(); i
++) {
72 // Don't print groups. Groups are flattened such that the deps of the
73 // group are added directly to the target that depended on the group.
74 // Printing and recursing into groups here will cause such targets to be
77 // It would be much more intuitive to do the opposite and not display the
78 // deps that were copied from the group to the target and instead display
79 // the group, but the source of those dependencies is not tracked.
80 if (sorted_deps
[i
].ptr
->output_type() == Target::GROUP
)
84 sorted_deps
[i
].label
.GetUserVisibleName(default_toolchain
) + "\n");
85 RecursivePrintDeps(sorted_deps
[i
].ptr
, default_toolchain
, indent_level
+ 1);
89 void PrintDeps(const Target
* target
, bool display_header
) {
90 const CommandLine
* cmdline
= CommandLine::ForCurrentProcess();
91 Label toolchain_label
= target
->label().GetToolchainLabel();
93 // Tree mode is separate.
94 if (cmdline
->HasSwitch("tree")) {
96 OutputString("\nDependency tree:\n");
97 RecursivePrintDeps(target
, toolchain_label
, 1);
101 // Collect the deps to display.
102 std::vector
<Label
> deps
;
103 if (cmdline
->HasSwitch("all")) {
105 OutputString("\nAll recursive dependencies:\n");
107 std::set
<Label
> all_deps
;
108 RecursiveCollectChildDeps(target
, &all_deps
);
109 for (std::set
<Label
>::iterator i
= all_deps
.begin();
110 i
!= all_deps
.end(); ++i
)
113 if (display_header
) {
114 OutputString("\nDirect dependencies "
115 "(try also \"--all\" and \"--tree\"):\n");
118 const LabelTargetVector
& target_deps
= target
->deps();
119 for (size_t i
= 0; i
< target_deps
.size(); i
++)
120 deps
.push_back(target_deps
[i
].label
);
122 const LabelTargetVector
& target_datadeps
= target
->datadeps();
123 for (size_t i
= 0; i
< target_datadeps
.size(); i
++)
124 deps
.push_back(target_datadeps
[i
].label
);
127 std::sort(deps
.begin(), deps
.end());
128 for (size_t i
= 0; i
< deps
.size(); i
++)
129 OutputString(" " + deps
[i
].GetUserVisibleName(toolchain_label
) + "\n");
132 // libs and lib_dirs are special in that they're inherited. We don't currently
133 // implement a blame feature for this since the bottom-up inheritance makes
135 void PrintLibDirs(const Target
* target
, bool display_header
) {
136 const OrderedSet
<SourceDir
>& lib_dirs
= target
->all_lib_dirs();
137 if (lib_dirs
.empty())
141 OutputString("\nlib_dirs\n");
143 for (size_t i
= 0; i
< lib_dirs
.size(); i
++)
144 OutputString(" " + FormatSourceDir(lib_dirs
[i
]) + "\n");
147 void PrintLibs(const Target
* target
, bool display_header
) {
148 const OrderedSet
<std::string
>& libs
= target
->all_libs();
153 OutputString("\nlibs\n");
155 for (size_t i
= 0; i
< libs
.size(); i
++)
156 OutputString(" " + libs
[i
] + "\n");
159 void PrintPublic(const Target
* target
, bool display_header
) {
161 OutputString("\npublic\n");
163 if (target
->all_headers_public()) {
164 OutputString(" [All headers listed in the sources are public.]\n");
168 Target::FileList public_headers
= target
->public_headers();
169 std::sort(public_headers
.begin(), public_headers
.end());
170 for (size_t i
= 0; i
< public_headers
.size(); i
++)
171 OutputString(" " + public_headers
[i
].value() + "\n");
174 void PrintVisibility(const Target
* target
, bool display_header
) {
176 OutputString("\nvisibility\n");
178 OutputString(target
->visibility().Describe(2, false));
181 void PrintConfigs(const Target
* target
, bool display_header
) {
182 // Configs (don't sort since the order determines how things are processed).
184 OutputString("\nConfigs (in order applying):\n");
186 Label toolchain_label
= target
->label().GetToolchainLabel();
187 const LabelConfigVector
& configs
= target
->configs();
188 for (size_t i
= 0; i
< configs
.size(); i
++) {
190 configs
[i
].label
.GetUserVisibleName(toolchain_label
) + "\n");
194 void PrintSources(const Target
* target
, bool display_header
) {
196 OutputString("\nSources:\n");
198 Target::FileList sources
= target
->sources();
199 std::sort(sources
.begin(), sources
.end());
200 for (size_t i
= 0; i
< sources
.size(); i
++)
201 OutputString(" " + sources
[i
].value() + "\n");
204 // Attribute the origin for attributing from where a target came from. Does
205 // nothing if the input is null or it does not have a location.
206 void OutputSourceOfDep(const ParseNode
* origin
, std::ostream
& out
) {
209 Location location
= origin
->GetRange().begin();
210 out
<< " (Added by " + location
.file()->name().value() << ":"
211 << location
.line_number() << ")\n";
214 // Templatized writer for writing out different config value types.
215 template<typename T
> struct DescValueWriter
{};
216 template<> struct DescValueWriter
<std::string
> {
217 void operator()(const std::string
& str
, std::ostream
& out
) const {
218 out
<< " " << str
<< "\n";
221 template<> struct DescValueWriter
<SourceDir
> {
222 void operator()(const SourceDir
& dir
, std::ostream
& out
) const {
223 out
<< " " << FormatSourceDir(dir
) << "\n";
227 // Writes a given config value type to the string, optionally with attribution.
228 // This should match RecursiveTargetConfigToStream in the order it traverses.
229 template<typename T
> void OutputRecursiveTargetConfig(
230 const Target
* target
,
231 const char* header_name
,
232 const std::vector
<T
>& (ConfigValues::* getter
)() const) {
233 bool display_blame
= CommandLine::ForCurrentProcess()->HasSwitch("blame");
235 DescValueWriter
<T
> writer
;
236 std::ostringstream out
;
238 for (ConfigValuesIterator
iter(target
); !iter
.done(); iter
.Next()) {
239 if ((iter
.cur().*getter
)().empty())
242 // Optional blame sub-head.
244 const Config
* config
= iter
.GetCurrentConfig();
246 // Source of this value is a config.
247 out
<< " From " << config
->label().GetUserVisibleName(false) << "\n";
248 OutputSourceOfDep(iter
.origin(), out
);
250 // Source of this value is the target itself.
251 out
<< " From " << target
->label().GetUserVisibleName(false) << "\n";
256 ConfigValuesToStream(iter
.cur(), getter
, writer
, out
);
259 std::string out_str
= out
.str();
260 if (!out_str
.empty()) {
261 OutputString("\n" + std::string(header_name
) + "\n");
262 OutputString(out_str
);
268 // desc ------------------------------------------------------------------------
270 const char kDesc
[] = "desc";
271 const char kDesc_HelpShort
[] =
272 "desc: Show lots of insightful information about a target.";
273 const char kDesc_Help
[] =
274 "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
275 " Displays information about a given labeled target.\n"
277 "Possibilities for <what to show>:\n"
278 " (If unspecified an overall summary will be displayed.)\n"
284 " Public header files.\n"
287 " Prints which targets can depend on this one.\n"
290 " Shows configs applied to the given target, sorted in the order\n"
291 " they're specified. This includes both configs specified in the\n"
292 " \"configs\" variable, as well as configs pushed onto this target\n"
293 " via dependencies specifying \"all\" or \"direct\" dependent\n"
296 " deps [--all | --tree]\n"
297 " Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
298 " recursive) dependencies of the given target. \"--tree\" shows them\n"
299 " in a tree format. Otherwise, they will be sorted alphabetically.\n"
300 " Both \"deps\" and \"datadeps\" will be included.\n"
302 " defines [--blame]\n"
303 " include_dirs [--blame]\n"
304 " cflags [--blame]\n"
305 " cflags_cc [--blame]\n"
306 " cflags_cxx [--blame]\n"
307 " ldflags [--blame]\n"
310 " Shows the given values taken from the target and all configs\n"
311 " applying. See \"--blame\" below.\n"
314 " Used with any value specified by a config, this will name\n"
315 " the config that specified the value. This doesn't currently work\n"
316 " for libs and lib_dirs because those are inherited and are more\n"
317 " complicated to figure out the blame (patches welcome).\n"
320 " This command will show the full name of directories and source files,\n"
321 " but when directories and source paths are written to the build file,\n"
322 " they will be adjusted to be relative to the build directory. So the\n"
323 " values for paths displayed by this command won't match (but should\n"
324 " mean the same thing).\n"
327 " gn desc //base:base\n"
328 " Summarizes the given target.\n"
330 " gn desc :base_unittests deps --tree\n"
331 " Shows a dependency tree of the \"base_unittests\" project in\n"
332 " the current directory.\n"
334 " gn desc //base defines --blame\n"
335 " Shows defines set for the //base:base target, annotated by where\n"
336 " each one was set from.\n";
338 #define OUTPUT_CONFIG_VALUE(name, type) \
339 OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
341 int RunDesc(const std::vector
<std::string
>& args
) {
342 if (args
.size() != 1 && args
.size() != 2) {
343 Err(Location(), "You're holding it wrong.",
344 "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
348 const Target
* target
= GetTargetForDesc(args
);
352 #define CONFIG_VALUE_HANDLER(name, type) \
353 } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
355 if (args
.size() == 2) {
356 // User specified one thing to display.
357 const std::string
& what
= args
[1];
358 if (what
== "configs") {
359 PrintConfigs(target
, false);
360 } else if (what
== "sources") {
361 PrintSources(target
, false);
362 } else if (what
== "public") {
363 PrintPublic(target
, false);
364 } else if (what
== "visibility") {
365 PrintVisibility(target
, false);
366 } else if (what
== "deps") {
367 PrintDeps(target
, false);
368 } else if (what
== "lib_dirs") {
369 PrintLibDirs(target
, false);
370 } else if (what
== "libs") {
371 PrintLibs(target
, false);
373 CONFIG_VALUE_HANDLER(defines
, std::string
)
374 CONFIG_VALUE_HANDLER(include_dirs
, SourceDir
)
375 CONFIG_VALUE_HANDLER(cflags
, std::string
)
376 CONFIG_VALUE_HANDLER(cflags_c
, std::string
)
377 CONFIG_VALUE_HANDLER(cflags_cc
, std::string
)
378 CONFIG_VALUE_HANDLER(cflags_objc
, std::string
)
379 CONFIG_VALUE_HANDLER(cflags_objcc
, std::string
)
380 CONFIG_VALUE_HANDLER(ldflags
, std::string
)
383 OutputString("Don't know how to display \"" + what
+ "\".\n");
387 #undef CONFIG_VALUE_HANDLER
393 // Generally we only want to display toolchains on labels when the toolchain
394 // is different than the default one for this target (which we always print
396 Label target_toolchain
= target
->label().GetToolchainLabel();
399 OutputString("Target: ", DECORATION_YELLOW
);
400 OutputString(target
->label().GetUserVisibleName(false) + "\n");
401 OutputString("Type: ", DECORATION_YELLOW
);
402 OutputString(std::string(
403 Target::GetStringForOutputType(target
->output_type())) + "\n");
404 OutputString("Toolchain: ", DECORATION_YELLOW
);
405 OutputString(target_toolchain
.GetUserVisibleName(false) + "\n");
407 PrintSources(target
, true);
408 PrintPublic(target
, true);
409 PrintVisibility(target
, true);
410 PrintConfigs(target
, true);
412 OUTPUT_CONFIG_VALUE(defines
, std::string
)
413 OUTPUT_CONFIG_VALUE(include_dirs
, SourceDir
)
414 OUTPUT_CONFIG_VALUE(cflags
, std::string
)
415 OUTPUT_CONFIG_VALUE(cflags_c
, std::string
)
416 OUTPUT_CONFIG_VALUE(cflags_cc
, std::string
)
417 OUTPUT_CONFIG_VALUE(cflags_objc
, std::string
)
418 OUTPUT_CONFIG_VALUE(cflags_objcc
, std::string
)
419 OUTPUT_CONFIG_VALUE(ldflags
, std::string
)
420 PrintLibs(target
, true);
421 PrintLibDirs(target
, true);
423 PrintDeps(target
, true);
428 } // namespace commands