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