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++) {
73 sorted_deps[i].label.GetUserVisibleName(default_toolchain) + "\n");
74 RecursivePrintDeps(sorted_deps[i].ptr, default_toolchain, indent_level + 1);
78 void PrintDeps(const Target* target, bool display_header) {
79 const CommandLine* cmdline = CommandLine::ForCurrentProcess();
80 Label toolchain_label = target->label().GetToolchainLabel();
82 // Tree mode is separate.
83 if (cmdline->HasSwitch("tree")) {
85 OutputString("\nDependency tree:\n");
86 RecursivePrintDeps(target, toolchain_label, 1);
90 // Collect the deps to display.
91 std::vector<Label> deps;
92 if (cmdline->HasSwitch("all")) {
94 OutputString("\nAll recursive dependencies:\n");
96 std::set<Label> all_deps;
97 RecursiveCollectChildDeps(target, &all_deps);
98 for (std::set<Label>::iterator i = all_deps.begin();
99 i != all_deps.end(); ++i)
102 if (display_header) {
103 OutputString("\nDirect dependencies "
104 "(try also \"--all\" and \"--tree\"):\n");
107 const LabelTargetVector& target_deps = target->deps();
108 for (size_t i = 0; i < target_deps.size(); i++)
109 deps.push_back(target_deps[i].label);
111 const LabelTargetVector& target_datadeps = target->datadeps();
112 for (size_t i = 0; i < target_datadeps.size(); i++)
113 deps.push_back(target_datadeps[i].label);
116 std::sort(deps.begin(), deps.end());
117 for (size_t i = 0; i < deps.size(); i++)
118 OutputString(" " + deps[i].GetUserVisibleName(toolchain_label) + "\n");
121 // libs and lib_dirs are special in that they're inherited. We don't currently
122 // implement a blame feature for this since the bottom-up inheritance makes
124 void PrintLibDirs(const Target* target, bool display_header) {
125 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs();
126 if (lib_dirs.empty())
130 OutputString("\nlib_dirs\n");
132 for (size_t i = 0; i < lib_dirs.size(); i++)
133 OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n");
136 void PrintLibs(const Target* target, bool display_header) {
137 const OrderedSet<std::string>& libs = target->all_libs();
142 OutputString("\nlibs\n");
144 for (size_t i = 0; i < libs.size(); i++)
145 OutputString(" " + libs[i] + "\n");
148 void PrintConfigs(const Target* target, bool display_header) {
149 // Configs (don't sort since the order determines how things are processed).
151 OutputString("\nConfigs (in order applying):\n");
153 Label toolchain_label = target->label().GetToolchainLabel();
154 const LabelConfigVector& configs = target->configs();
155 for (size_t i = 0; i < configs.size(); i++) {
157 configs[i].label.GetUserVisibleName(toolchain_label) + "\n");
161 void PrintSources(const Target* target, bool display_header) {
163 OutputString("\nSources:\n");
165 Target::FileList sources = target->sources();
166 std::sort(sources.begin(), sources.end());
167 for (size_t i = 0; i < sources.size(); i++)
168 OutputString(" " + sources[i].value() + "\n");
171 // Attribute the origin for attributing from where a target came from. Does
172 // nothing if the input is null or it does not have a location.
173 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
176 Location location = origin->GetRange().begin();
177 out << " (Added by " + location.file()->name().value() << ":"
178 << location.line_number() << ")\n";
181 // Templatized writer for writing out different config value types.
182 template<typename T> struct DescValueWriter {};
183 template<> struct DescValueWriter<std::string> {
184 void operator()(const std::string& str, std::ostream& out) const {
185 out << " " << str << "\n";
188 template<> struct DescValueWriter<SourceDir> {
189 void operator()(const SourceDir& dir, std::ostream& out) const {
190 out << " " << FormatSourceDir(dir) << "\n";
194 // Writes a given config value type to the string, optionally with attribution.
195 // This should match RecursiveTargetConfigToStream in the order it traverses.
196 template<typename T> void OutputRecursiveTargetConfig(
197 const Target* target,
198 const char* header_name,
199 const std::vector<T>& (ConfigValues::* getter)() const) {
200 bool display_blame = CommandLine::ForCurrentProcess()->HasSwitch("blame");
202 DescValueWriter<T> writer;
203 std::ostringstream out;
205 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
206 if ((iter.cur().*getter)().empty())
209 // Optional blame sub-head.
211 const Config* config = iter.GetCurrentConfig();
213 // Source of this value is a config.
214 out << " From " << config->label().GetUserVisibleName(false) << "\n";
215 OutputSourceOfDep(iter.origin(), out);
217 // Source of this value is the target itself.
218 out << " From " << target->label().GetUserVisibleName(false) << "\n";
223 ConfigValuesToStream(iter.cur(), getter, writer, out);
226 std::string out_str = out.str();
227 if (!out_str.empty()) {
228 OutputString("\n" + std::string(header_name) + "\n");
229 OutputString(out_str);
235 // desc ------------------------------------------------------------------------
237 const char kDesc[] = "desc";
238 const char kDesc_HelpShort[] =
239 "desc: Show lots of insightful information about a target.";
240 const char kDesc_Help[] =
241 "gn desc <target label> [<what to show>] [--blame] [--all | --tree]\n"
242 " Displays information about a given labeled target.\n"
244 "Possibilities for <what to show>:\n"
245 " (If unspecified an overall summary will be displayed.)\n"
251 " Shows configs applied to the given target, sorted in the order\n"
252 " they're specified. This includes both configs specified in the\n"
253 " \"configs\" variable, as well as configs pushed onto this target\n"
254 " via dependencies specifying \"all\" or \"direct\" dependent\n"
257 " deps [--all | --tree]\n"
258 " Show immediate (or, when \"--all\" or \"--tree\" is specified,\n"
259 " recursive) dependencies of the given target. \"--tree\" shows them\n"
260 " in a tree format. Otherwise, they will be sorted alphabetically.\n"
261 " Both \"deps\" and \"datadeps\" will be included.\n"
263 " defines [--blame]\n"
264 " include_dirs [--blame]\n"
265 " cflags [--blame]\n"
266 " cflags_cc [--blame]\n"
267 " cflags_cxx [--blame]\n"
268 " ldflags [--blame]\n"
271 " Shows the given values taken from the target and all configs\n"
272 " applying. See \"--blame\" below.\n"
275 " Used with any value specified by a config, this will name\n"
276 " the config that specified the value. This doesn't currently work\n"
277 " for libs and lib_dirs because those are inherited and are more\n"
278 " complicated to figure out the blame (patches welcome).\n"
281 " This command will show the full name of directories and source files,\n"
282 " but when directories and source paths are written to the build file,\n"
283 " they will be adjusted to be relative to the build directory. So the\n"
284 " values for paths displayed by this command won't match (but should\n"
285 " mean the same thing).\n"
288 " gn desc //base:base\n"
289 " Summarizes the given target.\n"
291 " gn desc :base_unittests deps --tree\n"
292 " Shows a dependency tree of the \"base_unittests\" project in\n"
293 " the current directory.\n"
295 " gn desc //base defines --blame\n"
296 " Shows defines set for the //base:base target, annotated by where\n"
297 " each one was set from.\n";
299 #define OUTPUT_CONFIG_VALUE(name, type) \
300 OutputRecursiveTargetConfig<type>(target, #name, &ConfigValues::name);
302 int RunDesc(const std::vector<std::string>& args) {
303 if (args.size() != 1 && args.size() != 2) {
304 Err(Location(), "You're holding it wrong.",
305 "Usage: \"gn desc <target_name> <what to display>\"").PrintToStdout();
309 const Target* target = GetTargetForDesc(args);
313 #define CONFIG_VALUE_HANDLER(name, type) \
314 } else if (what == #name) { OUTPUT_CONFIG_VALUE(name, type)
316 if (args.size() == 2) {
317 // User specified one thing to display.
318 const std::string& what = args[1];
319 if (what == "configs") {
320 PrintConfigs(target, false);
321 } else if (what == "sources") {
322 PrintSources(target, false);
323 } else if (what == "deps") {
324 PrintDeps(target, false);
325 } else if (what == "lib_dirs") {
326 PrintLibDirs(target, false);
327 } else if (what == "libs") {
328 PrintLibs(target, false);
330 CONFIG_VALUE_HANDLER(defines, std::string)
331 CONFIG_VALUE_HANDLER(include_dirs, SourceDir)
332 CONFIG_VALUE_HANDLER(cflags, std::string)
333 CONFIG_VALUE_HANDLER(cflags_c, std::string)
334 CONFIG_VALUE_HANDLER(cflags_cc, std::string)
335 CONFIG_VALUE_HANDLER(cflags_objc, std::string)
336 CONFIG_VALUE_HANDLER(cflags_objcc, std::string)
337 CONFIG_VALUE_HANDLER(ldflags, std::string)
340 OutputString("Don't know how to display \"" + what + "\".\n");
344 #undef CONFIG_VALUE_HANDLER
350 // Generally we only want to display toolchains on labels when the toolchain
351 // is different than the default one for this target (which we always print
353 Label target_toolchain = target->label().GetToolchainLabel();
356 OutputString("Target: ", DECORATION_YELLOW);
357 OutputString(target->label().GetUserVisibleName(false) + "\n");
358 OutputString("Type: ", DECORATION_YELLOW);
359 OutputString(std::string(
360 Target::GetStringForOutputType(target->output_type())) + "\n");
361 OutputString("Toolchain: ", DECORATION_YELLOW);
362 OutputString(target_toolchain.GetUserVisibleName(false) + "\n");
364 PrintSources(target, true);
365 PrintConfigs(target, true);
367 OUTPUT_CONFIG_VALUE(defines, std::string)
368 OUTPUT_CONFIG_VALUE(include_dirs, SourceDir)
369 OUTPUT_CONFIG_VALUE(cflags, std::string)
370 OUTPUT_CONFIG_VALUE(cflags_c, std::string)
371 OUTPUT_CONFIG_VALUE(cflags_cc, std::string)
372 OUTPUT_CONFIG_VALUE(cflags_objc, std::string)
373 OUTPUT_CONFIG_VALUE(cflags_objcc, std::string)
374 OUTPUT_CONFIG_VALUE(ldflags, std::string)
375 PrintLibs(target, true);
376 PrintLibDirs(target, true);
378 PrintDeps(target, true);
383 } // namespace commands