• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 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 <memory>
6 #include <set>
7 
8 #include "base/json/json_writer.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "gn/commands.h"
11 #include "gn/config.h"
12 #include "gn/config_values_extractors.h"
13 #include "gn/deps_iterator.h"
14 #include "gn/desc_builder.h"
15 #include "gn/input_file.h"
16 #include "gn/parse_tree.h"
17 #include "gn/resolved_target_data.h"
18 #include "gn/runtime_deps.h"
19 #include "gn/rust_variables.h"
20 #include "gn/scope.h"
21 #include "gn/settings.h"
22 #include "gn/standard_out.h"
23 #include "gn/substitution_writer.h"
24 #include "gn/swift_variables.h"
25 #include "gn/variables.h"
26 
27 // Example structure of Value for single target
28 // (not applicable or empty fields will be omitted depending on target type)
29 //
30 // target_properties = {
31 //   "type" : "output_type", // matching Target::GetStringForOutputType
32 //   "toolchain" : "toolchain_name",
33 //   "visibility" : [ list of visibility pattern descriptions ],
34 //   "test_only" : true or false,
35 //   "check_includes": true or false,
36 //   "allow_circular_includes_from": [ list of target names ],
37 //   "sources" : [ list of source files ],
38 //   "public" : either "*" or [ list of public headers],
39 //   "inputs" : [ list of inputs for target ],
40 //   "configs" : [ list of configs for this target ],
41 //   "public_configs" : [ list of public configs for this target],
42 //   "all_dependent_configs", [ list of all dependent configs for this target],
43 //   "script" : "script for action targets",
44 //   "args" : [ argument list for action targets ],
45 //   "depfile : "file name for action input dependencies",
46 //   "outputs" : [ list of target outputs ],
47 //   "arflags", "asmflags", "cflags", "cflags_c",
48 //   "cflags_cc", "cflags_objc", "cflags_objcc",
49 //   "rustflags" : [ list of flags],
50 //   "rustenv" : [ list of Rust environment variables ],
51 //   "defines" : [ list of preprocessor definitions ],
52 //   "include_dirs" : [ list of include directories ],
53 //   "precompiled_header" : "name of precompiled header file",
54 //   "precompiled_source" : "path to precompiled source",
55 //   "deps : [ list of target dependencies ],
56 //   "gen_deps : [ list of generate dependencies ],
57 //   "libs" : [ list of libraries ],
58 //   "lib_dirs" : [ list of library directories ]
59 //   "metadata" : [ dictionary of target metadata values ]
60 //   "data_keys" : [ list of target data keys ]
61 //   "walk_keys" : [ list of target walk keys ]
62 //   "crate_root" : "root file of a Rust target"
63 //   "crate_name" : "name of a Rust target"
64 //   "rebase" : true or false
65 //   "output_conversion" : "string for output conversion"
66 //   "response_file_contents": [ list of response file contents entries ]
67 // }
68 //
69 // Optionally, if "what" is specified while generating description, two other
70 // properties can be requested that are not included by default. First the
71 // runtime dependendencies (see "gn help runtime_deps"):
72 //
73 //   "runtime_deps" : [list of computed runtime dependencies]
74 //
75 // Second, for targets whose sources map to outputs (binary targets,
76 // action_foreach, and copies with non-constant outputs), the "source_outputs"
77 // indicates the mapping from source to output file(s):
78 //
79 //   "source_outputs" : {
80 //      "source_file x" : [ list of outputs for source file x ]
81 //      "source_file y" : [ list of outputs for source file y ]
82 //      ...
83 //   }
84 
85 namespace {
86 
FormatSourceDir(const SourceDir & dir)87 std::string FormatSourceDir(const SourceDir& dir) {
88 #if defined(OS_WIN)
89   // On Windows we fix up system absolute paths to look like native ones.
90   // Internally, they'll look like "/C:\foo\bar/"
91   if (dir.is_system_absolute()) {
92     std::string buf = dir.value();
93     if (buf.size() > 3 && buf[2] == ':') {
94       buf.erase(buf.begin());  // Erase beginning slash.
95       return buf;
96     }
97   }
98 #endif
99   return dir.value();
100 }
101 
102 void RecursiveCollectChildDeps(const Target* target, TargetSet* result);
103 
RecursiveCollectDeps(const Target * target,TargetSet * result)104 void RecursiveCollectDeps(const Target* target, TargetSet* result) {
105   if (!result->add(target))
106     return;  // Already did this target.
107 
108   RecursiveCollectChildDeps(target, result);
109 }
110 
RecursiveCollectChildDeps(const Target * target,TargetSet * result)111 void RecursiveCollectChildDeps(const Target* target, TargetSet* result) {
112   for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
113     RecursiveCollectDeps(pair.ptr, result);
114 }
115 
116 // Common functionality for target and config description builder
117 class BaseDescBuilder {
118  public:
119   using ValuePtr = std::unique_ptr<base::Value>;
120 
BaseDescBuilder(const std::set<std::string> & what,bool all,bool tree,bool blame)121   BaseDescBuilder(const std::set<std::string>& what,
122                   bool all,
123                   bool tree,
124                   bool blame)
125       : what_(what), all_(all), tree_(tree), blame_(blame) {}
126 
127  protected:
128   virtual Label GetToolchainLabel() const = 0;
129 
what(const std::string & w) const130   bool what(const std::string& w) const {
131     return what_.empty() || what_.find(w) != what_.end();
132   }
133 
134   template <typename T>
RenderValue(const std::vector<T> & vector)135   ValuePtr RenderValue(const std::vector<T>& vector) {
136     auto res = std::make_unique<base::ListValue>();
137     for (const auto& v : vector)
138       res->Append(RenderValue(v));
139 
140     return res;
141   }
142 
RenderValue(const std::string & s,bool optional=false)143   ValuePtr RenderValue(const std::string& s, bool optional = false) {
144     return (s.empty() && optional) ? std::make_unique<base::Value>()
145                                    : ValuePtr(new base::Value(s));
146   }
147 
RenderValue(const SourceDir & d)148   ValuePtr RenderValue(const SourceDir& d) {
149     return d.is_null() ? std::make_unique<base::Value>()
150                        : ValuePtr(new base::Value(FormatSourceDir(d)));
151   }
152 
RenderValue(const SourceFile & f)153   ValuePtr RenderValue(const SourceFile& f) {
154     return f.is_null() ? std::make_unique<base::Value>()
155                        : ValuePtr(new base::Value(f.value()));
156   }
157 
RenderValue(const SourceFile * f)158   ValuePtr RenderValue(const SourceFile* f) { return RenderValue(*f); }
159 
RenderValue(const LibFile & lib)160   ValuePtr RenderValue(const LibFile& lib) {
161     if (lib.is_source_file())
162       return RenderValue(lib.source_file());
163     return RenderValue(lib.value());
164   }
165 
166   template <typename T>
ToBaseValue(const std::vector<T> & vector)167   base::Value ToBaseValue(const std::vector<T>& vector) {
168     base::ListValue res;
169     for (const auto& v : vector)
170       res.GetList().emplace_back(ToBaseValue(v));
171     return std::move(res);
172   }
173 
ToBaseValue(const Scope * scope)174   base::Value ToBaseValue(const Scope* scope) {
175     base::DictionaryValue res;
176     Scope::KeyValueMap map;
177     scope->GetCurrentScopeValues(&map);
178     for (const auto& v : map)
179       res.SetKey(v.first, ToBaseValue(v.second));
180     return std::move(res);
181   }
182 
ToBaseValue(const Value & val)183   base::Value ToBaseValue(const Value& val) {
184     switch (val.type()) {
185       case Value::STRING:
186         return base::Value(val.string_value());
187       case Value::INTEGER:
188         return base::Value(int(val.int_value()));
189       case Value::BOOLEAN:
190         return base::Value(val.boolean_value());
191       case Value::SCOPE:
192         return ToBaseValue(val.scope_value());
193       case Value::LIST:
194         return ToBaseValue(val.list_value());
195       case Value::NONE:
196         return base::Value();
197     }
198     NOTREACHED();
199     return base::Value();
200   }
201 
202   template <class VectorType>
FillInConfigVector(base::ListValue * out,const VectorType & configs,int indent=0)203   void FillInConfigVector(base::ListValue* out,
204                           const VectorType& configs,
205                           int indent = 0) {
206     for (const auto& config : configs) {
207       std::string name(indent * 2, ' ');
208       name.append(config.label.GetUserVisibleName(GetToolchainLabel()));
209       out->AppendString(name);
210       if (tree_)
211         FillInConfigVector(out, config.ptr->configs(), indent + 1);
212     }
213   }
214 
FillInPrecompiledHeader(base::DictionaryValue * out,const ConfigValues & values)215   void FillInPrecompiledHeader(base::DictionaryValue* out,
216                                const ConfigValues& values) {
217     if (what(variables::kPrecompiledHeader) &&
218         !values.precompiled_header().empty()) {
219       out->SetWithoutPathExpansion(
220           variables::kPrecompiledHeader,
221           RenderValue(values.precompiled_header(), true));
222     }
223     if (what(variables::kPrecompiledSource) &&
224         !values.precompiled_source().is_null()) {
225       out->SetWithoutPathExpansion(variables::kPrecompiledSource,
226                                    RenderValue(values.precompiled_source()));
227     }
228   }
229 
230   std::set<std::string> what_;
231   bool all_;
232   bool tree_;
233   bool blame_;
234 };
235 
236 class ConfigDescBuilder : public BaseDescBuilder {
237  public:
ConfigDescBuilder(const Config * config,const std::set<std::string> & what)238   ConfigDescBuilder(const Config* config, const std::set<std::string>& what)
239       : BaseDescBuilder(what, false, false, false), config_(config) {}
240 
BuildDescription()241   std::unique_ptr<base::DictionaryValue> BuildDescription() {
242     auto res = std::make_unique<base::DictionaryValue>();
243     const ConfigValues& values = config_->resolved_values();
244 
245     if (what_.empty())
246       res->SetKey(
247           "toolchain",
248           base::Value(
249               config_->label().GetToolchainLabel().GetUserVisibleName(false)));
250 
251     if (what(variables::kConfigs) && !config_->configs().empty()) {
252       auto configs = std::make_unique<base::ListValue>();
253       FillInConfigVector(configs.get(), config_->configs().vector());
254       res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs));
255     }
256 
257     if (what(variables::kVisibility)) {
258       res->SetWithoutPathExpansion(variables::kVisibility,
259                                    config_->visibility().AsValue());
260     }
261 
262 #define CONFIG_VALUE_ARRAY_HANDLER(name, type)                        \
263   if (what(#name)) {                                                  \
264     ValuePtr ptr =                                                    \
265         render_config_value_array<type>(values, &ConfigValues::name); \
266     if (ptr) {                                                        \
267       res->SetWithoutPathExpansion(#name, std::move(ptr));            \
268     }                                                                 \
269   }
270     CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string)
271     CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string)
272     CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string)
273     CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string)
274     CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string)
275     CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string)
276     CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string)
277     CONFIG_VALUE_ARRAY_HANDLER(defines, std::string)
278     CONFIG_VALUE_ARRAY_HANDLER(frameworks, std::string)
279     CONFIG_VALUE_ARRAY_HANDLER(framework_dirs, SourceDir)
280     CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir)
281     CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile)
282     CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string)
283     CONFIG_VALUE_ARRAY_HANDLER(lib_dirs, SourceDir)
284     CONFIG_VALUE_ARRAY_HANDLER(libs, LibFile)
285     CONFIG_VALUE_ARRAY_HANDLER(rustflags, std::string)
286     CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string)
287 
288 #undef CONFIG_VALUE_ARRAY_HANDLER
289 
290     FillInPrecompiledHeader(res.get(), values);
291 
292     return res;
293   }
294 
295  protected:
GetToolchainLabel() const296   Label GetToolchainLabel() const override {
297     return config_->label().GetToolchainLabel();
298   }
299 
300  private:
301   template <typename T>
render_config_value_array(const ConfigValues & values,const std::vector<T> & (ConfigValues::* getter)()const)302   ValuePtr render_config_value_array(
303       const ConfigValues& values,
304       const std::vector<T>& (ConfigValues::*getter)() const) {
305     auto res = std::make_unique<base::ListValue>();
306 
307     for (const T& cur : (values.*getter)())
308       res->Append(RenderValue(cur));
309 
310     return res->empty() ? nullptr : std::move(res);
311   }
312 
313   const Config* config_;
314 };
315 
316 class TargetDescBuilder : public BaseDescBuilder {
317  public:
TargetDescBuilder(const Target * target,const std::set<std::string> & what,bool all,bool tree,bool blame)318   TargetDescBuilder(const Target* target,
319                     const std::set<std::string>& what,
320                     bool all,
321                     bool tree,
322                     bool blame)
323       : BaseDescBuilder(what, all, tree, blame), target_(target) {}
324 
BuildDescription()325   std::unique_ptr<base::DictionaryValue> BuildDescription() {
326     auto res = std::make_unique<base::DictionaryValue>();
327     bool is_binary_output = target_->IsBinary();
328 
329     if (what_.empty()) {
330       res->SetKey(
331           "type",
332           base::Value(Target::GetStringForOutputType(target_->output_type())));
333       res->SetKey(
334           "toolchain",
335           base::Value(
336               target_->label().GetToolchainLabel().GetUserVisibleName(false)));
337     }
338 
339     if (target_->source_types_used().RustSourceUsed()) {
340       if (what(variables::kRustCrateRoot)) {
341         res->SetWithoutPathExpansion(
342             variables::kRustCrateRoot,
343             RenderValue(target_->rust_values().crate_root()));
344       }
345       if (what(variables::kRustCrateName)) {
346         res->SetKey(variables::kRustCrateName,
347                     base::Value(target_->rust_values().crate_name()));
348       }
349     }
350 
351     if (target_->source_types_used().SwiftSourceUsed()) {
352       if (what(variables::kSwiftBridgeHeader)) {
353         res->SetWithoutPathExpansion(
354             variables::kSwiftBridgeHeader,
355             RenderValue(target_->swift_values().bridge_header()));
356       }
357       if (what(variables::kSwiftModuleName)) {
358         res->SetKey(variables::kSwiftModuleName,
359                     base::Value(target_->swift_values().module_name()));
360       }
361     }
362 
363     // General target meta variables.
364 
365     if (what(variables::kMetadata)) {
366       base::DictionaryValue metadata;
367       for (const auto& v : target_->metadata().contents())
368         metadata.SetKey(v.first, ToBaseValue(v.second));
369       res->SetKey(variables::kMetadata, std::move(metadata));
370     }
371 
372     if (what(variables::kVisibility))
373       res->SetWithoutPathExpansion(variables::kVisibility,
374                                    target_->visibility().AsValue());
375 
376     if (what(variables::kTestonly))
377       res->SetKey(variables::kTestonly, base::Value(target_->testonly()));
378 
379     if (is_binary_output) {
380       if (what(variables::kCheckIncludes))
381         res->SetKey(variables::kCheckIncludes,
382                     base::Value(target_->check_includes()));
383 
384       if (what(variables::kAllowCircularIncludesFrom)) {
385         auto labels = std::make_unique<base::ListValue>();
386         for (const auto& cur : target_->allow_circular_includes_from())
387           labels->AppendString(cur.GetUserVisibleName(GetToolchainLabel()));
388 
389         res->SetWithoutPathExpansion(variables::kAllowCircularIncludesFrom,
390                                      std::move(labels));
391       }
392     }
393 
394     if (what(variables::kSources) && !target_->sources().empty())
395       res->SetWithoutPathExpansion(variables::kSources,
396                                    RenderValue(target_->sources()));
397 
398     if (what(variables::kOutputName) && !target_->output_name().empty())
399       res->SetKey(variables::kOutputName, base::Value(target_->output_name()));
400 
401     if (what(variables::kOutputDir) && !target_->output_dir().is_null())
402       res->SetWithoutPathExpansion(variables::kOutputDir,
403                                    RenderValue(target_->output_dir()));
404 
405     if (what(variables::kOutputExtension) && target_->output_extension_set())
406       res->SetKey(variables::kOutputExtension,
407                   base::Value(target_->output_extension()));
408 
409     if (what(variables::kPublic)) {
410       if (target_->all_headers_public())
411         res->SetKey(variables::kPublic, base::Value("*"));
412       else
413         res->SetWithoutPathExpansion(variables::kPublic,
414                                      RenderValue(target_->public_headers()));
415     }
416 
417     if (what(variables::kInputs)) {
418       std::vector<const SourceFile*> inputs;
419       for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
420         for (const auto& input : iter.cur().inputs())
421           inputs.push_back(&input);
422       }
423       if (!inputs.empty())
424         res->SetWithoutPathExpansion(variables::kInputs, RenderValue(inputs));
425     }
426 
427     if (is_binary_output && what(variables::kConfigs) &&
428         !target_->configs().empty()) {
429       auto configs = std::make_unique<base::ListValue>();
430       FillInConfigVector(configs.get(), target_->configs().vector());
431       FillInConfigVector(configs.get(), target_->own_configs().vector());
432       res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs));
433     }
434 
435     if (what(variables::kPublicConfigs) && !target_->public_configs().empty()) {
436       auto configs = std::make_unique<base::ListValue>();
437       FillInConfigVector(configs.get(), target_->public_configs());
438       FillInConfigVector(configs.get(), target_->own_public_configs());
439       res->SetWithoutPathExpansion(variables::kPublicConfigs,
440                                    std::move(configs));
441     }
442 
443     if (what(variables::kAllDependentConfigs) &&
444         !target_->all_dependent_configs().empty()) {
445       auto configs = std::make_unique<base::ListValue>();
446       FillInConfigVector(configs.get(), target_->all_dependent_configs());
447       FillInConfigVector(configs.get(), target_->own_all_dependent_configs());
448       res->SetWithoutPathExpansion(variables::kAllDependentConfigs,
449                                    std::move(configs));
450     }
451 
452     // Action
453     if (target_->output_type() == Target::ACTION ||
454         target_->output_type() == Target::ACTION_FOREACH) {
455       if (what(variables::kScript))
456         res->SetKey(variables::kScript,
457                     base::Value(target_->action_values().script().value()));
458 
459       if (what(variables::kArgs)) {
460         auto args = std::make_unique<base::ListValue>();
461         for (const auto& elem : target_->action_values().args().list())
462           args->AppendString(elem.AsString());
463 
464         res->SetWithoutPathExpansion(variables::kArgs, std::move(args));
465       }
466       if (what(variables::kResponseFileContents) &&
467           !target_->action_values().rsp_file_contents().list().empty()) {
468         auto rsp_file_contents = std::make_unique<base::ListValue>();
469         for (const auto& elem :
470              target_->action_values().rsp_file_contents().list())
471           rsp_file_contents->AppendString(elem.AsString());
472 
473         res->SetWithoutPathExpansion(variables::kResponseFileContents,
474                                      std::move(rsp_file_contents));
475       }
476       if (what(variables::kDepfile) &&
477           !target_->action_values().depfile().empty()) {
478         res->SetKey(variables::kDepfile,
479                     base::Value(target_->action_values().depfile().AsString()));
480       }
481     }
482 
483     if (target_->output_type() != Target::SOURCE_SET &&
484         target_->output_type() != Target::GROUP &&
485         target_->output_type() != Target::BUNDLE_DATA) {
486       if (what(variables::kOutputs))
487         FillInOutputs(res.get());
488     }
489 
490     // Source outputs are only included when specifically asked for it
491     if (what_.find("source_outputs") != what_.end())
492       FillInSourceOutputs(res.get());
493 
494     if (target_->output_type() == Target::CREATE_BUNDLE && what("bundle_data"))
495       FillInBundle(res.get());
496 
497     if (is_binary_output) {
498 #define CONFIG_VALUE_ARRAY_HANDLER(name, type, config)                    \
499   if (what(#name)) {                                                      \
500     ValuePtr ptr = RenderConfigValues<type>(config, &ConfigValues::name); \
501     if (ptr) {                                                            \
502       res->SetWithoutPathExpansion(#name, std::move(ptr));                \
503     }                                                                     \
504   }
505       CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string,
506                                  kRecursiveWriterKeepDuplicates)
507       CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string,
508                                  kRecursiveWriterKeepDuplicates)
509       CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string,
510                                  kRecursiveWriterKeepDuplicates)
511       CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string,
512                                  kRecursiveWriterKeepDuplicates)
513       CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string,
514                                  kRecursiveWriterKeepDuplicates)
515       CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string,
516                                  kRecursiveWriterKeepDuplicates)
517       CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string,
518                                  kRecursiveWriterKeepDuplicates)
519       CONFIG_VALUE_ARRAY_HANDLER(rustflags, std::string,
520                                  kRecursiveWriterKeepDuplicates)
521       CONFIG_VALUE_ARRAY_HANDLER(rustenv, std::string,
522                                  kRecursiveWriterKeepDuplicates)
523       CONFIG_VALUE_ARRAY_HANDLER(defines, std::string,
524                                  kRecursiveWriterSkipDuplicates)
525       CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir,
526                                  kRecursiveWriterSkipDuplicates)
527       CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile,
528                                  kRecursiveWriterKeepDuplicates)
529       CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string,
530                                  kRecursiveWriterKeepDuplicates)
531       CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string,
532                                  kRecursiveWriterKeepDuplicates)
533 #undef CONFIG_VALUE_ARRAY_HANDLER
534 
535       // Libs and lib_dirs are handled specially below.
536 
537       if (what(variables::kExterns)) {
538         base::DictionaryValue externs;
539         for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
540           const ConfigValues& cur = iter.cur();
541           for (const auto& e : cur.externs()) {
542             externs.SetKey(e.first, base::Value(e.second.value()));
543           }
544         }
545         res->SetKey(variables::kExterns, std::move(externs));
546       }
547 
548       FillInPrecompiledHeader(res.get(), target_->config_values());
549     }
550 
551     // GeneratedFile vars.
552     if (target_->output_type() == Target::GENERATED_FILE) {
553       if (what(variables::kWriteOutputConversion)) {
554         res->SetKey(variables::kWriteOutputConversion,
555                     ToBaseValue(target_->output_conversion()));
556       }
557       if (what(variables::kDataKeys)) {
558         base::ListValue keys;
559         for (const auto& k : target_->data_keys())
560           keys.GetList().push_back(base::Value(k));
561         res->SetKey(variables::kDataKeys, std::move(keys));
562       }
563       if (what(variables::kRebase)) {
564         res->SetWithoutPathExpansion(variables::kRebase,
565                                      RenderValue(target_->rebase()));
566       }
567       if (what(variables::kWalkKeys)) {
568         base::ListValue keys;
569         for (const auto& k : target_->walk_keys())
570           keys.GetList().push_back(base::Value(k));
571         res->SetKey(variables::kWalkKeys, std::move(keys));
572       }
573     }
574 
575     if (what(variables::kDeps))
576       res->SetWithoutPathExpansion(variables::kDeps, RenderDeps());
577 
578     if (what(variables::kGenDeps) && !target_->gen_deps().empty())
579       res->SetWithoutPathExpansion(variables::kGenDeps, RenderGenDeps());
580 
581     // Runtime deps are special, print only when explicitly asked for and not in
582     // overview mode.
583     if (what_.find("runtime_deps") != what_.end())
584       res->SetWithoutPathExpansion("runtime_deps", RenderRuntimeDeps());
585 
586     // libs and lib_dirs are special in that they're inherited. We don't
587     // currently implement a blame feature for this since the bottom-up
588     // inheritance makes this difficult.
589 
590     ResolvedTargetData resolved;
591 
592     // Libs can be part of any target and get recursively pushed up the chain,
593     // so display them regardless of target type.
594     if (what(variables::kLibs)) {
595       const auto& all_libs = resolved.GetLinkedLibraries(target_);
596       if (!all_libs.empty()) {
597         auto libs = std::make_unique<base::ListValue>();
598         for (size_t i = 0; i < all_libs.size(); i++)
599           libs->AppendString(all_libs[i].value());
600         res->SetWithoutPathExpansion(variables::kLibs, std::move(libs));
601       }
602     }
603 
604     if (what(variables::kLibDirs)) {
605       const auto& all_lib_dirs = resolved.GetLinkedLibraryDirs(target_);
606       if (!all_lib_dirs.empty()) {
607         auto lib_dirs = std::make_unique<base::ListValue>();
608         for (size_t i = 0; i < all_lib_dirs.size(); i++)
609           lib_dirs->AppendString(FormatSourceDir(all_lib_dirs[i]));
610         res->SetWithoutPathExpansion(variables::kLibDirs, std::move(lib_dirs));
611       }
612     }
613 
614     if (what(variables::kFrameworks)) {
615       const auto& all_frameworks = resolved.GetLinkedFrameworks(target_);
616       if (!all_frameworks.empty()) {
617         auto frameworks = std::make_unique<base::ListValue>();
618         for (size_t i = 0; i < all_frameworks.size(); i++)
619           frameworks->AppendString(all_frameworks[i]);
620         res->SetWithoutPathExpansion(variables::kFrameworks,
621                                      std::move(frameworks));
622       }
623     }
624     if (what(variables::kWeakFrameworks)) {
625       const auto& weak_frameworks = resolved.GetLinkedWeakFrameworks(target_);
626       if (!weak_frameworks.empty()) {
627         auto frameworks = std::make_unique<base::ListValue>();
628         for (size_t i = 0; i < weak_frameworks.size(); i++)
629           frameworks->AppendString(weak_frameworks[i]);
630         res->SetWithoutPathExpansion(variables::kWeakFrameworks,
631                                      std::move(frameworks));
632       }
633     }
634 
635     if (what(variables::kFrameworkDirs)) {
636       const auto& all_framework_dirs = resolved.GetLinkedFrameworkDirs(target_);
637       if (!all_framework_dirs.empty()) {
638         auto framework_dirs = std::make_unique<base::ListValue>();
639         for (size_t i = 0; i < all_framework_dirs.size(); i++)
640           framework_dirs->AppendString(all_framework_dirs[i].value());
641         res->SetWithoutPathExpansion(variables::kFrameworkDirs,
642                                      std::move(framework_dirs));
643       }
644     }
645 
646     return res;
647   }
648 
649  private:
650   // Prints dependencies of the given target (not the target itself). If the
651   // set is non-null, new targets encountered will be added to the set, and if
652   // a dependency is in the set already, it will not be recused into. When the
653   // set is null, all dependencies will be printed.
RecursivePrintDeps(base::ListValue * out,const Target * target,TargetSet * seen_targets,int indent_level)654   void RecursivePrintDeps(base::ListValue* out,
655                           const Target* target,
656                           TargetSet* seen_targets,
657                           int indent_level) {
658     // Combine all deps into one sorted list.
659     std::vector<LabelTargetPair> sorted_deps;
660     for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
661       sorted_deps.push_back(pair);
662     std::sort(sorted_deps.begin(), sorted_deps.end());
663 
664     std::string indent(indent_level * 2, ' ');
665 
666     for (const auto& pair : sorted_deps) {
667       const Target* cur_dep = pair.ptr;
668       std::string str =
669           indent + cur_dep->label().GetUserVisibleName(GetToolchainLabel());
670 
671       bool print_children = true;
672       if (seen_targets) {
673         if (!seen_targets->add(cur_dep)) {
674           // Already seen.
675           print_children = false;
676           // Only print "..." if something is actually elided, which means that
677           // the current target has children.
678           if (!cur_dep->public_deps().empty() ||
679               !cur_dep->private_deps().empty() || !cur_dep->data_deps().empty())
680             str += "...";
681         }
682       }
683 
684       out->AppendString(str);
685 
686       if (print_children)
687         RecursivePrintDeps(out, cur_dep, seen_targets, indent_level + 1);
688     }
689   }
690 
RenderDeps()691   ValuePtr RenderDeps() {
692     auto res = std::make_unique<base::ListValue>();
693 
694     // Tree mode is separate.
695     if (tree_) {
696       if (all_) {
697         // Show all tree deps with no eliding.
698         RecursivePrintDeps(res.get(), target_, nullptr, 0);
699       } else {
700         // Don't recurse into duplicates.
701         TargetSet seen_targets;
702         RecursivePrintDeps(res.get(), target_, &seen_targets, 0);
703       }
704     } else {  // not tree
705 
706       // Collect the deps to display.
707       if (all_) {
708         // Show all dependencies.
709         TargetSet all_deps;
710         RecursiveCollectChildDeps(target_, &all_deps);
711         commands::FilterAndPrintTargetSet(all_deps, res.get());
712       } else {
713         // Show direct dependencies only.
714         std::vector<const Target*> deps;
715         for (const auto& pair : target_->GetDeps(Target::DEPS_ALL))
716           deps.push_back(pair.ptr);
717         std::sort(deps.begin(), deps.end());
718         commands::FilterAndPrintTargets(&deps, res.get());
719       }
720     }
721 
722     return res;
723   }
724 
RenderGenDeps()725   ValuePtr RenderGenDeps() {
726     auto res = std::make_unique<base::ListValue>();
727     Label default_tc = target_->settings()->default_toolchain_label();
728     std::vector<std::string> gen_deps;
729     for (const auto& pair : target_->gen_deps())
730       gen_deps.push_back(pair.label.GetUserVisibleName(default_tc));
731     std::sort(gen_deps.begin(), gen_deps.end());
732     for (const auto& dep : gen_deps)
733       res->AppendString(dep);
734     return res;
735   }
736 
RenderRuntimeDeps()737   ValuePtr RenderRuntimeDeps() {
738     auto res = std::make_unique<base::ListValue>();
739 
740     const Target* previous_from = NULL;
741     for (const auto& pair : ComputeRuntimeDeps(target_)) {
742       std::string str;
743       if (blame_) {
744         // Generally a target's runtime deps will be listed sequentially, so
745         // group them and don't duplicate the "from" label for two in a row.
746         if (previous_from == pair.second) {
747           str = "  ";
748         } else {
749           previous_from = pair.second;
750           res->AppendString(
751               str + "From " +
752               pair.second->label().GetUserVisibleName(GetToolchainLabel()));
753           str = "  ";
754         }
755       }
756 
757       res->AppendString(str + pair.first.value());
758     }
759 
760     return res;
761   }
762 
FillInSourceOutputs(base::DictionaryValue * res)763   void FillInSourceOutputs(base::DictionaryValue* res) {
764     // Only include "source outputs" if there are sources that map to outputs.
765     // Things like actions have constant per-target outputs that don't depend on
766     // the list of sources. These don't need source outputs.
767     if (target_->output_type() != Target::ACTION_FOREACH &&
768         target_->output_type() != Target::COPY_FILES && !target_->IsBinary())
769       return;  // Everything else has constant outputs.
770 
771     // "copy" targets may have patterns or not. If there's only one file, the
772     // user can specify a constant output name.
773     if (target_->output_type() == Target::COPY_FILES &&
774         target_->action_values().outputs().required_types().empty())
775       return;  // Constant output.
776 
777     auto dict = std::make_unique<base::DictionaryValue>();
778     for (const auto& source : target_->sources()) {
779       std::vector<OutputFile> outputs;
780       const char* tool_name = Tool::kToolNone;
781       if (target_->GetOutputFilesForSource(source, &tool_name, &outputs)) {
782         auto list = std::make_unique<base::ListValue>();
783         for (const auto& output : outputs)
784           list->AppendString(output.value());
785 
786         dict->SetWithoutPathExpansion(source.value(), std::move(list));
787       }
788     }
789     res->SetWithoutPathExpansion("source_outputs", std::move(dict));
790   }
791 
FillInBundle(base::DictionaryValue * res)792   void FillInBundle(base::DictionaryValue* res) {
793     auto data = std::make_unique<base::DictionaryValue>();
794     const BundleData& bundle_data = target_->bundle_data();
795     const Settings* settings = target_->settings();
796     BundleData::SourceFiles sources;
797     bundle_data.GetSourceFiles(&sources);
798     data->SetWithoutPathExpansion("source_files", RenderValue(sources));
799     data->SetKey(
800         "root_dir_output",
801         base::Value(bundle_data.GetBundleRootDirOutput(settings).value()));
802     data->SetWithoutPathExpansion("root_dir",
803                                   RenderValue(bundle_data.root_dir()));
804     data->SetWithoutPathExpansion("resources_dir",
805                                   RenderValue(bundle_data.resources_dir()));
806     data->SetWithoutPathExpansion("executable_dir",
807                                   RenderValue(bundle_data.executable_dir()));
808     data->SetKey("product_type", base::Value(bundle_data.product_type()));
809     data->SetWithoutPathExpansion(
810         "partial_info_plist", RenderValue(bundle_data.partial_info_plist()));
811 
812     auto deps = std::make_unique<base::ListValue>();
813     for (const auto* dep : bundle_data.bundle_deps())
814       deps->AppendString(dep->label().GetUserVisibleName(GetToolchainLabel()));
815 
816     data->SetWithoutPathExpansion("deps", std::move(deps));
817     res->SetWithoutPathExpansion("bundle_data", std::move(data));
818   }
819 
FillInOutputs(base::DictionaryValue * res)820   void FillInOutputs(base::DictionaryValue* res) {
821     std::vector<SourceFile> output_files;
822     Err err;
823     if (!target_->GetOutputsAsSourceFiles(LocationRange(), true, &output_files,
824                                           &err)) {
825       err.PrintToStdout();
826       return;
827     }
828     res->SetWithoutPathExpansion(variables::kOutputs,
829                                  RenderValue(output_files));
830 
831     // Write some extra data for certain output types.
832     if (target_->output_type() == Target::ACTION_FOREACH ||
833         target_->output_type() == Target::COPY_FILES) {
834       const SubstitutionList& outputs = target_->action_values().outputs();
835       if (!outputs.required_types().empty()) {
836         // Write out the output patterns if there are any.
837         auto patterns = std::make_unique<base::ListValue>();
838         for (const auto& elem : outputs.list())
839           patterns->AppendString(elem.AsString());
840 
841         res->SetWithoutPathExpansion("output_patterns", std::move(patterns));
842       }
843     }
844   }
845 
846   // Writes a given config value type to the string, optionally with
847   // attribution.
848   // This should match RecursiveTargetConfigToStream in the order it traverses.
849   template <class T>
RenderConfigValues(RecursiveWriterConfig writer_config,const std::vector<T> & (ConfigValues::* getter)()const)850   ValuePtr RenderConfigValues(RecursiveWriterConfig writer_config,
851                               const std::vector<T>& (ConfigValues::*getter)()
852                                   const) {
853     std::set<T> seen;
854     auto res = std::make_unique<base::ListValue>();
855     for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
856       const std::vector<T>& vec = (iter.cur().*getter)();
857 
858       if (vec.empty())
859         continue;
860 
861       if (blame_) {
862         const Config* config = iter.GetCurrentConfig();
863         if (config) {
864           // Source of this value is a config.
865           std::string from =
866               "From " + config->label().GetUserVisibleName(false);
867           res->AppendString(from);
868           if (iter.origin()) {
869             Location location = iter.origin()->GetRange().begin();
870             from = "     (Added by " + location.file()->name().value() + ":" +
871                    base::IntToString(location.line_number()) + ")";
872             res->AppendString(from);
873           }
874         } else {
875           // Source of this value is the target itself.
876           std::string from =
877               "From " + target_->label().GetUserVisibleName(false);
878           res->AppendString(from);
879         }
880       }
881 
882       // If blame is on, then do not de-dup across configs.
883       if (blame_)
884         seen.clear();
885 
886       for (const T& val : vec) {
887         switch (writer_config) {
888           case kRecursiveWriterKeepDuplicates:
889             break;
890 
891           case kRecursiveWriterSkipDuplicates: {
892             if (seen.find(val) != seen.end())
893               continue;
894 
895             seen.insert(val);
896             break;
897           }
898         }
899 
900         ValuePtr rendered = RenderValue(val);
901         std::string str;
902         // Indent string values in blame mode
903         if (blame_ && rendered->GetAsString(&str)) {
904           str = "  " + str;
905           rendered = std::make_unique<base::Value>(str);
906         }
907         res->Append(std::move(rendered));
908       }
909     }
910     return res->empty() ? nullptr : std::move(res);
911   }
912 
GetToolchainLabel() const913   Label GetToolchainLabel() const override {
914     return target_->label().GetToolchainLabel();
915   }
916 
917   const Target* target_;
918 };
919 
920 }  // namespace
921 
DescriptionForTarget(const Target * target,const std::string & what,bool all,bool tree,bool blame)922 std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForTarget(
923     const Target* target,
924     const std::string& what,
925     bool all,
926     bool tree,
927     bool blame) {
928   std::set<std::string> w;
929   if (!what.empty())
930     w.insert(what);
931   TargetDescBuilder b(target, w, all, tree, blame);
932   return b.BuildDescription();
933 }
934 
DescriptionForConfig(const Config * config,const std::string & what)935 std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForConfig(
936     const Config* config,
937     const std::string& what) {
938   std::set<std::string> w;
939   if (!what.empty())
940     w.insert(what);
941   ConfigDescBuilder b(config, w);
942   return b.BuildDescription();
943 }
944