1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6
7 #include <algorithm>
8 #include <memory>
9 #include <set>
10 #include <sstream>
11
12 #include "base/command_line.h"
13 #include "base/json/json_writer.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "gn/commands.h"
17 #include "gn/config.h"
18 #include "gn/desc_builder.h"
19 #include "gn/setup.h"
20 #include "gn/standard_out.h"
21 #include "gn/switches.h"
22 #include "gn/target.h"
23 #include "gn/variables.h"
24
25 namespace commands {
26
27 namespace {
28
29 // Desc-specific command line switches.
30 const char kBlame[] = "blame";
31 const char kTree[] = "tree";
32 const char kAll[] = "all";
33
PrintDictValue(const base::Value * value,int indentLevel,bool use_first_indent)34 void PrintDictValue(const base::Value* value,
35 int indentLevel,
36 bool use_first_indent) {
37 std::string indent(indentLevel * 2, ' ');
38 const base::ListValue* list_value = nullptr;
39 const base::DictionaryValue* dict_value = nullptr;
40 std::string string_value;
41 bool bool_value = false;
42 int int_value = 0;
43 if (use_first_indent)
44 OutputString(indent);
45 if (value->GetAsList(&list_value)) {
46 OutputString("[\n");
47 bool first = true;
48 for (const auto& v : *list_value) {
49 if (!first)
50 OutputString(",\n");
51 PrintDictValue(&v, indentLevel + 1, true);
52 first = false;
53 }
54 OutputString("\n" + indent + "]");
55 } else if (value->GetAsString(&string_value)) {
56 OutputString("\"" + string_value + "\"");
57 } else if (value->GetAsBoolean(&bool_value)) {
58 OutputString(bool_value ? "true" : "false");
59 } else if (value->GetAsDictionary(&dict_value)) {
60 OutputString("{\n");
61 std::string indent_plus_one((indentLevel + 1) * 2, ' ');
62 base::DictionaryValue::Iterator iter(*dict_value);
63 bool first = true;
64 while (!iter.IsAtEnd()) {
65 if (!first)
66 OutputString(",\n");
67 OutputString(indent_plus_one + iter.key() + " = ");
68 PrintDictValue(&iter.value(), indentLevel + 1, false);
69 iter.Advance();
70 first = false;
71 }
72 OutputString("\n" + indent + "}");
73 } else if (value->GetAsInteger(&int_value)) {
74 OutputString(base::IntToString(int_value));
75 } else if (value->is_none()) {
76 OutputString("<null>");
77 }
78 }
79
80 // Prints value with specified indentation level
PrintValue(const base::Value * value,int indentLevel)81 void PrintValue(const base::Value* value, int indentLevel) {
82 std::string indent(indentLevel * 2, ' ');
83 const base::ListValue* list_value = nullptr;
84 const base::DictionaryValue* dict_value = nullptr;
85 std::string string_value;
86 bool bool_value = false;
87 int int_value = 0;
88 if (value->GetAsList(&list_value)) {
89 for (const auto& v : *list_value) {
90 PrintValue(&v, indentLevel);
91 }
92 } else if (value->GetAsString(&string_value)) {
93 OutputString(indent);
94 OutputString(string_value);
95 OutputString("\n");
96 } else if (value->GetAsBoolean(&bool_value)) {
97 OutputString(indent);
98 OutputString(bool_value ? "true" : "false");
99 OutputString("\n");
100 } else if (value->GetAsDictionary(&dict_value)) {
101 base::DictionaryValue::Iterator iter(*dict_value);
102 while (!iter.IsAtEnd()) {
103 OutputString(indent + iter.key() + "\n");
104 PrintValue(&iter.value(), indentLevel + 1);
105 iter.Advance();
106 }
107 } else if (value->GetAsInteger(&int_value)) {
108 OutputString(indent);
109 OutputString(base::IntToString(int_value));
110 OutputString("\n");
111 } else if (value->is_none()) {
112 OutputString(indent + "<null>\n");
113 }
114 }
115
116 // Default handler for property
DefaultHandler(const std::string & name,const base::Value * value,bool value_only)117 void DefaultHandler(const std::string& name,
118 const base::Value* value,
119 bool value_only) {
120 if (value_only) {
121 PrintValue(value, 0);
122 return;
123 }
124 OutputString("\n");
125 OutputString(name);
126 OutputString("\n");
127 PrintValue(value, 1);
128 }
129
130 // Specific handler for properties that need different treatment
131
132 // Prints the dict in GN scope-sytle.
MetadataHandler(const std::string & name,const base::Value * value,bool value_only)133 void MetadataHandler(const std::string& name,
134 const base::Value* value,
135 bool value_only) {
136 if (value_only) {
137 PrintDictValue(value, 0, true);
138 OutputString("\n");
139 return;
140 }
141 OutputString("\n");
142 OutputString(name);
143 OutputString("\n");
144 PrintDictValue(value, 1, true);
145 OutputString("\n");
146 }
147
148 // Prints label and property value on one line, capitalizing the label.
LabelHandler(const std::string & name,const base::Value * value,bool value_only)149 void LabelHandler(const std::string& name,
150 const base::Value* value,
151 bool value_only) {
152 if (value_only) {
153 PrintValue(value, 0);
154 return;
155 }
156 std::string label = name;
157 label[0] = base::ToUpperASCII(label[0]);
158 std::string string_value;
159 if (value->GetAsString(&string_value)) {
160 OutputString(name + ": ", DECORATION_YELLOW);
161 OutputString(string_value + "\n");
162 }
163 }
164
VisibilityHandler(const std::string & name,const base::Value * value,bool value_only)165 void VisibilityHandler(const std::string& name,
166 const base::Value* value,
167 bool value_only) {
168 if (value_only) {
169 PrintValue(value, 0);
170 return;
171 }
172 const base::ListValue* list;
173 if (value->GetAsList(&list)) {
174 if (list->empty()) {
175 base::Value str("(no visibility)");
176 DefaultHandler(name, &str, value_only);
177 } else {
178 DefaultHandler(name, value, value_only);
179 }
180 }
181 }
182
PublicHandler(const std::string & name,const base::Value * value,bool value_only)183 void PublicHandler(const std::string& name,
184 const base::Value* value,
185 bool value_only) {
186 if (value_only) {
187 PrintValue(value, 0);
188 return;
189 }
190 std::string p;
191 if (value->GetAsString(&p)) {
192 if (p == "*") {
193 base::Value str("[All headers listed in the sources are public.]");
194 DefaultHandler(name, &str, value_only);
195 return;
196 }
197 }
198 DefaultHandler(name, value, value_only);
199 }
200
ConfigsHandler(const std::string & name,const base::Value * value,bool value_only)201 void ConfigsHandler(const std::string& name,
202 const base::Value* value,
203 bool value_only) {
204 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
205 if (tree)
206 DefaultHandler(name + " tree (in order applying)", value, value_only);
207 else
208 DefaultHandler(name + " (in order applying, try also --tree)", value,
209 value_only);
210 }
211
DepsHandler(const std::string & name,const base::Value * value,bool value_only)212 void DepsHandler(const std::string& name,
213 const base::Value* value,
214 bool value_only) {
215 bool tree = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
216 bool all = base::CommandLine::ForCurrentProcess()->HasSwitch(kTree);
217 if (tree) {
218 DefaultHandler("Dependency tree", value, value_only);
219 } else {
220 if (!all) {
221 DefaultHandler(
222 "Direct dependencies "
223 "(try also \"--all\", \"--tree\", or even \"--all --tree\")",
224 value, value_only);
225 } else {
226 DefaultHandler("All recursive dependencies", value, value_only);
227 }
228 }
229 }
230
231 // Outputs need special processing when output patterns are present.
ProcessOutputs(base::DictionaryValue * target,bool files_only)232 void ProcessOutputs(base::DictionaryValue* target, bool files_only) {
233 base::ListValue* patterns = nullptr;
234 base::ListValue* outputs = nullptr;
235 target->GetList("output_patterns", &patterns);
236 target->GetList(variables::kOutputs, &outputs);
237
238 int indent = 0;
239 if (outputs || patterns) {
240 if (!files_only) {
241 OutputString("\noutputs\n");
242 indent = 1;
243 }
244 if (patterns) {
245 if (!files_only) {
246 OutputString(" Output patterns\n");
247 indent = 2;
248 }
249 PrintValue(patterns, indent);
250 if (!files_only)
251 OutputString("\n Resolved output file list\n");
252 }
253 if (outputs)
254 PrintValue(outputs, indent);
255
256 target->Remove("output_patterns", nullptr);
257 target->Remove(variables::kOutputs, nullptr);
258 }
259 }
260
261 using DescHandlerFunc = void (*)(const std::string& name,
262 const base::Value* value,
263 bool value_only);
GetHandlers()264 std::map<std::string, DescHandlerFunc> GetHandlers() {
265 return {{"type", LabelHandler},
266 {"toolchain", LabelHandler},
267 {variables::kVisibility, VisibilityHandler},
268 {variables::kMetadata, MetadataHandler},
269 {variables::kTestonly, DefaultHandler},
270 {variables::kCheckIncludes, DefaultHandler},
271 {variables::kAllowCircularIncludesFrom, DefaultHandler},
272 {variables::kSources, DefaultHandler},
273 {variables::kPublic, PublicHandler},
274 {variables::kInputs, DefaultHandler},
275 {variables::kConfigs, ConfigsHandler},
276 {variables::kPublicConfigs, ConfigsHandler},
277 {variables::kAllDependentConfigs, ConfigsHandler},
278 {variables::kScript, DefaultHandler},
279 {variables::kArgs, DefaultHandler},
280 {variables::kDepfile, DefaultHandler},
281 {"bundle_data", DefaultHandler},
282 {variables::kArflags, DefaultHandler},
283 {variables::kAsmflags, DefaultHandler},
284 {variables::kCflags, DefaultHandler},
285 {variables::kCflagsC, DefaultHandler},
286 {variables::kCflagsCC, DefaultHandler},
287 {variables::kCflagsObjC, DefaultHandler},
288 {variables::kCflagsObjCC, DefaultHandler},
289 {variables::kDefines, DefaultHandler},
290 {variables::kFrameworkDirs, DefaultHandler},
291 {variables::kFrameworks, DefaultHandler},
292 {variables::kIncludeDirs, DefaultHandler},
293 {variables::kLdflags, DefaultHandler},
294 {variables::kPrecompiledHeader, DefaultHandler},
295 {variables::kPrecompiledSource, DefaultHandler},
296 {variables::kDeps, DepsHandler},
297 {variables::kLibs, DefaultHandler},
298 {variables::kLibDirs, DefaultHandler},
299 {variables::kDataKeys, DefaultHandler},
300 {variables::kRebase, DefaultHandler},
301 {variables::kWalkKeys, DefaultHandler},
302 {variables::kWriteOutputConversion, DefaultHandler},
303 {"runtime_deps", DefaultHandler}};
304 }
305
HandleProperty(const std::string & what,const std::map<std::string,DescHandlerFunc> & handler_map,std::unique_ptr<base::Value> & v,std::unique_ptr<base::DictionaryValue> & dict)306 void HandleProperty(const std::string& what,
307 const std::map<std::string, DescHandlerFunc>& handler_map,
308 std::unique_ptr<base::Value>& v,
309 std::unique_ptr<base::DictionaryValue>& dict) {
310 if (dict->Remove(what, &v)) {
311 auto pair = handler_map.find(what);
312 if (pair != handler_map.end())
313 pair->second(what, v.get(), false);
314 }
315 }
316
PrintTarget(const Target * target,const std::string & what,bool single_target,const std::map<std::string,DescHandlerFunc> & handler_map,bool all,bool tree,bool blame)317 bool PrintTarget(const Target* target,
318 const std::string& what,
319 bool single_target,
320 const std::map<std::string, DescHandlerFunc>& handler_map,
321 bool all,
322 bool tree,
323 bool blame) {
324 std::unique_ptr<base::DictionaryValue> dict =
325 DescBuilder::DescriptionForTarget(target, what, all, tree, blame);
326 if (!what.empty() && dict->empty()) {
327 OutputString("Don't know how to display \"" + what + "\" for \"" +
328 Target::GetStringForOutputType(target->output_type()) +
329 "\".\n");
330 return false;
331 }
332 // Print single value
333 if (!what.empty() && dict->size() == 1 && single_target) {
334 if (what == variables::kOutputs) {
335 ProcessOutputs(dict.get(), true);
336 return true;
337 }
338 base::DictionaryValue::Iterator iter(*dict);
339 auto pair = handler_map.find(what);
340 if (pair != handler_map.end())
341 pair->second(what, &iter.value(), true);
342 return true;
343 }
344
345 OutputString("Target ", DECORATION_YELLOW);
346 OutputString(target->label().GetUserVisibleName(false));
347 OutputString("\n");
348
349 std::unique_ptr<base::Value> v;
350 // Entries with DefaultHandler are present to enforce order
351 HandleProperty("type", handler_map, v, dict);
352 HandleProperty("toolchain", handler_map, v, dict);
353 HandleProperty(variables::kVisibility, handler_map, v, dict);
354 HandleProperty(variables::kMetadata, handler_map, v, dict);
355 HandleProperty(variables::kTestonly, handler_map, v, dict);
356 HandleProperty(variables::kCheckIncludes, handler_map, v, dict);
357 HandleProperty(variables::kAllowCircularIncludesFrom, handler_map, v, dict);
358 HandleProperty(variables::kSources, handler_map, v, dict);
359 HandleProperty(variables::kPublic, handler_map, v, dict);
360 HandleProperty(variables::kInputs, handler_map, v, dict);
361 HandleProperty(variables::kConfigs, handler_map, v, dict);
362 HandleProperty(variables::kPublicConfigs, handler_map, v, dict);
363 HandleProperty(variables::kAllDependentConfigs, handler_map, v, dict);
364 HandleProperty(variables::kScript, handler_map, v, dict);
365 HandleProperty(variables::kArgs, handler_map, v, dict);
366 HandleProperty(variables::kDepfile, handler_map, v, dict);
367 ProcessOutputs(dict.get(), false);
368 HandleProperty("bundle_data", handler_map, v, dict);
369 HandleProperty(variables::kArflags, handler_map, v, dict);
370 HandleProperty(variables::kAsmflags, handler_map, v, dict);
371 HandleProperty(variables::kCflags, handler_map, v, dict);
372 HandleProperty(variables::kCflagsC, handler_map, v, dict);
373 HandleProperty(variables::kCflagsCC, handler_map, v, dict);
374 HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
375 HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
376 HandleProperty(variables::kDefines, handler_map, v, dict);
377 HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
378 HandleProperty(variables::kFrameworks, handler_map, v, dict);
379 HandleProperty(variables::kIncludeDirs, handler_map, v, dict);
380 HandleProperty(variables::kLdflags, handler_map, v, dict);
381 HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict);
382 HandleProperty(variables::kPrecompiledSource, handler_map, v, dict);
383 HandleProperty(variables::kDeps, handler_map, v, dict);
384 HandleProperty(variables::kLibs, handler_map, v, dict);
385 HandleProperty(variables::kLibDirs, handler_map, v, dict);
386 HandleProperty(variables::kDataKeys, handler_map, v, dict);
387 HandleProperty(variables::kRebase, handler_map, v, dict);
388 HandleProperty(variables::kWalkKeys, handler_map, v, dict);
389 HandleProperty(variables::kWriteOutputConversion, handler_map, v, dict);
390
391 #undef HandleProperty
392
393 // Process the rest (if any)
394 base::DictionaryValue::Iterator iter(*dict);
395 while (!iter.IsAtEnd()) {
396 DefaultHandler(iter.key(), &iter.value(), false);
397 iter.Advance();
398 }
399
400 return true;
401 }
402
PrintConfig(const Config * config,const std::string & what,bool single_config,const std::map<std::string,DescHandlerFunc> & handler_map)403 bool PrintConfig(const Config* config,
404 const std::string& what,
405 bool single_config,
406 const std::map<std::string, DescHandlerFunc>& handler_map) {
407 std::unique_ptr<base::DictionaryValue> dict =
408 DescBuilder::DescriptionForConfig(config, what);
409 if (!what.empty() && dict->empty()) {
410 OutputString("Don't know how to display \"" + what + "\" for a config.\n");
411 return false;
412 }
413 // Print single value
414 if (!what.empty() && dict->size() == 1 && single_config) {
415 base::DictionaryValue::Iterator iter(*dict);
416 auto pair = handler_map.find(what);
417 if (pair != handler_map.end())
418 pair->second(what, &iter.value(), true);
419 return true;
420 }
421
422 OutputString("Config: ", DECORATION_YELLOW);
423 OutputString(config->label().GetUserVisibleName(false));
424 OutputString("\n");
425
426 std::unique_ptr<base::Value> v;
427 HandleProperty("toolchain", handler_map, v, dict);
428 if (!config->configs().empty()) {
429 OutputString(
430 "(This is a composite config, the values below are after the\n"
431 "expansion of the child configs.)\n");
432 }
433 HandleProperty(variables::kArflags, handler_map, v, dict);
434 HandleProperty(variables::kAsmflags, handler_map, v, dict);
435 HandleProperty(variables::kCflags, handler_map, v, dict);
436 HandleProperty(variables::kCflagsC, handler_map, v, dict);
437 HandleProperty(variables::kCflagsCC, handler_map, v, dict);
438 HandleProperty(variables::kCflagsObjC, handler_map, v, dict);
439 HandleProperty(variables::kCflagsObjCC, handler_map, v, dict);
440 HandleProperty(variables::kDefines, handler_map, v, dict);
441 HandleProperty(variables::kFrameworkDirs, handler_map, v, dict);
442 HandleProperty(variables::kFrameworks, handler_map, v, dict);
443 HandleProperty(variables::kIncludeDirs, handler_map, v, dict);
444 HandleProperty(variables::kInputs, handler_map, v, dict);
445 HandleProperty(variables::kLdflags, handler_map, v, dict);
446 HandleProperty(variables::kLibs, handler_map, v, dict);
447 HandleProperty(variables::kLibDirs, handler_map, v, dict);
448 HandleProperty(variables::kPrecompiledHeader, handler_map, v, dict);
449 HandleProperty(variables::kPrecompiledSource, handler_map, v, dict);
450
451 #undef HandleProperty
452
453 return true;
454 }
455
456 } // namespace
457
458 // desc ------------------------------------------------------------------------
459
460 const char kDesc[] = "desc";
461 const char kDesc_HelpShort[] =
462 "desc: Show lots of insightful information about a target or config.";
463 const char kDesc_Help[] =
464 R"(gn desc
465
466 gn desc <out_dir> <label or pattern> [<what to show>] [--blame]
467 [--format=json]
468
469 Displays information about a given target or config. The build parameters
470 will be taken for the build in the given <out_dir>.
471
472 The <label or pattern> can be a target label, a config label, or a label
473 pattern (see "gn help label_pattern"). A label pattern will only match
474 targets.
475
476 Possibilities for <what to show>
477
478 (If unspecified an overall summary will be displayed.)
479
480 all_dependent_configs
481 allow_circular_includes_from
482 arflags [--blame]
483 args
484 cflags [--blame]
485 cflags_c [--blame]
486 cflags_cc [--blame]
487 check_includes
488 configs [--tree] (see below)
489 data_keys
490 defines [--blame]
491 depfile
492 deps [--all] [--tree] (see below)
493 framework_dirs
494 frameworks
495 include_dirs [--blame]
496 inputs
497 ldflags [--blame]
498 lib_dirs
499 libs
500 metadata
501 output_conversion
502 outputs
503 public_configs
504 public
505 rebase
506 script
507 sources
508 testonly
509 visibility
510 walk_keys
511
512 runtime_deps
513 Compute all runtime deps for the given target. This is a computed list
514 and does not correspond to any GN variable, unlike most other values
515 here.
516
517 The output is a list of file names relative to the build directory. See
518 "gn help runtime_deps" for how this is computed. This also works with
519 "--blame" to see the source of the dependency.
520
521 Shared flags
522 )"
523
524 ALL_TOOLCHAINS_SWITCH_HELP
525
526 R"(
527 --format=json
528 Format the output as JSON instead of text.
529
530 Target flags
531
532 --blame
533 Used with any value specified on a config, this will name the config that
534 causes that target to get the flag. This doesn't currently work for libs,
535 lib_dirs, frameworks and framework_dirs because those are inherited and
536 are more complicated to figure out the blame (patches welcome).
537
538 Configs
539
540 The "configs" section will list all configs that apply. For targets this will
541 include configs specified in the "configs" variable of the target, and also
542 configs pushed onto this target via public or "all dependent" configs.
543
544 Configs can have child configs. Specifying --tree will show the hierarchy.
545
546 Printing outputs
547
548 The "outputs" section will list all outputs that apply, including the outputs
549 computed from the tool definition (eg for "executable", "static_library", ...
550 targets).
551
552 Printing deps
553
554 Deps will include all public, private, and data deps (TODO this could be
555 clarified and enhanced) sorted in order applying. The following may be used:
556
557 --all
558 Collects all recursive dependencies and prints a sorted flat list. Also
559 usable with --tree (see below).
560 )"
561
562 TARGET_PRINTING_MODE_COMMAND_LINE_HELP
563 "\n" TARGET_TESTONLY_FILTER_COMMAND_LINE_HELP
564
565 R"(
566 --tree
567 Print a dependency tree. By default, duplicates will be elided with "..."
568 but when --all and -tree are used together, no eliding will be performed.
569
570 The "deps", "public_deps", and "data_deps" will all be included in the
571 tree.
572
573 Tree output can not be used with the filtering or output flags: --as,
574 --type, --testonly.
575 )"
576
577 TARGET_TYPE_FILTER_COMMAND_LINE_HELP
578
579 R"(Note
580
581 This command will show the full name of directories and source files, but
582 when directories and source paths are written to the build file, they will be
583 adjusted to be relative to the build directory. So the values for paths
584 displayed by this command won't match (but should mean the same thing).
585
586 Examples
587
588 gn desc out/Debug //base:base
589 Summarizes the given target.
590
591 gn desc out/Foo :base_unittests deps --tree
592 Shows a dependency tree of the "base_unittests" project in
593 the current directory.
594
595 gn desc out/Debug //base defines --blame
596 Shows defines set for the //base:base target, annotated by where
597 each one was set from.
598 )";
599
RunDesc(const std::vector<std::string> & args)600 int RunDesc(const std::vector<std::string>& args) {
601 if (args.size() != 2 && args.size() != 3) {
602 Err(Location(), "You're holding it wrong.",
603 "Usage: \"gn desc <out_dir> <target_name> [<what to display>]\"")
604 .PrintToStdout();
605 return 1;
606 }
607 const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
608
609 // Deliberately leaked to avoid expensive process teardown.
610 Setup* setup = new Setup;
611 if (!setup->DoSetup(args[0], false))
612 return 1;
613 if (!setup->Run())
614 return 1;
615
616 // Resolve target(s) and config from inputs.
617 UniqueVector<const Target*> target_matches;
618 UniqueVector<const Config*> config_matches;
619 UniqueVector<const Toolchain*> toolchain_matches;
620 UniqueVector<SourceFile> file_matches;
621
622 std::vector<std::string> target_list;
623 target_list.push_back(args[1]);
624
625 if (!ResolveFromCommandLineInput(
626 setup, target_list, cmdline->HasSwitch(switches::kAllToolchains),
627 &target_matches, &config_matches, &toolchain_matches, &file_matches))
628 return 1;
629
630 std::string what_to_print;
631 if (args.size() == 3)
632 what_to_print = args[2];
633
634 bool json = cmdline->GetSwitchValueASCII("format") == "json";
635
636 if (target_matches.empty() && config_matches.empty()) {
637 OutputString(
638 "The input " + args[1] + " matches no targets, configs or files.\n",
639 DECORATION_YELLOW);
640 return 1;
641 }
642
643 if (json) {
644 // Convert all targets/configs to JSON, serialize and print them
645 auto res = std::make_unique<base::DictionaryValue>();
646 if (!target_matches.empty()) {
647 for (const auto* target : target_matches) {
648 res->SetWithoutPathExpansion(
649 target->label().GetUserVisibleName(
650 target->settings()->default_toolchain_label()),
651 DescBuilder::DescriptionForTarget(
652 target, what_to_print, cmdline->HasSwitch(kAll),
653 cmdline->HasSwitch(kTree), cmdline->HasSwitch(kBlame)));
654 }
655 } else if (!config_matches.empty()) {
656 for (const auto* config : config_matches) {
657 res->SetWithoutPathExpansion(
658 config->label().GetUserVisibleName(false),
659 DescBuilder::DescriptionForConfig(config, what_to_print));
660 }
661 }
662 std::string s;
663 base::JSONWriter::WriteWithOptions(
664 *res.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
665 OutputString(s);
666 } else {
667 // Regular (non-json) formatted output
668 bool multiple_outputs = (target_matches.size() + config_matches.size()) > 1;
669 std::map<std::string, DescHandlerFunc> handlers = GetHandlers();
670
671 bool printed_output = false;
672 for (const Target* target : target_matches) {
673 if (printed_output)
674 OutputString("\n\n");
675 printed_output = true;
676
677 if (!PrintTarget(target, what_to_print, !multiple_outputs, handlers,
678 cmdline->HasSwitch(kAll), cmdline->HasSwitch(kTree),
679 cmdline->HasSwitch(kBlame)))
680 return 1;
681 }
682 for (const Config* config : config_matches) {
683 if (printed_output)
684 OutputString("\n\n");
685 printed_output = true;
686
687 if (!PrintConfig(config, what_to_print, !multiple_outputs, handlers))
688 return 1;
689 }
690 }
691
692 return 0;
693 }
694
695 } // namespace commands
696