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