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

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] Add myself to AUTHORS 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 | « tools/gn/BUILD.gn ('k') | 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"
14 #include "base/strings/string_util.h"
13 #include "tools/gn/commands.h" 15 #include "tools/gn/commands.h"
14 #include "tools/gn/config.h" 16 #include "tools/gn/config.h"
15 #include "tools/gn/config_values_extractors.h" 17 #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" 18 #include "tools/gn/setup.h"
22 #include "tools/gn/standard_out.h" 19 #include "tools/gn/standard_out.h"
23 #include "tools/gn/substitution_writer.h"
24 #include "tools/gn/switches.h" 20 #include "tools/gn/switches.h"
25 #include "tools/gn/target.h" 21 #include "tools/gn/target.h"
26 #include "tools/gn/variables.h" 22 #include "tools/gn/variables.h"
27 23
28 namespace commands { 24 namespace commands {
29 25
30 namespace { 26 namespace {
31 27
32 // Desc-specific command line switches. 28 // Desc-specific command line switches.
33 const char kBlame[] = "blame"; 29 const char kBlame[] = "blame";
34 const char kTree[] = "tree"; 30 const char kTree[] = "tree";
35 31 const char kAll[] = "all";
36 // Prints the given directory in a nice way for the user to view. 32
37 std::string FormatSourceDir(const SourceDir& dir) { 33 // Prints value with specified indentation level
38 #if defined(OS_WIN) 34 void PrintValue(const base::Value* value, int indentLevel) {
39 // On Windows we fix up system absolute paths to look like native ones. 35 std::string indent(indentLevel * 2, ' ');
40 // Internally, they'll look like "/C:\foo\bar/" 36 const base::ListValue* list_value = nullptr;
41 if (dir.is_system_absolute()) { 37 const base::DictionaryValue* dict_value = nullptr;
42 std::string buf = dir.value(); 38 std::string string_value;
43 if (buf.size() > 3 && buf[2] == ':') { 39 bool bool_value = false;
44 buf.erase(buf.begin()); // Erase beginning slash. 40 if (value->GetAsList(&list_value)) {
45 return buf; 41 for (const auto& v : *list_value) {
46 } 42 PrintValue(v.get(), indentLevel);
47 } 43 }
48 #endif 44 } else if (value->GetAsString(&string_value)) {
49 return dir.value(); 45 OutputString(indent);
50 } 46 OutputString(string_value);
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"); 47 OutputString("\n");
109 if (print_children) { 48 } else if (value->GetAsBoolean(&bool_value)) {
110 RecursivePrintDeps(cur_dep, default_toolchain, seen_targets, 49 OutputString(indent);
111 indent_level + 1); 50 OutputString(bool_value ? "true" : "false");
112 } 51 OutputString("\n");
113 } 52 } else if (value->GetAsDictionary(&dict_value)) {
114 } 53 base::DictionaryValue::Iterator iter(*dict_value);
115 54 while (!iter.IsAtEnd()) {
116 void PrintDeps(const Target* target, bool display_header) { 55 OutputString(indent + iter.key() + "\n");
117 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); 56 PrintValue(&iter.value(), indentLevel + 1);
118 Label toolchain_label = target->label().GetToolchainLabel(); 57 iter.Advance();
119 58 }
120 // Tree mode is separate. 59 } else if (value->IsType(base::Value::TYPE_NULL)) {
121 if (cmdline->HasSwitch(kTree)) { 60 OutputString(indent + "<null>\n");
122 if (display_header) 61 }
123 OutputString("\nDependency tree\n"); 62 }
124 63
125 if (cmdline->HasSwitch("all")) { 64 // Default handler for property
126 // Show all tree deps with no eliding. 65 void DefaultHandler(const std::string& name, const base::Value* value) {
127 RecursivePrintDeps(target, toolchain_label, nullptr, 1); 66 OutputString("\n");
67 OutputString(name);
68 OutputString("\n");
69 PrintValue(value, 1);
70 }
71
72 // Specific handler for properties that need different treatment
73
74 // Prints label and property value on one line, capitalizing the label.
75 void LabelHandler(std::string name, const base::Value* value) {
76 name[0] = base::ToUpperASCII(name[0]);
77 std::string string_value;
78 if (value->GetAsString(&string_value)) {
79 OutputString(name + ": ", DECORATION_YELLOW);
80 OutputString(string_value + "\n");
81 }
82 }
83
84 void VisibilityHandler(const std::string& name, const base::Value* value) {
85 const base::ListValue* list;
86 if (value->GetAsList(&list)) {
87 if (list->empty()) {
88 base::StringValue str("(no visibility)");
89 DefaultHandler(name, &str);
128 } else { 90 } else {
129 // Don't recurse into duplicates. 91 DefaultHandler(name, value);
130 std::set<const Target*> seen_targets; 92 }
131 RecursivePrintDeps(target, toolchain_label, &seen_targets, 1); 93 }
132 } 94 }
133 return; 95
134 } 96 void PublicHandler(const std::string& name, const base::Value* value) {
135 97 std::string p;
136 // Collect the deps to display. 98 if (value->GetAsString(&p)) {
137 if (cmdline->HasSwitch("all")) { 99 if (p == "*") {
138 // Show all dependencies. 100 base::StringValue str("[All headers listed in the sources are public.]");
139 if (display_header) 101 DefaultHandler(name, &str);
140 OutputString("\nAll recursive dependencies\n"); 102 return;
141 103 }
142 std::set<const Target*> all_deps; 104 }
143 RecursiveCollectChildDeps(target, &all_deps); 105 DefaultHandler(name, value);
144 FilterAndPrintTargetSet(display_header, all_deps); 106 }
107
108 void ConfigsHandler(const std::string& name, const base::Value* value) {
109 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
110 if (tree)
111 DefaultHandler(name + " tree (in order applying)", value);
112 else
113 DefaultHandler(name + " (in order applying, try also --tree)", value);
114 }
115
116 void DepsHandler(const std::string& name, const base::Value* value) {
117 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
118 bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
119 if (tree) {
120 DefaultHandler("Dependency tree", value);
145 } else { 121 } else {
146 std::vector<const Target*> deps; 122 if (!all) {
147 // Show direct dependencies only. 123 DefaultHandler(
148 if (display_header) { 124 "Direct dependencies "
149 OutputString( 125 "(try also \"--all\", \"--tree\", or even \"--all --tree\")",
150 "\nDirect dependencies " 126 value);
151 "(try also \"--all\", \"--tree\", or even \"--all --tree\")\n"); 127 } else {
152 } 128 DefaultHandler("All recursive dependencies", value);
153 for (const auto& pair : target->GetDeps(Target::DEPS_ALL)) 129 }
154 deps.push_back(pair.ptr); 130 }
155 std::sort(deps.begin(), deps.end()); 131 }
156 FilterAndPrintTargets(display_header, &deps); 132
157 } 133 // Outputs need special processing when output patterns are present.
158 } 134 void ProcessOutputs(base::DictionaryValue* target) {
159 135 base::ListValue* patterns = nullptr;
160 // libs and lib_dirs are special in that they're inherited. We don't currently 136 base::ListValue* outputs = nullptr;
161 // implement a blame feature for this since the bottom-up inheritance makes 137 target->GetList("output_patterns", &patterns);
162 // this difficult. 138 target->GetList(variables::kOutputs, &outputs);
163 void PrintLibDirs(const Target* target, bool display_header) { 139
164 const OrderedSet<SourceDir>& lib_dirs = target->all_lib_dirs(); 140 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"); 141 OutputString("\noutputs\n");
330 142 int indent = 1;
331 if (target->output_type() == Target::ACTION) { 143 if (patterns) {
332 // Action, print out outputs, don't apply sources to it. 144 OutputString(" Output patterns\n");
333 for (const auto& elem : target->action_values().outputs().list()) { 145 indent = 2;
334 OutputString(" " + elem.AsString() + "\n"); 146 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 if (target->output_type() == Target::ACTION_FOREACH) {
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"); 147 OutputString("\n Resolved output file list\n");
352 } 148 }
353 149 if (outputs)
354 // Resolved output list. 150 PrintValue(outputs, indent);
355 std::vector<SourceFile> output_files; 151
356 SubstitutionWriter::ApplyListToSources(target->settings(), outputs, 152 target->Remove("output_patterns", nullptr);
357 target->sources(), &output_files); 153 target->Remove(variables::kOutputs, nullptr);
358 PrintFileList(output_files, std::string(), true, false); 154 }
359 } else {
360 DCHECK(target->IsBinary());
361 const Tool* tool = target->toolchain()->GetToolForTargetFinalOutput(target);
362
363 std::vector<OutputFile> output_files;
364 SubstitutionWriter::ApplyListToLinkerAsOutputFile(
365 target, tool, tool->outputs(), &output_files);
366
367 std::vector<SourceFile> output_files_as_source_file;
368 for (const OutputFile& output_file : output_files) {
369 output_files_as_source_file.push_back(
370 output_file.AsSourceFile(target->settings()->build_settings()));
371 }
372
373 PrintFileList(output_files_as_source_file, std::string(), true, false);
374 }
375 }
376
377 void PrintScript(const Target* target, bool display_header) {
378 if (display_header)
379 OutputString("\nscript\n");
380 OutputString(" " + target->action_values().script().value() + "\n");
381 }
382
383 void PrintArgs(const Target* target, bool display_header) {
384 if (display_header)
385 OutputString("\nargs\n");
386 for (const auto& elem : target->action_values().args().list()) {
387 OutputString(" " + elem.AsString() + "\n");
388 }
389 }
390
391 void PrintDepfile(const Target* target, bool display_header) {
392 if (target->action_values().depfile().empty())
393 return;
394 if (display_header)
395 OutputString("\ndepfile\n");
396 OutputString(" " + target->action_values().depfile().AsString() + "\n");
397 }
398
399 // Attribute the origin for attributing from where a target came from. Does
400 // nothing if the input is null or it does not have a location.
401 void OutputSourceOfDep(const ParseNode* origin, std::ostream& out) {
402 if (!origin)
403 return;
404 Location location = origin->GetRange().begin();
405 out << " (Added by " + location.file()->name().value() << ":"
406 << location.line_number() << ")\n";
407 }
408
409 // Templatized writer for writing out different config value types.
410 template<typename T> struct DescValueWriter {};
411 template<> struct DescValueWriter<std::string> {
412 void operator()(const std::string& str, std::ostream& out) const {
413 out << " " << str << "\n";
414 }
415 };
416
417 template<> struct DescValueWriter<SourceDir> {
418 void operator()(const SourceDir& dir, std::ostream& out) const {
419 out << " " << FormatSourceDir(dir) << "\n";
420 }
421 };
422
423 template<> struct DescValueWriter<LibFile> {
424 void operator()(const LibFile& lib, std::ostream& out) const {
425 if (lib.is_source_file())
426 out << " " << lib.source_file().value() << "\n";
427 else
428 out << " " << lib.value() << "\n";
429 }
430 };
431
432 // Writes a given config value type to the string, optionally with attribution.
433 // This should match RecursiveTargetConfigToStream in the order it traverses.
434 template<typename T> void OutputRecursiveTargetConfig(
435 const Target* target,
436 const char* header_name,
437 const std::vector<T>& (ConfigValues::* getter)() const) {
438 bool display_blame =
439 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
440
441 DescValueWriter<T> writer;
442 std::ostringstream out;
443
444 for (ConfigValuesIterator iter(target); !iter.done(); iter.Next()) {
445 if ((iter.cur().*getter)().empty())
446 continue;
447
448 // Optional blame sub-head.
449 if (display_blame) {
450 const Config* config = iter.GetCurrentConfig();
451 if (config) {
452 // Source of this value is a config.
453 out << " From " << config->label().GetUserVisibleName(false) << "\n";
454 OutputSourceOfDep(iter.origin(), out);
455 } else {
456 // Source of this value is the target itself.
457 out << " From " << target->label().GetUserVisibleName(false) << "\n";
458 }
459 }
460
461 // Actual values.
462 ConfigValuesToStream(iter.cur(), getter, writer, out);
463 }
464
465 std::string out_str = out.str();
466 if (!out_str.empty()) {
467 if (header_name)
468 OutputString("\n" + std::string(header_name) + "\n");
469 OutputString(out_str);
470 }
471 }
472
473 template<typename T> void OutputConfigValueArray(
474 const ConfigValues& values,
475 const char* header_name,
476 const std::vector<T>& (ConfigValues::* getter)() const) {
477 std::ostringstream out;
478
479 DescValueWriter<T> writer;
480 for (const T& cur : (values.*getter)())
481 writer(cur, out);
482
483 std::string out_str = out.str();
484 if (!out_str.empty()) {
485 if (header_name)
486 OutputString("\n" + std::string(header_name) + "\n");
487 OutputString(out_str);
488 }
489 }
490
491 void PrintRuntimeDeps(const Target* target) {
492 bool display_blame =
493 base::CommandLine::ForCurrentProcess()->HasSwitch(kBlame);
494 Label toolchain = target->label().GetToolchainLabel();
495
496 const Target* previous_from = NULL;
497 for (const auto& pair : ComputeRuntimeDeps(target)) {
498 if (display_blame) {
499 // Generally a target's runtime deps will be listed sequentially, so
500 // group them and don't duplicate the "from" label for two in a row.
501 if (previous_from == pair.second) {
502 OutputString(" "); // Just indent.
503 } else {
504 previous_from = pair.second;
505 OutputString("From ");
506 OutputString(pair.second->label().GetUserVisibleName(toolchain));
507 OutputString("\n "); // Make the file name indented.
508 }
509 }
510 OutputString(pair.first.value());
511 OutputString("\n");
512 }
513 }
514
515 // If "what" is empty, prints all PCH info. If "what" is nonempty, prints only
516 // the things that match (if any). Returns true if anything was printed.
517 bool PrintPrecompiledHeaderInfo(const ConfigValues& values,
518 const std::string& what,
519 bool display_headers) {
520 bool found_match = false;
521 if (what == variables::kPrecompiledHeader || what.empty()) {
522 if (!values.precompiled_header().empty()) {
523 if (display_headers)
524 OutputString("\nprecompiled_header\n");
525 OutputString(values.precompiled_header() + "\n");
526 }
527 found_match = true;
528 }
529 if (what == variables::kPrecompiledSource || what.empty()) {
530 if (!values.precompiled_source().is_null()) {
531 if (display_headers)
532 OutputString("\nprecompiled_source\n");
533 OutputString(values.precompiled_source().value() + "\n");
534 }
535 found_match = true;
536 }
537 return found_match;
538 } 155 }
539 156
540 bool PrintTarget(const Target* target, 157 bool PrintTarget(const Target* target,
541 const std::string& what, 158 const std::string& what,
542 bool display_target_header) { 159 bool single_target,
543 if (display_target_header) { 160 bool all,
544 OutputString("Target: ", DECORATION_YELLOW); 161 bool tree,
545 OutputString(target->label().GetUserVisibleName(false) + "\n"); 162 bool blame) {
546 OutputString("Type: ", DECORATION_YELLOW); 163 std::unique_ptr<base::DictionaryValue> dict =
547 OutputString(std::string( 164 DescBuilder::DescriptionForTarget(target, what, all, tree, blame);
548 Target::GetStringForOutputType(target->output_type())) + "\n"); 165 if (!what.empty() && dict->empty()) {
549 OutputString("Toolchain: ", DECORATION_YELLOW);
550 OutputString(
551 target->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
552 }
553
554 // Display headers when outputting everything.
555 bool display_headers = what.empty();
556 bool is_binary_output = target->IsBinary();
557
558 bool found_match = false;
559
560 // General target meta variables.
561 if (what.empty() || what == variables::kVisibility) {
562 PrintVisibility(target, display_headers);
563 found_match = true;
564 }
565 if (what.empty() || what == variables::kTestonly) {
566 PrintTestonly(target, display_headers);
567 found_match = true;
568 }
569
570 // Binary target meta variables.
571 if (is_binary_output) {
572 if (what.empty() || what == variables::kCheckIncludes) {
573 PrintCheckIncludes(target, display_headers);
574 found_match = true;
575 }
576 if (what.empty() || what == variables::kAllowCircularIncludesFrom) {
577 PrintAllowCircularIncludesFrom(target, display_headers);
578 found_match = true;
579 }
580 }
581
582 // Sources and inputs.
583 if (what.empty() || what == variables::kSources) {
584 PrintSources(target, display_headers);
585 found_match = true;
586 }
587 if (what.empty() || what == variables::kPublic) {
588 PrintPublic(target, display_headers);
589 found_match = true;
590 }
591 if (what.empty() || what == variables::kInputs) {
592 PrintInputs(target, display_headers);
593 found_match = true;
594 }
595
596 // Configs. Configs set directly on a target are only relevant for binary
597 // targets
598 if (is_binary_output && (what.empty() || what == variables::kConfigs)) {
599 PrintConfigs(target, display_headers);
600 found_match = true;
601 }
602
603 // Dependent/public configs can be applied to anything.
604 if (what.empty() || what == variables::kPublicConfigs) {
605 PrintPublicConfigs(target, display_headers);
606 found_match = true;
607 }
608 if (what.empty() || what == variables::kAllDependentConfigs) {
609 PrintAllDependentConfigs(target, display_headers);
610 found_match = true;
611 }
612
613 // Action values.
614 if (target->output_type() == Target::ACTION ||
615 target->output_type() == Target::ACTION_FOREACH) {
616 if (what.empty() || what == variables::kScript) {
617 PrintScript(target, display_headers);
618 found_match = true;
619 }
620 if (what.empty() || what == variables::kArgs) {
621 PrintArgs(target, display_headers);
622 found_match = true;
623 }
624 if (what.empty() || what == variables::kDepfile) {
625 PrintDepfile(target, display_headers);
626 found_match = true;
627 }
628 }
629
630 // Outputs.
631 if (target->output_type() != Target::SOURCE_SET &&
632 target->output_type() != Target::GROUP) {
633 if (what.empty() || what == variables::kOutputs) {
634 PrintOutputs(target, display_headers);
635 found_match = true;
636 }
637 }
638
639 // Values from configs only apply to binary targets.
640 if (is_binary_output) {
641 #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
642 if (what.empty() || what == #name) { \
643 OutputRecursiveTargetConfig<type>( \
644 target, display_headers ? #name : nullptr, &ConfigValues::name); \
645 found_match = true; \
646 }
647
648 CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
649 CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
650 CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
651 CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
652 CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
653 CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
654 CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
655 CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
656 CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
657 CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
658 // Libs and lib_dirs are handled specially below.
659
660 #undef CONFIG_VALUE_ARRAY_HANDLER
661
662 found_match |= PrintPrecompiledHeaderInfo(target->config_values(),
663 what, display_headers);
664 }
665
666 // Deps
667 if (what.empty() || what == "deps") {
668 PrintDeps(target, display_headers);
669 found_match = true;
670 }
671
672 // Runtime deps are special, print only when explicitly asked for and not in
673 // overview mode.
674 if (what == "runtime_deps") {
675 PrintRuntimeDeps(target);
676 found_match = true;
677 }
678
679 // Libs can be part of any target and get recursively pushed up the chain,
680 // so display them regardless of target type.
681 if (what.empty() || what == variables::kLibs) {
682 PrintLibs(target, display_headers);
683 found_match = true;
684 }
685 if (what.empty() || what == variables::kLibDirs) {
686 PrintLibDirs(target, display_headers);
687 found_match = true;
688 }
689
690 if (!found_match) {
691 OutputString("Don't know how to display \"" + what + "\" for \"" + 166 OutputString("Don't know how to display \"" + what + "\" for \"" +
692 Target::GetStringForOutputType(target->output_type()) + "\".\n"); 167 Target::GetStringForOutputType(target->output_type()) +
168 "\".\n");
693 return false; 169 return false;
694 } 170 }
171 // Print single value, without any headers
172 if (!what.empty() && dict->size() == 1 && single_target) {
173 base::DictionaryValue::Iterator iter(*dict);
174 PrintValue(&iter.value(), 0);
175 return true;
176 }
177
178 OutputString("Target ", DECORATION_YELLOW);
179 OutputString(target->label().GetUserVisibleName(false));
180 OutputString("\n");
181
182 std::unique_ptr<base::Value> v;
183 #define HANDLER(property, handler_name) \
184 if (dict->Remove(property, &v)) { \
185 handler_name(property, v.get()); \
186 }
187
188 // Entries with DefaultHandler are present to enforce order
189 HANDLER("type", LabelHandler);
190 HANDLER("toolchain", LabelHandler);
191 HANDLER(variables::kVisibility, VisibilityHandler);
192 HANDLER(variables::kTestonly, DefaultHandler);
193 HANDLER(variables::kCheckIncludes, DefaultHandler);
194 HANDLER(variables::kAllowCircularIncludesFrom, DefaultHandler);
195 HANDLER(variables::kSources, DefaultHandler);
196 HANDLER(variables::kPublic, PublicHandler);
197 HANDLER(variables::kInputs, DefaultHandler);
198 HANDLER(variables::kConfigs, ConfigsHandler);
199 HANDLER(variables::kPublicConfigs, ConfigsHandler);
200 HANDLER(variables::kAllDependentConfigs, ConfigsHandler);
201 HANDLER(variables::kScript, DefaultHandler);
202 HANDLER(variables::kArgs, DefaultHandler);
203 HANDLER(variables::kDepfile, DefaultHandler);
204 ProcessOutputs(dict.get());
205 HANDLER("bundle_data", DefaultHandler);
206 HANDLER(variables::kArflags, DefaultHandler);
207 HANDLER(variables::kAsmflags, DefaultHandler);
208 HANDLER(variables::kCflags, DefaultHandler);
209 HANDLER(variables::kCflagsC, DefaultHandler);
210 HANDLER(variables::kCflagsCC, DefaultHandler);
211 HANDLER(variables::kCflagsObjC, DefaultHandler);
212 HANDLER(variables::kCflagsObjCC, DefaultHandler);
213 HANDLER(variables::kDefines, DefaultHandler);
214 HANDLER(variables::kIncludeDirs, DefaultHandler);
215 HANDLER(variables::kLdflags, DefaultHandler);
216 HANDLER(variables::kPrecompiledHeader, DefaultHandler);
217 HANDLER(variables::kPrecompiledSource, DefaultHandler);
218 HANDLER(variables::kDeps, DepsHandler);
219 HANDLER(variables::kLibs, DefaultHandler);
220 HANDLER(variables::kLibDirs, DefaultHandler);
221
222 #undef HANDLER
223
224 // Process the rest (if any)
225 base::DictionaryValue::Iterator iter(*dict);
226 while (!iter.IsAtEnd()) {
227 DefaultHandler(iter.key(), &iter.value());
228 iter.Advance();
229 }
230
695 return true; 231 return true;
696 } 232 }
697 233
698 bool PrintConfig(const Config* config, 234 bool PrintConfig(const Config* config,
699 const std::string& what, 235 const std::string& what,
700 bool display_config_header) { 236 bool single_config) {
701 const ConfigValues& values = config->resolved_values(); 237 std::unique_ptr<base::DictionaryValue> dict =
702 238 DescBuilder::DescriptionForConfig(config, what);
703 if (display_config_header) { 239 if (!what.empty() && dict->empty()) {
704 OutputString("Config: ", DECORATION_YELLOW);
705 OutputString(config->label().GetUserVisibleName(false) + "\n");
706 OutputString("Toolchain: ", DECORATION_YELLOW);
707 OutputString(
708 config->label().GetToolchainLabel().GetUserVisibleName(false) + "\n");
709 if (what.empty() && !config->configs().empty()) {
710 OutputString(
711 "(This is a composite config, the values below are after the\n"
712 "expansion of the child configs.)\n");
713 }
714 }
715
716 // Display headers when outputting everything.
717 bool display_headers = what.empty();
718
719 if (what.empty() || what == variables::kConfigs)
720 PrintConfigs(config, display_headers);
721
722 #define CONFIG_VALUE_ARRAY_HANDLER(name, type) \
723 if (what.empty() || what == #name) { \
724 OutputConfigValueArray<type>(values, display_headers ? #name : nullptr, \
725 &ConfigValues::name); \
726 found_match = true; \
727 }
728
729 bool found_match = false;
730
731 CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
732 CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
733 CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
734 CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
735 CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
736 CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
737 CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
738 CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
739 CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
740 CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
741 CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
742 CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
743
744 #undef CONFIG_VALUE_ARRAY_HANDLER
745
746 // Handles all PCH-related variables.
747 found_match |= PrintPrecompiledHeaderInfo(config->resolved_values(),
748 what, display_headers);
749
750 if (!found_match) {
751 OutputString("Don't know how to display \"" + what + "\" for a config.\n"); 240 OutputString("Don't know how to display \"" + what + "\" for a config.\n");
752 return false; 241 return false;
753 } 242 }
243 // Print single value, without any headers
244 if (!what.empty() && dict->size() == 1 && single_config) {
245 base::DictionaryValue::Iterator iter(*dict);
246 PrintValue(&iter.value(), 0);
247 return true;
248 }
249
250 OutputString("Config: ", DECORATION_YELLOW);
251 OutputString(config->label().GetUserVisibleName(false));
252 OutputString("\n");
253
254 std::unique_ptr<base::Value> v;
255 #define HANDLER(property, handler_name) \
256 if (dict->Remove(property, &v)) { \
257 handler_name(property, v.get()); \
258 }
259
260 HANDLER("toolchain", LabelHandler);
261 if (!config->configs().empty()) {
262 OutputString(
263 "(This is a composite config, the values below are after the\n"
264 "expansion of the child configs.)\n");
265 }
266 HANDLER(variables::kArflags, DefaultHandler);
267 HANDLER(variables::kAsmflags, DefaultHandler);
268 HANDLER(variables::kCflags, DefaultHandler);
269 HANDLER(variables::kCflagsC, DefaultHandler);
270 HANDLER(variables::kCflagsCC, DefaultHandler);
271 HANDLER(variables::kCflagsObjC, DefaultHandler);
272 HANDLER(variables::kCflagsObjCC, DefaultHandler);
273 HANDLER(variables::kDefines, DefaultHandler);
274 HANDLER(variables::kIncludeDirs, DefaultHandler);
275 HANDLER(variables::kLdflags, DefaultHandler);
276 HANDLER(variables::kLibs, DefaultHandler);
277 HANDLER(variables::kLibDirs, DefaultHandler);
278 HANDLER(variables::kPrecompiledHeader, DefaultHandler);
279 HANDLER(variables::kPrecompiledSource, DefaultHandler);
280
281 #undef HANDLER
282
754 return true; 283 return true;
755 } 284 }
756 285
757 } // namespace 286 } // namespace
758 287
759 // desc ------------------------------------------------------------------------ 288 // desc ------------------------------------------------------------------------
760 289
761 const char kDesc[] = "desc"; 290 const char kDesc[] = "desc";
762 const char kDesc_HelpShort[] = 291 const char kDesc_HelpShort[] =
763 "desc: Show lots of insightful information about a target or config."; 292 "desc: Show lots of insightful information about a target or config.";
764 const char kDesc_Help[] = 293 const char kDesc_Help[] =
765 "gn desc <out_dir> <label or pattern> [<what to show>] [--blame]\n" 294 "gn desc <out_dir> <label or pattern> [<what to show>] [--blame] "
295 "[--format=json]\n"
766 "\n" 296 "\n"
767 " Displays information about a given target or config. The build\n" 297 " Displays information about a given target or config. The build\n"
768 " build parameters will be taken for the build in the given <out_dir>.\n" 298 " build parameters will be taken for the build in the given <out_dir>.\n"
769 "\n" 299 "\n"
770 " The <label or pattern> can be a target label, a config label, or a\n" 300 " The <label or pattern> can be a target label, a config label, or a\n"
771 " label pattern (see \"gn help label_pattern\"). A label pattern will\n" 301 " label pattern (see \"gn help label_pattern\"). A label pattern will\n"
772 " only match targets.\n" 302 " only match targets.\n"
773 "\n" 303 "\n"
774 "Possibilities for <what to show>\n" 304 "Possibilities for <what to show>\n"
775 "\n" 305 "\n"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 "\n" 337 "\n"
808 " The output is a list of file names relative to the build\n" 338 " The output is a list of file names relative to the build\n"
809 " directory. See \"gn help runtime_deps\" for how this is computed.\n" 339 " directory. See \"gn help runtime_deps\" for how this is computed.\n"
810 " This also works with \"--blame\" to see the source of the\n" 340 " This also works with \"--blame\" to see the source of the\n"
811 " dependency.\n" 341 " dependency.\n"
812 "\n" 342 "\n"
813 "Shared flags\n" 343 "Shared flags\n"
814 "\n" 344 "\n"
815 ALL_TOOLCHAINS_SWITCH_HELP 345 ALL_TOOLCHAINS_SWITCH_HELP
816 "\n" 346 "\n"
347 " --format=json\n"
348 " Format the output as JSON instead of text.\n"
349 "\n"
817 "Target flags\n" 350 "Target flags\n"
818 "\n" 351 "\n"
819 " --blame\n" 352 " --blame\n"
820 " Used with any value specified on a config, this will name\n" 353 " Used with any value specified on a config, this will name\n"
821 " the config that cause that target to get the flag. This doesn't\n" 354 " the config that cause that target to get the flag. This doesn't\n"
822 " currently work for libs and lib_dirs because those are inherited\n" 355 " currently work for libs and lib_dirs because those are inherited\n"
823 " and are more complicated to figure out the blame (patches\n" 356 " and are more complicated to figure out the blame (patches\n"
824 " welcome).\n" 357 " welcome).\n"
825 "\n" 358 "\n"
826 "Configs\n" 359 "Configs\n"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 448
916 if (!ResolveFromCommandLineInput( 449 if (!ResolveFromCommandLineInput(
917 setup, target_list, cmdline->HasSwitch(switches::kAllToolchains), 450 setup, target_list, cmdline->HasSwitch(switches::kAllToolchains),
918 &target_matches, &config_matches, &toolchain_matches, &file_matches)) 451 &target_matches, &config_matches, &toolchain_matches, &file_matches))
919 return 1; 452 return 1;
920 453
921 std::string what_to_print; 454 std::string what_to_print;
922 if (args.size() == 3) 455 if (args.size() == 3)
923 what_to_print = args[2]; 456 what_to_print = args[2];
924 457
925 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1; 458 bool json = cmdline->GetSwitchValueASCII("format") == "json";
926 459
927 // Display headers for each target when printing all values, or when printing 460 if (json) {
928 // multiple targets or configs. 461 // Convert all targets/configs to JSON, serialize and print them
929 bool display_item_header = multiple_outputs || what_to_print.empty(); 462 auto res = base::WrapUnique(new base::DictionaryValue());
463 if (!target_matches.empty()) {
464 for (const auto* target : target_matches) {
465 res->Set(target->label().GetUserVisibleName(
466 target->settings()->default_toolchain_label()),
467 DescBuilder::DescriptionForTarget(
468 target, what_to_print, cmdline->HasSwitch(kAll),
469 cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
470 }
471 } else if (!config_matches.empty()) {
472 for (const auto* config : config_matches) {
473 res->Set(config->label().GetUserVisibleName(false),
474 DescBuilder::DescriptionForConfig(config, what_to_print));
475 }
476 }
477 std::string s;
478 base::JSONWriter::WriteWithOptions(
479 *res.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
480 OutputString(s);
481 } else {
482 // Regular (non-json) formatted output
483 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
930 484
931 bool printed_output = false; 485 bool printed_output = false;
932 for (const Target* target : target_matches) { 486 for (const Target* target : target_matches) {
933 if (printed_output) 487 if (printed_output)
934 OutputString("\n\n"); 488 OutputString("\n\n");
935 printed_output = true; 489 printed_output = true;
936 490
937 if (!PrintTarget(target, what_to_print, display_item_header)) 491 if (!PrintTarget(target, what_to_print, !multiple_outputs,
938 return 1; 492 cmdline->HasSwitch(kAll), cmdline->HasSwitch(kTree),
939 } 493 cmdline->HasSwitch(kBlame)))
940 for (const Config* config : config_matches) { 494 return 1;
941 if (printed_output) 495 }
942 OutputString("\n\n"); 496 for (const Config* config : config_matches) {
943 printed_output = true; 497 if (printed_output)
498 OutputString("\n\n");
499 printed_output = true;
944 500
945 if (!PrintConfig(config, what_to_print, display_item_header)) 501 if (!PrintConfig(config, what_to_print, !multiple_outputs))
946 return 1; 502 return 1;
503 }
947 } 504 }
948 505
949 return 0; 506 return 0;
950 } 507 }
951 508
952 } // namespace commands 509 } // namespace commands
OLDNEW
« no previous file with comments | « tools/gn/BUILD.gn ('k') | tools/gn/command_gen.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698