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