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