Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1007)

Side by Side Diff: tools/gn/command_desc.cc

Issue 2064533002: [GN] Add JSON project writer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: [GN] fix include order Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/gn/command_gen.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <sstream> 9 #include <sstream>
10 10
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "build/build_config.h" 12 #include "base/json/json_writer.h"
13 #include "base/memory/ptr_util.h"
13 #include "tools/gn/commands.h" 14 #include "tools/gn/commands.h"
14 #include "tools/gn/config.h" 15 #include "tools/gn/config.h"
15 #include "tools/gn/config_values_extractors.h" 16 #include "tools/gn/desc_builder.h"
16 #include "tools/gn/deps_iterator.h"
17 #include "tools/gn/filesystem_utils.h"
18 #include "tools/gn/item.h"
19 #include "tools/gn/label.h"
20 #include "tools/gn/runtime_deps.h"
21 #include "tools/gn/setup.h" 17 #include "tools/gn/setup.h"
22 #include "tools/gn/standard_out.h" 18 #include "tools/gn/standard_out.h"
23 #include "tools/gn/substitution_writer.h"
24 #include "tools/gn/switches.h" 19 #include "tools/gn/switches.h"
25 #include "tools/gn/target.h" 20 #include "tools/gn/target.h"
26 #include "tools/gn/variables.h" 21 #include "tools/gn/variables.h"
27 22
28 namespace commands { 23 namespace commands {
29 24
30 namespace { 25 namespace {
31 26
32 // Desc-specific command line switches. 27 // Desc-specific command line switches.
33 const char kBlame[] = "blame"; 28 const char kBlame[] = "blame";
34 const char kTree[] = "tree"; 29 const char kTree[] = "tree";
35 30 const char kAll[] = "all";
36 // Prints the given directory in a nice way for the user to view. 31
37 std::string FormatSourceDir(const SourceDir& dir) { 32 // Prints value with specified indentation level
38 #if defined(OS_WIN) 33 void PrintValue(const base::Value* value, int indentLevel) {
39 // On Windows we fix up system absolute paths to look like native ones. 34 std::string indent(indentLevel * 2, ' ');
40 // Internally, they'll look like "/C:\foo\bar/" 35 const base::ListValue* list = nullptr;
41 if (dir.is_system_absolute()) { 36 const base::DictionaryValue* dict = nullptr;
42 std::string buf = dir.value(); 37 std::string string;
43 if (buf.size() > 3 && buf[2] == ':') { 38 bool b(false);
brettw 2016/07/01 23:34:17 Can you do bool bool_value = false; (the paren-s
44 buf.erase(buf.begin()); // Erase beginning slash. 39 if (value->GetAsList(&list)) {
45 return buf; 40 for (const auto& v : *list) {
46 } 41 PrintValue(v.get(), indentLevel);
47 } 42 }
48 #endif 43 } else if (value->GetAsString(&string)) {
49 return dir.value(); 44 OutputString(indent);
50 } 45 OutputString(string);
51
52 void RecursiveCollectChildDeps(const Target* target,
53 std::set<const Target*>* result);
54
55 void RecursiveCollectDeps(const Target* target,
56 std::set<const Target*>* result) {
57 if (result->find(target) != result->end())
58 return; // Already did this target.
59 result->insert(target);
60
61 RecursiveCollectChildDeps(target, result);
62 }
63
64 void RecursiveCollectChildDeps(const Target* target,
65 std::set<const Target*>* result) {
66 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
67 RecursiveCollectDeps(pair.ptr, result);
68 }
69
70 // Prints dependencies of the given target (not the target itself). If the
71 // set is non-null, new targets encountered will be added to the set, and if
72 // a dependency is in the set already, it will not be recused into. When the
73 // set is null, all dependencies will be printed.
74 void RecursivePrintDeps(const Target* target,
75 const Label& default_toolchain,
76 std::set<const Target*>* seen_targets,
77 int indent_level) {
78 // Combine all deps into one sorted list.
79 std::vector<LabelTargetPair> sorted_deps;
80 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
81 sorted_deps.push_back(pair);
82 std::sort(sorted_deps.begin(), sorted_deps.end(),
83 LabelPtrLabelLess<Target>());
84
85 std::string indent(indent_level * 2, ' ');
86 for (const auto& pair : sorted_deps) {
87 const Target* cur_dep = pair.ptr;
88
89 OutputString(indent +
90 cur_dep->label().GetUserVisibleName(default_toolchain));
91 bool print_children = true;
92 if (seen_targets) {
93 if (seen_targets->find(cur_dep) == seen_targets->end()) {
94 // New target, mark it visited.
95 seen_targets->insert(cur_dep);
96 } else {
97 // Already seen.
98 print_children = false;
99 // Only print "..." if something is actually elided, which means that
100 // the current target has children.
101 if (!cur_dep->public_deps().empty() ||
102 !cur_dep->private_deps().empty() ||
103 !cur_dep->data_deps().empty())
104 OutputString("...");
105 }
106 }
107
108 OutputString("\n"); 46 OutputString("\n");
109 if (print_children) { 47 } else if (value->GetAsBoolean(&b)) {
110 RecursivePrintDeps(cur_dep, default_toolchain, seen_targets, 48 OutputString(indent);
111 indent_level + 1); 49 OutputString(b ? "true" : "false");
112 } 50 OutputString("\n");
113 } 51 } else if (value->GetAsDictionary(&dict)) {
114 } 52 base::DictionaryValue::Iterator iter(*dict);
115 53 while (!iter.IsAtEnd()) {
116 void PrintDeps(const Target* target, bool display_header) { 54 OutputString(indent + iter.key() + "\n");
117 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); 55 PrintValue(&iter.value(), indentLevel + 1);
118 Label toolchain_label = target->label().GetToolchainLabel(); 56 iter.Advance();
119 57 }
120 // Tree mode is separate. 58 } else if (value->IsType(base::Value::TYPE_NULL)) {
121 if (cmdline->HasSwitch(kTree)) { 59 OutputString(indent + "<null>\n");
122 if (display_header) 60 }
123 OutputString("\nDependency tree\n"); 61 }
124 62
125 if (cmdline->HasSwitch("all")) { 63 // Default handler for property
126 // Show all tree deps with no eliding. 64 void DefaultHandler(const std::string& name, const base::Value* value) {
127 RecursivePrintDeps(target, toolchain_label, nullptr, 1); 65 OutputString("\n");
66 OutputString(name);
67 OutputString("\n");
68 PrintValue(value, 1);
69 }
70
71 // Specific handler for properties that needs different treatment
72
73 void TypeHandler(const std::string& name, const base::Value* value) {
74 std::string type;
75 if (value->GetAsString(&type)) {
76 auto t = DescBuilder::GetOutputTypeForString(type);
77 OutputString("Type: ", DECORATION_YELLOW);
78 OutputString(Target::GetStringForOutputType(t));
79 OutputString("\n");
80 }
81 }
82
83 void ToolchainHandler(const std::string& name, const base::Value* value) {
84 std::string toolchain;
85 if (value->GetAsString(&toolchain)) {
86 OutputString("Toolchain: ", DECORATION_YELLOW);
87 OutputString(toolchain + "\n");
88 }
89 }
90
91 void VisibilityHandler(const std::string& name, const base::Value* value) {
92 const base::ListValue* list;
93 if (value->GetAsList(&list)) {
94 if (list->empty()) {
95 base::StringValue str("(no visibility)");
96 DefaultHandler(name, &str);
128 } else { 97 } else {
129 // Don't recurse into duplicates. 98 DefaultHandler(name, value);
130 std::set<const Target*> seen_targets; 99 }
131 RecursivePrintDeps(target, toolchain_label, &seen_targets, 1); 100 }
132 } 101 }
133 return; 102
134 } 103 void PublicHandler(const std::string& name, const base::Value* value) {
135 104 std::string p;
136 // Collect the deps to display. 105 if (value->GetAsString(&p)) {
137 if (cmdline->HasSwitch("all")) { 106 if (p == "*") {
138 // Show all dependencies. 107 base::StringValue str("[All headers listed in the sources are public.]");
139 if (display_header) 108 DefaultHandler(name, &str);
140 OutputString("\nAll recursive dependencies\n"); 109 return;
141 110 }
142 std::set<const Target*> all_deps; 111 }
143 RecursiveCollectChildDeps(target, &all_deps); 112 DefaultHandler(name, value);
144 FilterAndPrintTargetSet(display_header, all_deps); 113 }
114
115 void ConfigsHandler(const std::string& name, const base::Value* value) {
116 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
117 if (tree)
118 DefaultHandler(name + " tree (in order applying)", value);
119 else
120 DefaultHandler(name + " (in order applying, try also --tree)", value);
121 }
122
123 void DepsHandler(const std::string& name, const base::Value* value) {
124 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
125 bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
126 if (tree) {
127 DefaultHandler("Dependency tree", value);
145 } else { 128 } else {
146 std::vector<const Target*> deps; 129 if (!all) {
147 // Show direct dependencies only. 130 DefaultHandler(
148 if (display_header) { 131 "Direct dependencies "
149 OutputString( 132 "(try also \"--all\", \"--tree\", or even \"--all --tree\")",
150 "\nDirect dependencies " 133 value);
151 "(try also \"--all\", \"--tree\", or even \"--all --tree\")\n"); 134 } else {
152 } 135 DefaultHandler("All recursive dependencies", value);
153 for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) 136 }
154 deps.push_back(pair.ptr); 137 }
155 std::sort(deps.begin(), deps.end()); 138 }
156 FilterAndPrintTargets(display_header, &deps); 139
157 } 140 // Outputs need special processing when output patterns are present
158 } 141 void ProcessOutputs(base::DictionaryValue* target) {
159 142 base::ListValue* patterns = nullptr;
160 // libs and lib_dirs are special in that they're inherited. We don't currently 143 base::ListValue* outputs = nullptr;
161 // implement a blame feature for this since the bottom-up inheritance makes 144 target->GetList("output_patterns", &patterns);
162 // this difficult. 145 target->GetList(variables::kOutputs, &outputs);
163 void PrintLibDirs(const Target* target, bool display_header) { 146
164 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs(); 147 if (outputs || patterns) {
165 if (lib_dirs.empty())
166 return;
167
168 if (display_header)
169 OutputString("\nlib_dirs\n");
170
171 for (size_t i = 0; i < lib_dirs.size(); i++)
172 OutputString(" " + FormatSourceDir(lib_dirs[i]) + "\n");
173 }
174
175 void PrintLibs(const Target* target, bool display_header) {
176 const OrderedSet<LibFile>& libs = target->all_libs();
177 if (libs.empty())
178 return;
179
180 if (display_header)
181 OutputString("\nlibs\n");
182
183 for (size_t i = 0; i < libs.size(); i++)
184 OutputString(" " + libs[i].value() + "\n");
185 }
186
187 void PrintPublic(const Target* target, bool display_header) {
188 if (display_header)
189 OutputString("\npublic\n");
190
191 if (target->all_headers_public()) {
192 OutputString(" [All headers listed in the sources are public.]\n");
193 return;
194 }
195
196 Target::FileList public_headers = target->public_headers();
197 std::sort(public_headers.begin(), public_headers.end());
198 for (const auto& hdr : public_headers)
199 OutputString(" " + hdr.value() + "\n");
200 }
201
202 void PrintCheckIncludes(const Target* target, bool display_header) {
203 if (display_header)
204 OutputString("\ncheck_includes\n");
205
206 if (target->check_includes())
207 OutputString(" true\n");
208 else
209 OutputString(" false\n");
210 }
211
212 void PrintAllowCircularIncludesFrom(const Target* target, bool display_header) {
213 if (display_header)
214 OutputString("\nallow_circular_includes_from\n");
215
216 Label toolchain_label = target->label().GetToolchainLabel();
217 for (const auto& cur : target->allow_circular_includes_from())
218 OutputString(" " + cur.GetUserVisibleName(toolchain_label) + "\n");
219 }
220
221 void PrintVisibility(const Target* target, bool display_header) {
222 if (display_header)
223 OutputString("\nvisibility\n");
224
225 OutputString(target->visibility().Describe(2, false));
226 }
227
228 void PrintTestonly(const Target* target, bool display_header) {
229 if (display_header)
230 OutputString("\ntestonly\n");
231
232 if (target->testonly())
233 OutputString(" true\n");
234 else
235 OutputString(" false\n");
236 }
237
238 // Recursively prints subconfigs of a config.
239 void PrintSubConfigs(const Config* config, int indent_level) {
240 if (config->configs().empty())
241 return;
242
243 std::string indent(indent_level * 2, ' ');
244 Label toolchain_label = config->label().GetToolchainLabel();
245 for (const auto& pair : config->configs()) {
246 OutputString(
247 indent + pair.label.GetUserVisibleName(toolchain_label) + "\n");
248 PrintSubConfigs(pair.ptr, indent_level + 1);
249 }
250 }
251
252 // This allows configs stored as either std::vector<LabelConfigPair> or
253 // UniqueVector<LabelConfigPair> to be printed.
254 template <class VectorType>
255 void PrintConfigsVector(const Item* item,
256 const VectorType& configs,
257 const std::string& heading,
258 bool display_header) {
259 if (configs.empty())
260 return;
261
262 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
263
264 // Don't sort since the order determines how things are processed.
265 if (display_header) {
266 if (tree)
267 OutputString("\n" + heading + " tree (in order applying)\n");
268 else
269 OutputString("\n" + heading + " (in order applying, try also --tree)\n");
270 }
271
272 Label toolchain_label = item->label().GetToolchainLabel();
273 for (const auto& config : configs) {
274 OutputString(" " + config.label.GetUserVisibleName(toolchain_label) +
275 "\n");
276 if (tree)
277 PrintSubConfigs(config.ptr, 2); // 2 = start with double-indent.
278 }
279 }
280
281 void PrintConfigs(const Target* target, bool display_header) {
282 PrintConfigsVector(target, target->configs().vector(), "configs",
283 display_header);
284 }
285
286 void PrintConfigs(const Config* config, bool display_header) {
287 PrintConfigsVector(config, config->configs().vector(), "configs",
288 display_header);
289 }
290
291 void PrintPublicConfigs(const Target* target, bool display_header) {
292 PrintConfigsVector(target, target->public_configs(),
293 "public_configs", display_header);
294 }
295
296 void PrintAllDependentConfigs(const Target* target, bool display_header) {
297 PrintConfigsVector(target, target->all_dependent_configs(),
298 "all_dependent_configs", display_header);
299 }
300
301 void PrintFileList(const Target::FileList& files,
302 const std::string& header,
303 bool indent_extra,
304 bool display_header) {
305 if (files.empty())
306 return;
307
308 if (display_header)
309 OutputString("\n" + header + "\n");
310
311 std::string indent = indent_extra ? " " : " ";
312
313 Target::FileList sorted = files;
314 std::sort(sorted.begin(), sorted.end());
315 for (const auto& elem : sorted)
316 OutputString(indent + elem.value() + "\n");
317 }
318
319 void PrintSources(const Target* target, bool display_header) {
320 PrintFileList(target->sources(), "sources", false, display_header);
321 }
322
323 void PrintInputs(const Target* target, bool display_header) {
324 PrintFileList(target->inputs(), "inputs", false, display_header);
325 }
326
327 void PrintOutputs(const Target* target, bool display_header) {
328 if (display_header)
329 OutputString("\noutputs\n"); 148 OutputString("\noutputs\n");
330 149 int indent = 1;
331 if (target->output_type() == Target::ACTION) { 150 if (patterns) {
332 // Action, print out outputs, don't apply sources to it. 151 OutputString(" Output patterns\n");
333 for (const auto& elem : target->action_values().outputs().list()) { 152 indent = 2;
334 OutputString(" " + elem.AsString() + "\n"); 153 PrintValue(patterns, indent);
335 }
336 } else if (target->output_type() == Target::CREATE_BUNDLE) {
337 std::vector<SourceFile> output_files;
338 target->bundle_data().GetOutputsAsSourceFiles(target->settings(),
339 &output_files);
340 PrintFileList(output_files, std::string(), true, false);
341 } else {
342 const SubstitutionList& outputs = target->action_values().outputs();
343 if (!outputs.required_types().empty()) {
344 // Display the pattern and resolved pattern separately, since there are
345 // subtitutions used.
346 OutputString(" Output pattern\n");
347 for (const auto& elem : outputs.list())
348 OutputString(" " + elem.AsString() + "\n");
349
350 // Now display what that resolves to given the sources.
351 OutputString("\n Resolved output file list\n"); 154 OutputString("\n Resolved output file list\n");
352 } 155 }
353 156 if (outputs)
354 // Resolved output list. 157 PrintValue(outputs, indent);
355 std::vector<SourceFile> output_files; 158
356 SubstitutionWriter::ApplyListToSources(target->settings(), outputs, 159 target->Remove("output_patterns", nullptr);
357 target->sources(), &output_files); 160 target->Remove(variables::kOutputs, nullptr);
358 PrintFileList(output_files, std::string(), true, false); 161 }
359 }
360 }
361
362 void PrintScript(const Target* target, bool display_header) {
363 if (display_header)
364 OutputString("\nscript\n");
365 OutputString(" " + target->action_values().script().value() + "\n");
366 }
367
368 void PrintArgs(const Target* target, bool display_header) {
369 if (display_header)
370 OutputString("\nargs\n");
371 for (const auto& elem : target->action_values().args().list()) {
372 OutputString(" " + elem.AsString() + "\n");
373 }
374 }
375
376 void PrintDepfile(const Target* target, bool display_header) {
377 if (target->action_values().depfile().empty())
378 return;
379 if (display_header)
380 OutputString("\ndepfile\n");
381 OutputString(" " + target->action_values().depfile().AsString() + "\n");
382 }
383
384 // Attribute the origin for attributing from where a target came from. Does
385 // nothing if the input is null or it does not have a location.
386 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
387 if (!origin)
388 return;
389 Location location = origin->GetRange().begin();
390 out << " (Added by " + location.file()->name().value() << ":"
391 << location.line_number() << ")\n";
392 }
393
394 // Templatized writer for writing out different config value types.
395 template<typename T> struct DescValueWriter {};
396 template<> struct DescValueWriter<std::string> {
397 void operator()(const std::string& str, std::ostream& out) const {
398 out << " " << str << "\n";
399 }
400 };
401
402 template<> struct DescValueWriter<SourceDir> {
403 void operator()(const SourceDir& dir, std::ostream& out) const {
404 out << " " << FormatSourceDir(dir) << "\n";
405 }
406 };
407
408 template<> struct DescValueWriter<LibFile> {
409 void operator()(const LibFile& lib, std::ostream& out) const {
410 if (lib.is_source_file())
411 out << " " << lib.source_file().value() << "\n";
412 else
413 out << " " << lib.value() << "\n";
414 }
415 };
416
417 // Writes a given config value type to the string, optionally with attribution.
418 // This should match RecursiveTargetConfigToStream in the order it traverses.
419 template<typename T> void OutputRecursiveTargetConfig(
420 const Target* target,
421 const char* header_name,
422 const std::vector<T>& (ConfigValues::* getter)() const) {
423 bool display_blame =
424 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
425
426 DescValueWriter<T> writer;
427 std::ostringstream out;
428
429 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
430 if ((iter.cur().*getter)().empty())
431 continue;
432
433 // Optional blame sub-head.
434 if (display_blame) {
435 const Config* config = iter.GetCurrentConfig();
436 if (config) {
437 // Source of this value is a config.
438 out << " From " << config->label().GetUserVisibleName(false) << "\n";
439 OutputSourceOfDep(iter.origin(), out);
440 } else {
441 // Source of this value is the target itself.
442 out << " From " << target->label().GetUserVisibleName(false) << "\n";
443 }
444 }
445
446 // Actual values.
447 ConfigValuesToStream(iter.cur(), getter, writer, out);
448 }
449
450 std::string out_str = out.str();
451 if (!out_str.empty()) {
452 if (header_name)
453 OutputString("\n" + std::string(header_name) + "\n");
454 OutputString(out_str);
455 }
456 }
457
458 template<typename T> void OutputConfigValueArray(
459 const ConfigValues& values,
460 const char* header_name,
461 const std::vector<T>& (ConfigValues::* getter)() const) {
462 std::ostringstream out;
463
464 DescValueWriter<T> writer;
465 for (const T& cur : (values.*getter)())
466 writer(cur, out);
467
468 std::string out_str = out.str();
469 if (!out_str.empty()) {
470 if (header_name)
471 OutputString("\n" + std::string(header_name) + "\n");
472 OutputString(out_str);
473 }
474 }
475
476 void PrintRuntimeDeps(const Target* target) {
477 bool display_blame =
478 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
479 Label toolchain = target->label().GetToolchainLabel();
480
481 const Target* previous_from = NULL;
482 for (const auto& pair : ComputeRuntimeDeps(target)) {
483 if (display_blame) {
484 // Generally a target's runtime deps will be listed sequentially, so
485 // group them and don't duplicate the "from" label for two in a row.
486 if (previous_from == pair.second) {
487 OutputString(" "); // Just indent.
488 } else {
489 previous_from = pair.second;
490 OutputString("From ");
491 OutputString(pair.second->label().GetUserVisibleName(toolchain));
492 OutputString("\n "); // Make the file name indented.
493 }
494 }
495 OutputString(pair.first.value());
496 OutputString("\n");
497 }
498 }
499
500 // If "what" is empty, prints all PCH info. If "what" is nonempty, prints only
501 // the things that match (if any). Returns true if anything was printed.
502 bool PrintPrecompiledHeaderInfo(const ConfigValues& values,
503 const std::string& what,
504 bool display_headers) {
505 bool found_match = false;
506 if (what == variables::kPrecompiledHeader || what.empty()) {
507 if (!values.precompiled_header().empty()) {
508 if (display_headers)
509 OutputString("\nprecompiled_header\n");
510 OutputString(values.precompiled_header() + "\n");
511 }
512 found_match = true;
513 }
514 if (what == variables::kPrecompiledSource || what.empty()) {
515 if (!values.precompiled_source().is_null()) {
516 if (display_headers)
517 OutputString("\nprecompiled_source\n");
518 OutputString(values.precompiled_source().value() + "\n");
519 }
520 found_match = true;
521 }
522 return found_match;
523 } 162 }
524 163
525 bool PrintTarget(const Target* target, 164 bool PrintTarget(const Target* target,
526 const std::string& what, 165 const std::string& what,
527 bool display_target_header) { 166 bool single_target,
528 if (display_target_header) { 167 bool all,
529 OutputString("Target: ", DECORATION_YELLOW); 168 bool tree,
530 OutputString(target->label().GetUserVisibleName(false) + "\n"); 169 bool blame) {
531 OutputString("Type: ", DECORATION_YELLOW); 170 std::unique_ptr<base::DictionaryValue> dict =
532 OutputString(std::string( 171 DescBuilder::DescriptionForTarget(target, what, all, tree, blame);
533 Target::GetStringForOutputType(target->output_type())) + "\n"); 172 if (!what.empty() && dict->empty()) {
534 OutputString("Toolchain: ", DECORATION_YELLOW);
535 OutputString(
536 target->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
537 }
538
539 // Display headers when outputting everything.
540 bool display_headers = what.empty();
541 bool is_binary_output = target->IsBinary();
542
543 bool found_match = false;
544
545 // General target meta variables.
546 if (what.empty() || what == variables::kVisibility) {
547 PrintVisibility(target, display_headers);
548 found_match = true;
549 }
550 if (what.empty() || what == variables::kTestonly) {
551 PrintTestonly(target, display_headers);
552 found_match = true;
553 }
554
555 // Binary target meta variables.
556 if (is_binary_output) {
557 if (what.empty() || what == variables::kCheckIncludes) {
558 PrintCheckIncludes(target, display_headers);
559 found_match = true;
560 }
561 if (what.empty() || what == variables::kAllowCircularIncludesFrom) {
562 PrintAllowCircularIncludesFrom(target, display_headers);
563 found_match = true;
564 }
565 }
566
567 // Sources and inputs.
568 if (what.empty() || what == variables::kSources) {
569 PrintSources(target, display_headers);
570 found_match = true;
571 }
572 if (what.empty() || what == variables::kPublic) {
573 PrintPublic(target, display_headers);
574 found_match = true;
575 }
576 if (what.empty() || what == variables::kInputs) {
577 PrintInputs(target, display_headers);
578 found_match = true;
579 }
580
581 // Configs. Configs set directly on a target are only relevant for binary
582 // targets
583 if (is_binary_output && (what.empty() || what == variables::kConfigs)) {
584 PrintConfigs(target, display_headers);
585 found_match = true;
586 }
587
588 // Dependent/public configs can be applied to anything.
589 if (what.empty() || what == variables::kPublicConfigs) {
590 PrintPublicConfigs(target, display_headers);
591 found_match = true;
592 }
593 if (what.empty() || what == variables::kAllDependentConfigs) {
594 PrintAllDependentConfigs(target, display_headers);
595 found_match = true;
596 }
597
598 // Action values.
599 if (target->output_type() == Target::ACTION ||
600 target->output_type() == Target::ACTION_FOREACH) {
601 if (what.empty() || what == variables::kScript) {
602 PrintScript(target, display_headers);
603 found_match = true;
604 }
605 if (what.empty() || what == variables::kArgs) {
606 PrintArgs(target, display_headers);
607 found_match = true;
608 }
609 if (what.empty() || what == variables::kDepfile) {
610 PrintDepfile(target, display_headers);
611 found_match = true;
612 }
613 }
614
615 // Outputs.
616 if (target->output_type() == Target::ACTION ||
617 target->output_type() == Target::ACTION_FOREACH ||
618 target->output_type() == Target::COPY_FILES ||
619 target->output_type() == Target::CREATE_BUNDLE) {
620 if (what.empty() || what == variables::kOutputs) {
621 PrintOutputs(target, display_headers);
622 found_match = true;
623 }
624 }
625
626 // Values from configs only apply to binary targets.
627 if (is_binary_output) {
628 #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
629 if (what.empty() || what == #name) { \
630 OutputRecursiveTargetConfig<type>( \
631 target, display_headers ? #name : nullptr, &ConfigValues::name); \
632 found_match = true; \
633 }
634
635 CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
636 CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
637 CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
638 CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
639 CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
640 CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
641 CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
642 CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
643 CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
644 CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
645 // Libs and lib_dirs are handled specially below.
646
647 #undef CONFIG_VALUE_ARRAY_HANDLER
648
649 found_match |= PrintPrecompiledHeaderInfo(target->config_values(),
650 what, display_headers);
651 }
652
653 // Deps
654 if (what.empty() || what == "deps") {
655 PrintDeps(target, display_headers);
656 found_match = true;
657 }
658
659 // Runtime deps are special, print only when explicitly asked for and not in
660 // overview mode.
661 if (what == "runtime_deps") {
662 PrintRuntimeDeps(target);
663 found_match = true;
664 }
665
666 // Libs can be part of any target and get recursively pushed up the chain,
667 // so display them regardless of target type.
668 if (what.empty() || what == variables::kLibs) {
669 PrintLibs(target, display_headers);
670 found_match = true;
671 }
672 if (what.empty() || what == variables::kLibDirs) {
673 PrintLibDirs(target, display_headers);
674 found_match = true;
675 }
676
677 if (!found_match) {
678 OutputString("Don't know how to display \"" + what + "\" for \"" + 173 OutputString("Don't know how to display \"" + what + "\" for \"" +
679 Target::GetStringForOutputType(target->output_type()) + "\".\n"); 174 Target::GetStringForOutputType(target->output_type()) +
175 "\".\n");
680 return false; 176 return false;
681 } 177 }
178 // Print single value, without any headers
179 if (!what.empty() && dict->size() == 1 && single_target) {
180 base::DictionaryValue::Iterator iter(*dict);
181 PrintValue(&iter.value(), 0);
182 return true;
183 }
184
185 OutputString("Target ", DECORATION_YELLOW);
186 OutputString(target->label().GetUserVisibleName(false));
187 OutputString("\n");
188
189 std::unique_ptr<base::Value> v;
190 #define HANDLER(property, handler_name) \
191 if (dict->Remove(property, &v)) { \
192 handler_name(property, v.get()); \
193 }
194
195 // Entries with DefaultHandler are present to enforce order
196 HANDLER("type", TypeHandler);
197 HANDLER("toolchain", ToolchainHandler);
198 HANDLER(variables::kVisibility, VisibilityHandler);
199 HANDLER(variables::kTestonly, DefaultHandler);
200 HANDLER(variables::kCheckIncludes, DefaultHandler);
201 HANDLER(variables::kAllowCircularIncludesFrom, DefaultHandler);
202 HANDLER(variables::kSources, DefaultHandler);
203 HANDLER(variables::kPublic, PublicHandler);
204 HANDLER(variables::kInputs, DefaultHandler);
205 HANDLER(variables::kConfigs, ConfigsHandler);
206 HANDLER(variables::kPublicConfigs, ConfigsHandler);
207 HANDLER(variables::kAllDependentConfigs, ConfigsHandler);
208 HANDLER(variables::kScript, DefaultHandler);
209 HANDLER(variables::kArgs, DefaultHandler);
210 HANDLER(variables::kDepfile, DefaultHandler);
211 ProcessOutputs(dict.get());
212 HANDLER("bundle_data", DefaultHandler);
213 HANDLER(variables::kArflags, DefaultHandler);
214 HANDLER(variables::kAsmflags, DefaultHandler);
215 HANDLER(variables::kCflags, DefaultHandler);
216 HANDLER(variables::kCflagsC, DefaultHandler);
217 HANDLER(variables::kCflagsCC, DefaultHandler);
218 HANDLER(variables::kCflagsObjC, DefaultHandler);
219 HANDLER(variables::kCflagsObjCC, DefaultHandler);
220 HANDLER(variables::kDefines, DefaultHandler);
221 HANDLER(variables::kIncludeDirs, DefaultHandler);
222 HANDLER(variables::kLdflags, DefaultHandler);
223 HANDLER(variables::kPrecompiledHeader, DefaultHandler);
224 HANDLER(variables::kPrecompiledSource, DefaultHandler);
225 HANDLER(variables::kDeps, DepsHandler);
226 HANDLER(variables::kLibs, DefaultHandler);
227 HANDLER(variables::kLibDirs, DefaultHandler);
228
229 #undef HANDLER
230
231 // Process the rest (if any)
232 base::DictionaryValue::Iterator iter(*dict);
233 while (!iter.IsAtEnd()) {
234 DefaultHandler(iter.key(), &iter.value());
235 iter.Advance();
236 }
237
682 return true; 238 return true;
683 } 239 }
684 240
685 bool PrintConfig(const Config* config, 241 bool PrintConfig(const Config* config,
686 const std::string& what, 242 const std::string& what,
687 bool display_config_header) { 243 bool single_config) {
688 const ConfigValues& values = config->resolved_values(); 244 std::unique_ptr<base::DictionaryValue> dict =
689 245 DescBuilder::DescriptionForConfig(config, what);
690 if (display_config_header) { 246 if (!what.empty() && dict->empty()) {
691 OutputString("Config: ", DECORATION_YELLOW);
692 OutputString(config->label().GetUserVisibleName(false) + "\n");
693 OutputString("Toolchain: ", DECORATION_YELLOW);
694 OutputString(
695 config->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
696 if (what.empty() && !config->configs().empty()) {
697 OutputString(
698 "(This is a composite config, the values below are after the\n"
699 "expansion of the child configs.)\n");
700 }
701 }
702
703 // Display headers when outputting everything.
704 bool display_headers = what.empty();
705
706 if (what.empty() || what == variables::kConfigs)
707 PrintConfigs(config, display_headers);
708
709 #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
710 if (what.empty() || what == #name) { \
711 OutputConfigValueArray<type>(values, display_headers ? #name : nullptr, \
712 &ConfigValues::name); \
713 found_match = true; \
714 }
715
716 bool found_match = false;
717
718 CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
719 CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
720 CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
721 CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
722 CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
723 CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
724 CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
725 CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
726 CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
727 CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
728 CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
729 CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
730
731 #undef CONFIG_VALUE_ARRAY_HANDLER
732
733 // Handles all PCH-related variables.
734 found_match |= PrintPrecompiledHeaderInfo(config->resolved_values(),
735 what, display_headers);
736
737 if (!found_match) {
738 OutputString("Don't know how to display \"" + what + "\" for a config.\n"); 247 OutputString("Don't know how to display \"" + what + "\" for a config.\n");
739 return false; 248 return false;
740 } 249 }
250 // Print single value, without any headers
251 if (!what.empty() && dict->size() == 1 && single_config) {
252 base::DictionaryValue::Iterator iter(*dict);
253 PrintValue(&iter.value(), 0);
254 return true;
255 }
256
257 OutputString("Config: ", DECORATION_YELLOW);
258 OutputString(config->label().GetUserVisibleName(false));
259 OutputString("\n");
260
261 std::unique_ptr<base::Value> v;
262 #define HANDLER(property, handler_name) \
263 if (dict->Remove(property, &v)) { \
264 handler_name(property, v.get()); \
265 }
266
267 HANDLER("toolchain", ToolchainHandler);
268 if (!config->configs().empty()) {
269 OutputString(
270 "(This is a composite config, the values below are after the\n"
271 "expansion of the child configs.)\n");
272 }
273 HANDLER(variables::kArflags, DefaultHandler);
274 HANDLER(variables::kAsmflags, DefaultHandler);
275 HANDLER(variables::kCflags, DefaultHandler);
276 HANDLER(variables::kCflagsC, DefaultHandler);
277 HANDLER(variables::kCflagsCC, DefaultHandler);
278 HANDLER(variables::kCflagsObjC, DefaultHandler);
279 HANDLER(variables::kCflagsObjCC, DefaultHandler);
280 HANDLER(variables::kDefines, DefaultHandler);
281 HANDLER(variables::kIncludeDirs, DefaultHandler);
282 HANDLER(variables::kLdflags, DefaultHandler);
283 HANDLER(variables::kLibs, DefaultHandler);
284 HANDLER(variables::kLibDirs, DefaultHandler);
285 HANDLER(variables::kPrecompiledHeader, DefaultHandler);
286 HANDLER(variables::kPrecompiledSource, DefaultHandler);
287
288 #undef HANDLER
289
741 return true; 290 return true;
742 } 291 }
743 292
744 } // namespace 293 } // namespace
745 294
746 // desc ------------------------------------------------------------------------ 295 // desc ------------------------------------------------------------------------
747 296
748 const char kDesc[] = "desc"; 297 const char kDesc[] = "desc";
749 const char kDesc_HelpShort[] = 298 const char kDesc_HelpShort[] =
750 "desc: Show lots of insightful information about a target or config."; 299 "desc: Show lots of insightful information about a target or config.";
751 const char kDesc_Help[] = 300 const char kDesc_Help[] =
752 "gn desc <out_dir> <label or pattern> [<what to show>] [--blame]\n" 301 "gn desc <out_dir> <label or pattern> [<what to show>] [--blame] "
302 "[--format=json]\n"
753 "\n" 303 "\n"
754 " Displays information about a given target or config. The build\n" 304 " Displays information about a given target or config. The build\n"
755 " build parameters will be taken for the build in the given <out_dir>.\n" 305 " build parameters will be taken for the build in the given <out_dir>.\n"
756 "\n" 306 "\n"
757 " The <label or pattern> can be a target label, a config label, or a\n" 307 " The <label or pattern> can be a target label, a config label, or a\n"
758 " label pattern (see \"gn help label_pattern\"). A label pattern will\n" 308 " label pattern (see \"gn help label_pattern\"). A label pattern will\n"
759 " only match targets.\n" 309 " only match targets.\n"
760 "\n" 310 "\n"
761 "Possibilities for <what to show>\n" 311 "Possibilities for <what to show>\n"
762 "\n" 312 "\n"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 "\n" 362 "\n"
813 "Configs\n" 363 "Configs\n"
814 "\n" 364 "\n"
815 " The \"configs\" section will list all configs that apply. For targets\n" 365 " The \"configs\" section will list all configs that apply. For targets\n"
816 " this will include configs specified in the \"configs\" variable of\n" 366 " this will include configs specified in the \"configs\" variable of\n"
817 " the target, and also configs pushed onto this target via public\n" 367 " the target, and also configs pushed onto this target via public\n"
818 " or \"all dependent\" configs.\n" 368 " or \"all dependent\" configs.\n"
819 "\n" 369 "\n"
820 " Configs can have child configs. Specifying --tree will show the\n" 370 " Configs can have child configs. Specifying --tree will show the\n"
821 " hierarchy.\n" 371 " hierarchy.\n"
822 "\n" 372 "\n"
823 "Printing deps\n" 373 "Printing deps\n"
824 "\n" 374 "\n"
825 " Deps will include all public, private, and data deps (TODO this could\n" 375 " Deps will include all public, private, and data deps (TODO this could\n"
826 " be clarified and enhanced) sorted in order applying. The following\n" 376 " be clarified and enhanced) sorted in order applying. The following\n"
827 " may be used:\n" 377 " may be used:\n"
828 "\n" 378 "\n"
829 " --all\n" 379 " --all\n"
830 " Collects all recursive dependencies and prints a sorted flat list.\n" 380 " Collects all recursive dependencies and prints a sorted flat list.\n"
831 " Also usable with --tree (see below).\n" 381 " Also usable with --tree (see below).\n"
832 "\n" 382 "\n"
833 TARGET_PRINTING_MODE_COMMAND_LINE_HELP 383 TARGET_PRINTING_MODE_COMMAND_LINE_HELP
834 "\n" 384 "\n"
835 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP 385 TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP
836 "\n" 386 "\n"
837 " --tree\n" 387 " --tree\n"
838 " Print a dependency tree. By default, duplicates will be elided\n" 388 " Print a dependency tree. By default, duplicates will be elided\n"
839 " with \"...\" but when --all and -tree are used together, no\n" 389 " with \"...\" but when --all and -tree are used together, no\n"
840 " eliding will be performed.\n" 390 " eliding will be performed.\n"
841 "\n" 391 "\n"
842 " The \"deps\", \"public_deps\", and \"data_deps\" will all be\n" 392 " The \"deps\", \"public_deps\", and \"data_deps\" will all be\n"
843 " included in the tree.\n" 393 " included in the tree.\n"
844 "\n" 394 "\n"
845 " Tree output can not be used with the filtering or output flags:\n" 395 " Tree output can not be used with the filtering or output flags:\n"
846 " --as, --type, --testonly.\n" 396 " --as, --type, --testonly.\n"
847 "\n" 397 "\n"
848 TARGET_TYPE_FILTER_COMMAND_LINE_HELP 398 TARGET_TYPE_FILTER_COMMAND_LINE_HELP
849 "\n" 399 "\n"
400 "Format\n"
401 "\n"
402 " Optional --format=json flag can be specified to switch output to JSON.\n"
403 "\n"
850 "Note\n" 404 "Note\n"
851 "\n" 405 "\n"
852 " This command will show the full name of directories and source files,\n" 406 " This command will show the full name of directories and source files,\n"
853 " but when directories and source paths are written to the build file,\n" 407 " but when directories and source paths are written to the build file,\n"
854 " they will be adjusted to be relative to the build directory. So the\n" 408 " they will be adjusted to be relative to the build directory. So the\n"
855 " values for paths displayed by this command won't match (but should\n" 409 " values for paths displayed by this command won't match (but should\n"
856 " mean the same thing).\n" 410 " mean the same thing).\n"
857 "\n" 411 "\n"
858 "Examples\n" 412 "Examples\n"
859 "\n" 413 "\n"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 450
897 if (!ResolveFromCommandLineInput( 451 if (!ResolveFromCommandLineInput(
898 setup, target_list, cmdline->HasSwitch(switches::kAllToolchains), 452 setup, target_list, cmdline->HasSwitch(switches::kAllToolchains),
899 &target_matches, &config_matches, &toolchain_matches, &file_matches)) 453 &target_matches, &config_matches, &toolchain_matches, &file_matches))
900 return 1; 454 return 1;
901 455
902 std::string what_to_print; 456 std::string what_to_print;
903 if (args.size() == 3) 457 if (args.size() == 3)
904 what_to_print = args[2]; 458 what_to_print = args[2];
905 459
906 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1; 460 bool json = cmdline->GetSwitchValueASCII("format") == "json";
907 461
908 // Display headers for each target when printing all values, or when printing 462 if (json) {
909 // multiple targets or configs. 463 // Convert all targets/configs to JSON, serialize and print them
910 bool display_item_header = multiple_outputs || what_to_print.empty(); 464 auto res = base::WrapUnique(new base::DictionaryValue());
465 if (!target_matches.empty()) {
466 for (const auto* target : target_matches) {
467 res->Set(target->label().GetUserVisibleName(
468 target->settings()->default_toolchain_label()),
469 DescBuilder::DescriptionForTarget(
470 target, what_to_print, cmdline->HasSwitch(kAll),
471 cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
472 }
473 } else if (!config_matches.empty()) {
474 for (const auto* config : config_matches) {
475 res->Set(config->label().GetUserVisibleName(false),
476 DescBuilder::DescriptionForConfig(config, what_to_print));
477 }
478 }
479 std::string s;
480 base::JSONWriter::WriteWithOptions(
481 *res.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
482 OutputString(s);
483 } else {
484 // Regular (non-json) formatted output
485 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
911 486
912 bool printed_output = false; 487 bool printed_output = false;
913 for (const Target* target : target_matches) { 488 for (const Target* target : target_matches) {
914 if (printed_output) 489 if (printed_output)
915 OutputString("\n\n"); 490 OutputString("\n\n");
916 printed_output = true; 491 printed_output = true;
917 492
918 if (!PrintTarget(target, what_to_print, display_item_header)) 493 if (!PrintTarget(target, what_to_print, !multiple_outputs,
919 return 1; 494 cmdline->HasSwitch(kAll), cmdline->HasSwitch(kTree),
920 } 495 cmdline->HasSwitch(kBlame)))
921 for (const Config* config : config_matches) { 496 return 1;
922 if (printed_output) 497 }
923 OutputString("\n\n"); 498 for (const Config* config : config_matches) {
924 printed_output = true; 499 if (printed_output)
500 OutputString("\n\n");
501 printed_output = true;
925 502
926 if (!PrintConfig(config, what_to_print, display_item_header)) 503 if (!PrintConfig(config, what_to_print, !multiple_outputs))
927 return 1; 504 return 1;
505 }
928 } 506 }
929 507
930 return 0; 508 return 0;
931 } 509 }
932 510
933 } // namespace commands 511 } // namespace commands
OLDNEW
« no previous file with comments | « no previous file | tools/gn/command_gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698