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 res->SetWithoutPathExpansion(variables::kConfigs, std::move(configs));
432 }
433
434 if (what(variables::kPublicConfigs) && !target_->public_configs().empty()) {
435 auto configs = std::make_unique<base::ListValue>();
436 FillInConfigVector(configs.get(), target_->public_configs());
437 res->SetWithoutPathExpansion(variables::kPublicConfigs,
438 std::move(configs));
439 }
440
441 if (what(variables::kAllDependentConfigs) &&
442 !target_->all_dependent_configs().empty()) {
443 auto configs = std::make_unique<base::ListValue>();
444 FillInConfigVector(configs.get(), target_->all_dependent_configs());
445 res->SetWithoutPathExpansion(variables::kAllDependentConfigs,
446 std::move(configs));
447 }
448
449 // Action
450 if (target_->output_type() == Target::ACTION ||
451 target_->output_type() == Target::ACTION_FOREACH) {
452 if (what(variables::kScript))
453 res->SetKey(variables::kScript,
454 base::Value(target_->action_values().script().value()));
455
456 if (what(variables::kArgs)) {
457 auto args = std::make_unique<base::ListValue>();
458 for (const auto& elem : target_->action_values().args().list())
459 args->AppendString(elem.AsString());
460
461 res->SetWithoutPathExpansion(variables::kArgs, std::move(args));
462 }
463 if (what(variables::kResponseFileContents) &&
464 !target_->action_values().rsp_file_contents().list().empty()) {
465 auto rsp_file_contents = std::make_unique<base::ListValue>();
466 for (const auto& elem :
467 target_->action_values().rsp_file_contents().list())
468 rsp_file_contents->AppendString(elem.AsString());
469
470 res->SetWithoutPathExpansion(variables::kResponseFileContents,
471 std::move(rsp_file_contents));
472 }
473 if (what(variables::kDepfile) &&
474 !target_->action_values().depfile().empty()) {
475 res->SetKey(variables::kDepfile,
476 base::Value(target_->action_values().depfile().AsString()));
477 }
478 }
479
480 if (target_->output_type() != Target::SOURCE_SET &&
481 target_->output_type() != Target::GROUP &&
482 target_->output_type() != Target::BUNDLE_DATA) {
483 if (what(variables::kOutputs))
484 FillInOutputs(res.get());
485 }
486
487 // Source outputs are only included when specifically asked for it
488 if (what_.find("source_outputs") != what_.end())
489 FillInSourceOutputs(res.get());
490
491 if (target_->output_type() == Target::CREATE_BUNDLE && what("bundle_data"))
492 FillInBundle(res.get());
493
494 if (is_binary_output) {
495 #define CONFIG_VALUE_ARRAY_HANDLER(name, type, config) \
496 if (what(#name)) { \
497 ValuePtr ptr = RenderConfigValues<type>(config, &ConfigValues::name); \
498 if (ptr) { \
499 res->SetWithoutPathExpansion(#name, std::move(ptr)); \
500 } \
501 }
502 CONFIG_VALUE_ARRAY_HANDLER(arflags, std::string,
503 kRecursiveWriterKeepDuplicates)
504 CONFIG_VALUE_ARRAY_HANDLER(asmflags, std::string,
505 kRecursiveWriterKeepDuplicates)
506 CONFIG_VALUE_ARRAY_HANDLER(cflags, std::string,
507 kRecursiveWriterKeepDuplicates)
508 CONFIG_VALUE_ARRAY_HANDLER(cflags_c, std::string,
509 kRecursiveWriterKeepDuplicates)
510 CONFIG_VALUE_ARRAY_HANDLER(cflags_cc, std::string,
511 kRecursiveWriterKeepDuplicates)
512 CONFIG_VALUE_ARRAY_HANDLER(cflags_objc, std::string,
513 kRecursiveWriterKeepDuplicates)
514 CONFIG_VALUE_ARRAY_HANDLER(cflags_objcc, std::string,
515 kRecursiveWriterKeepDuplicates)
516 CONFIG_VALUE_ARRAY_HANDLER(rustflags, std::string,
517 kRecursiveWriterKeepDuplicates)
518 CONFIG_VALUE_ARRAY_HANDLER(rustenv, std::string,
519 kRecursiveWriterKeepDuplicates)
520 CONFIG_VALUE_ARRAY_HANDLER(defines, std::string,
521 kRecursiveWriterSkipDuplicates)
522 CONFIG_VALUE_ARRAY_HANDLER(include_dirs, SourceDir,
523 kRecursiveWriterSkipDuplicates)
524 CONFIG_VALUE_ARRAY_HANDLER(inputs, SourceFile,
525 kRecursiveWriterKeepDuplicates)
526 CONFIG_VALUE_ARRAY_HANDLER(ldflags, std::string,
527 kRecursiveWriterKeepDuplicates)
528 CONFIG_VALUE_ARRAY_HANDLER(swiftflags, std::string,
529 kRecursiveWriterKeepDuplicates)
530 #undef CONFIG_VALUE_ARRAY_HANDLER
531
532 // Libs and lib_dirs are handled specially below.
533
534 if (what(variables::kExterns)) {
535 base::DictionaryValue externs;
536 for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
537 const ConfigValues& cur = iter.cur();
538 for (const auto& e : cur.externs()) {
539 externs.SetKey(e.first, base::Value(e.second.value()));
540 }
541 }
542 res->SetKey(variables::kExterns, std::move(externs));
543 }
544
545 FillInPrecompiledHeader(res.get(), target_->config_values());
546 }
547
548 // GeneratedFile vars.
549 if (target_->output_type() == Target::GENERATED_FILE) {
550 if (what(variables::kWriteOutputConversion)) {
551 res->SetKey(variables::kWriteOutputConversion,
552 ToBaseValue(target_->output_conversion()));
553 }
554 if (what(variables::kDataKeys)) {
555 base::ListValue keys;
556 for (const auto& k : target_->data_keys())
557 keys.GetList().push_back(base::Value(k));
558 res->SetKey(variables::kDataKeys, std::move(keys));
559 }
560 if (what(variables::kRebase)) {
561 res->SetWithoutPathExpansion(variables::kRebase,
562 RenderValue(target_->rebase()));
563 }
564 if (what(variables::kWalkKeys)) {
565 base::ListValue keys;
566 for (const auto& k : target_->walk_keys())
567 keys.GetList().push_back(base::Value(k));
568 res->SetKey(variables::kWalkKeys, std::move(keys));
569 }
570 }
571
572 if (what(variables::kDeps))
573 res->SetWithoutPathExpansion(variables::kDeps, RenderDeps());
574
575 if (what(variables::kGenDeps) && !target_->gen_deps().empty())
576 res->SetWithoutPathExpansion(variables::kGenDeps, RenderGenDeps());
577
578 // Runtime deps are special, print only when explicitly asked for and not in
579 // overview mode.
580 if (what_.find("runtime_deps") != what_.end())
581 res->SetWithoutPathExpansion("runtime_deps", RenderRuntimeDeps());
582
583 // libs and lib_dirs are special in that they're inherited. We don't
584 // currently implement a blame feature for this since the bottom-up
585 // inheritance makes this difficult.
586
587 ResolvedTargetData resolved;
588
589 // Libs can be part of any target and get recursively pushed up the chain,
590 // so display them regardless of target type.
591 if (what(variables::kLibs)) {
592 const auto& all_libs = resolved.GetLinkedLibraries(target_);
593 if (!all_libs.empty()) {
594 auto libs = std::make_unique<base::ListValue>();
595 for (size_t i = 0; i < all_libs.size(); i++)
596 libs->AppendString(all_libs[i].value());
597 res->SetWithoutPathExpansion(variables::kLibs, std::move(libs));
598 }
599 }
600
601 if (what(variables::kLibDirs)) {
602 const auto& all_lib_dirs = resolved.GetLinkedLibraryDirs(target_);
603 if (!all_lib_dirs.empty()) {
604 auto lib_dirs = std::make_unique<base::ListValue>();
605 for (size_t i = 0; i < all_lib_dirs.size(); i++)
606 lib_dirs->AppendString(FormatSourceDir(all_lib_dirs[i]));
607 res->SetWithoutPathExpansion(variables::kLibDirs, std::move(lib_dirs));
608 }
609 }
610
611 if (what(variables::kFrameworks)) {
612 const auto& all_frameworks = resolved.GetLinkedFrameworks(target_);
613 if (!all_frameworks.empty()) {
614 auto frameworks = std::make_unique<base::ListValue>();
615 for (size_t i = 0; i < all_frameworks.size(); i++)
616 frameworks->AppendString(all_frameworks[i]);
617 res->SetWithoutPathExpansion(variables::kFrameworks,
618 std::move(frameworks));
619 }
620 }
621 if (what(variables::kWeakFrameworks)) {
622 const auto& weak_frameworks = resolved.GetLinkedWeakFrameworks(target_);
623 if (!weak_frameworks.empty()) {
624 auto frameworks = std::make_unique<base::ListValue>();
625 for (size_t i = 0; i < weak_frameworks.size(); i++)
626 frameworks->AppendString(weak_frameworks[i]);
627 res->SetWithoutPathExpansion(variables::kWeakFrameworks,
628 std::move(frameworks));
629 }
630 }
631
632 if (what(variables::kFrameworkDirs)) {
633 const auto& all_framework_dirs = resolved.GetLinkedFrameworkDirs(target_);
634 if (!all_framework_dirs.empty()) {
635 auto framework_dirs = std::make_unique<base::ListValue>();
636 for (size_t i = 0; i < all_framework_dirs.size(); i++)
637 framework_dirs->AppendString(all_framework_dirs[i].value());
638 res->SetWithoutPathExpansion(variables::kFrameworkDirs,
639 std::move(framework_dirs));
640 }
641 }
642
643 return res;
644 }
645
646 private:
647 // Prints dependencies of the given target (not the target itself). If the
648 // set is non-null, new targets encountered will be added to the set, and if
649 // a dependency is in the set already, it will not be recused into. When the
650 // set is null, all dependencies will be printed.
RecursivePrintDeps(base::ListValue * out,const Target * target,TargetSet * seen_targets,int indent_level)651 void RecursivePrintDeps(base::ListValue* out,
652 const Target* target,
653 TargetSet* seen_targets,
654 int indent_level) {
655 // Combine all deps into one sorted list.
656 std::vector<LabelTargetPair> sorted_deps;
657 for (const auto& pair : target->GetDeps(Target::DEPS_ALL))
658 sorted_deps.push_back(pair);
659 std::sort(sorted_deps.begin(), sorted_deps.end());
660
661 std::string indent(indent_level * 2, ' ');
662
663 for (const auto& pair : sorted_deps) {
664 const Target* cur_dep = pair.ptr;
665 std::string str =
666 indent + cur_dep->label().GetUserVisibleName(GetToolchainLabel());
667
668 bool print_children = true;
669 if (seen_targets) {
670 if (!seen_targets->add(cur_dep)) {
671 // Already seen.
672 print_children = false;
673 // Only print "..." if something is actually elided, which means that
674 // the current target has children.
675 if (!cur_dep->public_deps().empty() ||
676 !cur_dep->private_deps().empty() || !cur_dep->data_deps().empty())
677 str += "...";
678 }
679 }
680
681 out->AppendString(str);
682
683 if (print_children)
684 RecursivePrintDeps(out, cur_dep, seen_targets, indent_level + 1);
685 }
686 }
687
RenderDeps()688 ValuePtr RenderDeps() {
689 auto res = std::make_unique<base::ListValue>();
690
691 // Tree mode is separate.
692 if (tree_) {
693 if (all_) {
694 // Show all tree deps with no eliding.
695 RecursivePrintDeps(res.get(), target_, nullptr, 0);
696 } else {
697 // Don't recurse into duplicates.
698 TargetSet seen_targets;
699 RecursivePrintDeps(res.get(), target_, &seen_targets, 0);
700 }
701 } else { // not tree
702
703 // Collect the deps to display.
704 if (all_) {
705 // Show all dependencies.
706 TargetSet all_deps;
707 RecursiveCollectChildDeps(target_, &all_deps);
708 commands::FilterAndPrintTargetSet(all_deps, res.get());
709 } else {
710 // Show direct dependencies only.
711 std::vector<const Target*> deps;
712 for (const auto& pair : target_->GetDeps(Target::DEPS_ALL))
713 deps.push_back(pair.ptr);
714 std::sort(deps.begin(), deps.end());
715 commands::FilterAndPrintTargets(&deps, res.get());
716 }
717 }
718
719 return res;
720 }
721
RenderGenDeps()722 ValuePtr RenderGenDeps() {
723 auto res = std::make_unique<base::ListValue>();
724 Label default_tc = target_->settings()->default_toolchain_label();
725 std::vector<std::string> gen_deps;
726 for (const auto& pair : target_->gen_deps())
727 gen_deps.push_back(pair.label.GetUserVisibleName(default_tc));
728 std::sort(gen_deps.begin(), gen_deps.end());
729 for (const auto& dep : gen_deps)
730 res->AppendString(dep);
731 return res;
732 }
733
RenderRuntimeDeps()734 ValuePtr RenderRuntimeDeps() {
735 auto res = std::make_unique<base::ListValue>();
736
737 const Target* previous_from = NULL;
738 for (const auto& pair : ComputeRuntimeDeps(target_)) {
739 std::string str;
740 if (blame_) {
741 // Generally a target's runtime deps will be listed sequentially, so
742 // group them and don't duplicate the "from" label for two in a row.
743 if (previous_from == pair.second) {
744 str = " ";
745 } else {
746 previous_from = pair.second;
747 res->AppendString(
748 str + "From " +
749 pair.second->label().GetUserVisibleName(GetToolchainLabel()));
750 str = " ";
751 }
752 }
753
754 res->AppendString(str + pair.first.value());
755 }
756
757 return res;
758 }
759
FillInSourceOutputs(base::DictionaryValue * res)760 void FillInSourceOutputs(base::DictionaryValue* res) {
761 // Only include "source outputs" if there are sources that map to outputs.
762 // Things like actions have constant per-target outputs that don't depend on
763 // the list of sources. These don't need source outputs.
764 if (target_->output_type() != Target::ACTION_FOREACH &&
765 target_->output_type() != Target::COPY_FILES && !target_->IsBinary())
766 return; // Everything else has constant outputs.
767
768 // "copy" targets may have patterns or not. If there's only one file, the
769 // user can specify a constant output name.
770 if (target_->output_type() == Target::COPY_FILES &&
771 target_->action_values().outputs().required_types().empty())
772 return; // Constant output.
773
774 auto dict = std::make_unique<base::DictionaryValue>();
775 for (const auto& source : target_->sources()) {
776 std::vector<OutputFile> outputs;
777 const char* tool_name = Tool::kToolNone;
778 if (target_->GetOutputFilesForSource(source, &tool_name, &outputs)) {
779 auto list = std::make_unique<base::ListValue>();
780 for (const auto& output : outputs)
781 list->AppendString(output.value());
782
783 dict->SetWithoutPathExpansion(source.value(), std::move(list));
784 }
785 }
786 res->SetWithoutPathExpansion("source_outputs", std::move(dict));
787 }
788
FillInBundle(base::DictionaryValue * res)789 void FillInBundle(base::DictionaryValue* res) {
790 auto data = std::make_unique<base::DictionaryValue>();
791 const BundleData& bundle_data = target_->bundle_data();
792 const Settings* settings = target_->settings();
793 BundleData::SourceFiles sources;
794 bundle_data.GetSourceFiles(&sources);
795 data->SetWithoutPathExpansion("source_files", RenderValue(sources));
796 data->SetKey(
797 "root_dir_output",
798 base::Value(bundle_data.GetBundleRootDirOutput(settings).value()));
799 data->SetWithoutPathExpansion("root_dir",
800 RenderValue(bundle_data.root_dir()));
801 data->SetWithoutPathExpansion("resources_dir",
802 RenderValue(bundle_data.resources_dir()));
803 data->SetWithoutPathExpansion("executable_dir",
804 RenderValue(bundle_data.executable_dir()));
805 data->SetKey("product_type", base::Value(bundle_data.product_type()));
806 data->SetWithoutPathExpansion(
807 "partial_info_plist", RenderValue(bundle_data.partial_info_plist()));
808
809 auto deps = std::make_unique<base::ListValue>();
810 for (const auto* dep : bundle_data.bundle_deps())
811 deps->AppendString(dep->label().GetUserVisibleName(GetToolchainLabel()));
812
813 data->SetWithoutPathExpansion("deps", std::move(deps));
814 res->SetWithoutPathExpansion("bundle_data", std::move(data));
815 }
816
FillInOutputs(base::DictionaryValue * res)817 void FillInOutputs(base::DictionaryValue* res) {
818 std::vector<SourceFile> output_files;
819 Err err;
820 if (!target_->GetOutputsAsSourceFiles(LocationRange(), true, &output_files,
821 &err)) {
822 err.PrintToStdout();
823 return;
824 }
825 res->SetWithoutPathExpansion(variables::kOutputs,
826 RenderValue(output_files));
827
828 // Write some extra data for certain output types.
829 if (target_->output_type() == Target::ACTION_FOREACH ||
830 target_->output_type() == Target::COPY_FILES) {
831 const SubstitutionList& outputs = target_->action_values().outputs();
832 if (!outputs.required_types().empty()) {
833 // Write out the output patterns if there are any.
834 auto patterns = std::make_unique<base::ListValue>();
835 for (const auto& elem : outputs.list())
836 patterns->AppendString(elem.AsString());
837
838 res->SetWithoutPathExpansion("output_patterns", std::move(patterns));
839 }
840 }
841 }
842
843 // Writes a given config value type to the string, optionally with
844 // attribution.
845 // This should match RecursiveTargetConfigToStream in the order it traverses.
846 template <class T>
RenderConfigValues(RecursiveWriterConfig writer_config,const std::vector<T> & (ConfigValues::* getter)()const)847 ValuePtr RenderConfigValues(RecursiveWriterConfig writer_config,
848 const std::vector<T>& (ConfigValues::*getter)()
849 const) {
850 std::set<T> seen;
851 auto res = std::make_unique<base::ListValue>();
852 for (ConfigValuesIterator iter(target_); !iter.done(); iter.Next()) {
853 const std::vector<T>& vec = (iter.cur().*getter)();
854
855 if (vec.empty())
856 continue;
857
858 if (blame_) {
859 const Config* config = iter.GetCurrentConfig();
860 if (config) {
861 // Source of this value is a config.
862 std::string from =
863 "From " + config->label().GetUserVisibleName(false);
864 res->AppendString(from);
865 if (iter.origin()) {
866 Location location = iter.origin()->GetRange().begin();
867 from = " (Added by " + location.file()->name().value() + ":" +
868 base::IntToString(location.line_number()) + ")";
869 res->AppendString(from);
870 }
871 } else {
872 // Source of this value is the target itself.
873 std::string from =
874 "From " + target_->label().GetUserVisibleName(false);
875 res->AppendString(from);
876 }
877 }
878
879 // If blame is on, then do not de-dup across configs.
880 if (blame_)
881 seen.clear();
882
883 for (const T& val : vec) {
884 switch (writer_config) {
885 case kRecursiveWriterKeepDuplicates:
886 break;
887
888 case kRecursiveWriterSkipDuplicates: {
889 if (seen.find(val) != seen.end())
890 continue;
891
892 seen.insert(val);
893 break;
894 }
895 }
896
897 ValuePtr rendered = RenderValue(val);
898 std::string str;
899 // Indent string values in blame mode
900 if (blame_ && rendered->GetAsString(&str)) {
901 str = " " + str;
902 rendered = std::make_unique<base::Value>(str);
903 }
904 res->Append(std::move(rendered));
905 }
906 }
907 return res->empty() ? nullptr : std::move(res);
908 }
909
GetToolchainLabel() const910 Label GetToolchainLabel() const override {
911 return target_->label().GetToolchainLabel();
912 }
913
914 const Target* target_;
915 };
916
917 } // namespace
918
DescriptionForTarget(const Target * target,const std::string & what,bool all,bool tree,bool blame)919 std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForTarget(
920 const Target* target,
921 const std::string& what,
922 bool all,
923 bool tree,
924 bool blame) {
925 std::set<std::string> w;
926 if (!what.empty())
927 w.insert(what);
928 TargetDescBuilder b(target, w, all, tree, blame);
929 return b.BuildDescription();
930 }
931
DescriptionForConfig(const Config * config,const std::string & what)932 std::unique_ptr<base::DictionaryValue> DescBuilder::DescriptionForConfig(
933 const Config* config,
934 const std::string& what) {
935 std::set<std::string> w;
936 if (!what.empty())
937 w.insert(what);
938 ConfigDescBuilder b(config, w);
939 return b.BuildDescription();
940 }
941