Add ICU message format support
[chromium-blink-merge.git] / tools / gn / target_generator.cc
blobcd633f200018d9d5bda1ed6813a7a78d88c0e47a
1 // Copyright (c) 2013 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.
5 #include "tools/gn/target_generator.h"
7 #include "tools/gn/action_target_generator.h"
8 #include "tools/gn/binary_target_generator.h"
9 #include "tools/gn/build_settings.h"
10 #include "tools/gn/config.h"
11 #include "tools/gn/copy_target_generator.h"
12 #include "tools/gn/err.h"
13 #include "tools/gn/filesystem_utils.h"
14 #include "tools/gn/functions.h"
15 #include "tools/gn/group_target_generator.h"
16 #include "tools/gn/parse_tree.h"
17 #include "tools/gn/scheduler.h"
18 #include "tools/gn/scope.h"
19 #include "tools/gn/token.h"
20 #include "tools/gn/value.h"
21 #include "tools/gn/value_extractors.h"
22 #include "tools/gn/variables.h"
24 TargetGenerator::TargetGenerator(Target* target,
25 Scope* scope,
26 const FunctionCallNode* function_call,
27 Err* err)
28 : target_(target),
29 scope_(scope),
30 function_call_(function_call),
31 err_(err) {
34 TargetGenerator::~TargetGenerator() {
37 void TargetGenerator::Run() {
38 // All target types use these.
39 if (!FillDependentConfigs())
40 return;
42 if (!FillData())
43 return;
45 if (!FillDependencies())
46 return;
48 if (!FillTestonly())
49 return;
51 if (!Visibility::FillItemVisibility(target_, scope_, err_))
52 return;
54 // Do type-specific generation.
55 DoRun();
58 // static
59 void TargetGenerator::GenerateTarget(Scope* scope,
60 const FunctionCallNode* function_call,
61 const std::vector<Value>& args,
62 const std::string& output_type,
63 Err* err) {
64 // Name is the argument to the function.
65 if (args.size() != 1u || args[0].type() != Value::STRING) {
66 *err = Err(function_call,
67 "Target generator requires one string argument.",
68 "Otherwise I'm not sure what to call this target.");
69 return;
72 // The location of the target is the directory name with no slash at the end.
73 // FIXME(brettw) validate name.
74 const Label& toolchain_label = ToolchainLabelForScope(scope);
75 Label label(scope->GetSourceDir(), args[0].string_value(),
76 toolchain_label.dir(), toolchain_label.name());
78 if (g_scheduler->verbose_logging())
79 g_scheduler->Log("Defining target", label.GetUserVisibleName(true));
81 scoped_ptr<Target> target(new Target(scope->settings(), label));
82 target->set_defined_from(function_call);
84 // Create and call out to the proper generator.
85 if (output_type == functions::kCopy) {
86 CopyTargetGenerator generator(target.get(), scope, function_call, err);
87 generator.Run();
88 } else if (output_type == functions::kAction) {
89 ActionTargetGenerator generator(target.get(), scope, function_call,
90 Target::ACTION, err);
91 generator.Run();
92 } else if (output_type == functions::kActionForEach) {
93 ActionTargetGenerator generator(target.get(), scope, function_call,
94 Target::ACTION_FOREACH, err);
95 generator.Run();
96 } else if (output_type == functions::kExecutable) {
97 BinaryTargetGenerator generator(target.get(), scope, function_call,
98 Target::EXECUTABLE, err);
99 generator.Run();
100 } else if (output_type == functions::kGroup) {
101 GroupTargetGenerator generator(target.get(), scope, function_call, err);
102 generator.Run();
103 } else if (output_type == functions::kSharedLibrary) {
104 BinaryTargetGenerator generator(target.get(), scope, function_call,
105 Target::SHARED_LIBRARY, err);
106 generator.Run();
107 } else if (output_type == functions::kSourceSet) {
108 BinaryTargetGenerator generator(target.get(), scope, function_call,
109 Target::SOURCE_SET, err);
110 generator.Run();
111 } else if (output_type == functions::kStaticLibrary) {
112 BinaryTargetGenerator generator(target.get(), scope, function_call,
113 Target::STATIC_LIBRARY, err);
114 generator.Run();
115 } else {
116 *err = Err(function_call, "Not a known target type",
117 "I am very confused by the target type \"" + output_type + "\"");
120 if (err->has_error())
121 return;
123 // Save this target for the file.
124 Scope::ItemVector* collector = scope->GetItemCollector();
125 if (!collector) {
126 *err = Err(function_call, "Can't define a target in this context.");
127 return;
129 collector->push_back(target.release());
132 const BuildSettings* TargetGenerator::GetBuildSettings() const {
133 return scope_->settings()->build_settings();
136 bool TargetGenerator::FillSources() {
137 const Value* value = scope_->GetValue(variables::kSources, true);
138 if (!value)
139 return true;
141 Target::FileList dest_sources;
142 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
143 scope_->GetSourceDir(), &dest_sources, err_))
144 return false;
145 target_->sources().swap(dest_sources);
146 return true;
149 bool TargetGenerator::FillPublic() {
150 const Value* value = scope_->GetValue(variables::kPublic, true);
151 if (!value)
152 return true;
154 // If the public headers are defined, don't default to public.
155 target_->set_all_headers_public(false);
157 Target::FileList dest_public;
158 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
159 scope_->GetSourceDir(), &dest_public, err_))
160 return false;
161 target_->public_headers().swap(dest_public);
162 return true;
165 bool TargetGenerator::FillInputs() {
166 const Value* value = scope_->GetValue(variables::kInputs, true);
167 if (!value)
168 return true;
170 Target::FileList dest_inputs;
171 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
172 scope_->GetSourceDir(), &dest_inputs, err_))
173 return false;
174 target_->inputs().swap(dest_inputs);
175 return true;
178 bool TargetGenerator::FillConfigs() {
179 return FillGenericConfigs(variables::kConfigs, &target_->configs());
182 bool TargetGenerator::FillDependentConfigs() {
183 if (!FillGenericConfigs(variables::kAllDependentConfigs,
184 &target_->all_dependent_configs()))
185 return false;
186 if (!FillGenericConfigs(variables::kPublicConfigs,
187 &target_->public_configs()))
188 return false;
190 // "public_configs" was previously named "direct_dependent_configs", fall
191 // back to that if public_configs was undefined.
192 if (!scope_->GetValue(variables::kPublicConfigs, false)) {
193 if (!FillGenericConfigs("direct_dependent_configs",
194 &target_->public_configs()))
195 return false;
197 return true;
200 bool TargetGenerator::FillData() {
201 const Value* value = scope_->GetValue(variables::kData, true);
202 if (!value)
203 return true;
204 if (!value->VerifyTypeIs(Value::LIST, err_))
205 return false;
207 const std::vector<Value>& input_list = value->list_value();
208 std::vector<std::string>& output_list = target_->data();
209 output_list.reserve(input_list.size());
211 const SourceDir& dir = scope_->GetSourceDir();
212 const std::string& root_path =
213 scope_->settings()->build_settings()->root_path_utf8();
215 for (size_t i = 0; i < input_list.size(); i++) {
216 const Value& input = input_list[i];
217 if (!input.VerifyTypeIs(Value::STRING, err_))
218 return false;
219 const std::string& input_str = input.string_value();
221 // Treat each input as either a file or a directory, depending on the
222 // last character.
223 if (!input_str.empty() && input_str[input_str.size() - 1] == '/') {
224 // Resolve as directory.
225 SourceDir resolved =
226 dir.ResolveRelativeDir(input, input_str, err_, root_path);
227 if (err_->has_error())
228 return false;
229 output_list.push_back(resolved.value());
230 } else {
231 // Resolve as file.
232 SourceFile resolved = dir.ResolveRelativeFile(input, err_, root_path);
233 if (err_->has_error())
234 return false;
235 output_list.push_back(resolved.value());
238 return true;
241 bool TargetGenerator::FillDependencies() {
242 if (!FillGenericDeps(variables::kDeps, &target_->private_deps()))
243 return false;
244 if (!FillGenericDeps(variables::kPublicDeps, &target_->public_deps()))
245 return false;
246 if (!FillGenericDeps(variables::kDataDeps, &target_->data_deps()))
247 return false;
249 // "data_deps" was previously named "datadeps". For backwards-compat, read
250 // the old one if no "data_deps" were specified.
251 if (!scope_->GetValue(variables::kDataDeps, false)) {
252 if (!FillGenericDeps("datadeps", &target_->data_deps()))
253 return false;
256 // This is a list of dependent targets to have their configs fowarded, so
257 // it goes here rather than in FillConfigs.
258 if (!FillForwardDependentConfigs())
259 return false;
260 return true;
263 bool TargetGenerator::FillTestonly() {
264 const Value* value = scope_->GetValue(variables::kTestonly, true);
265 if (value) {
266 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
267 return false;
268 target_->set_testonly(value->boolean_value());
270 return true;
273 bool TargetGenerator::FillOutputs(bool allow_substitutions) {
274 const Value* value = scope_->GetValue(variables::kOutputs, true);
275 if (!value)
276 return true;
278 SubstitutionList& outputs = target_->action_values().outputs();
279 if (!outputs.Parse(*value, err_))
280 return false;
282 if (!allow_substitutions) {
283 // Verify no substitutions were actually used.
284 if (!outputs.required_types().empty()) {
285 *err_ = Err(*value, "Source expansions not allowed here.",
286 "The outputs of this target used source {{expansions}} but this "
287 "targe type\ndoesn't support them. Just express the outputs "
288 "literally.");
289 return false;
293 // Check the substitutions used are valid for this purpose.
294 if (!EnsureValidSourcesSubstitutions(outputs.required_types(),
295 value->origin(), err_))
296 return false;
298 // Validate that outputs are in the output dir.
299 CHECK(outputs.list().size() == value->list_value().size());
300 for (size_t i = 0; i < outputs.list().size(); i++) {
301 if (!EnsureSubstitutionIsInOutputDir(outputs.list()[i],
302 value->list_value()[i]))
303 return false;
305 return true;
308 bool TargetGenerator::FillCheckIncludes() {
309 const Value* value = scope_->GetValue(variables::kCheckIncludes, true);
310 if (!value)
311 return true;
312 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
313 return false;
314 target_->set_check_includes(value->boolean_value());
315 return true;
318 bool TargetGenerator::EnsureSubstitutionIsInOutputDir(
319 const SubstitutionPattern& pattern,
320 const Value& original_value) {
321 if (pattern.ranges().empty()) {
322 // Pattern is empty, error out (this prevents weirdness below).
323 *err_ = Err(original_value, "This has an empty value in it.");
324 return false;
327 if (pattern.ranges()[0].type == SUBSTITUTION_LITERAL) {
328 // If the first thing is a literal, it must start with the output dir.
329 if (!EnsureStringIsInOutputDir(
330 GetBuildSettings()->build_dir(),
331 pattern.ranges()[0].literal, original_value.origin(), err_))
332 return false;
333 } else {
334 // Otherwise, the first subrange must be a pattern that expands to
335 // something in the output directory.
336 if (!SubstitutionIsInOutputDir(pattern.ranges()[0].type)) {
337 *err_ = Err(original_value,
338 "File is not inside output directory.",
339 "The given file should be in the output directory. Normally you\n"
340 "would specify\n\"$target_out_dir/foo\" or "
341 "\"{{source_gen_dir}}/foo\".");
342 return false;
346 return true;
349 bool TargetGenerator::FillGenericConfigs(const char* var_name,
350 UniqueVector<LabelConfigPair>* dest) {
351 const Value* value = scope_->GetValue(var_name, true);
352 if (value) {
353 ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(),
354 ToolchainLabelForScope(scope_), dest, err_);
356 return !err_->has_error();
359 bool TargetGenerator::FillGenericDeps(const char* var_name,
360 LabelTargetVector* dest) {
361 const Value* value = scope_->GetValue(var_name, true);
362 if (value) {
363 ExtractListOfLabels(*value, scope_->GetSourceDir(),
364 ToolchainLabelForScope(scope_), dest, err_);
366 return !err_->has_error();
369 bool TargetGenerator::FillForwardDependentConfigs() {
370 const Value* value = scope_->GetValue(
371 variables::kForwardDependentConfigsFrom, true);
372 if (value) {
373 ExtractListOfUniqueLabels(*value, scope_->GetSourceDir(),
374 ToolchainLabelForScope(scope_),
375 &target_->forward_dependent_configs(), err_);
377 return !err_->has_error();