Correct blacklist entry message
[chromium-blink-merge.git] / tools / gn / target_generator.cc
blob3bb51eb9863c6c9855ef8ff0a9241d5c46cb44de
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/binary_target_generator.h"
8 #include "tools/gn/build_settings.h"
9 #include "tools/gn/config.h"
10 #include "tools/gn/copy_target_generator.h"
11 #include "tools/gn/err.h"
12 #include "tools/gn/filesystem_utils.h"
13 #include "tools/gn/functions.h"
14 #include "tools/gn/group_target_generator.h"
15 #include "tools/gn/item_node.h"
16 #include "tools/gn/parse_tree.h"
17 #include "tools/gn/scheduler.h"
18 #include "tools/gn/scope.h"
19 #include "tools/gn/script_target_generator.h"
20 #include "tools/gn/target_manager.h"
21 #include "tools/gn/token.h"
22 #include "tools/gn/value.h"
23 #include "tools/gn/value_extractors.h"
24 #include "tools/gn/variables.h"
26 TargetGenerator::TargetGenerator(Target* target,
27 Scope* scope,
28 const Token& function_token,
29 Err* err)
30 : target_(target),
31 scope_(scope),
32 function_token_(function_token),
33 err_(err) {
36 TargetGenerator::~TargetGenerator() {
39 void TargetGenerator::Run() {
40 // All target types use these.
41 FillDependentConfigs();
42 FillData();
43 FillDependencies();
44 FillGypFile();
46 // To type-specific generation.
47 DoRun();
49 // Mark the target as complete.
50 if (!err_->has_error()) {
51 target_->SetGenerated(&function_token_);
52 GetBuildSettings()->target_manager().TargetGenerationComplete(
53 target_->label(), err_);
57 // static
58 void TargetGenerator::GenerateTarget(Scope* scope,
59 const Token& function_token,
60 const std::vector<Value>& args,
61 const std::string& output_type,
62 Err* err) {
63 // Name is the argument to the function.
64 if (args.size() != 1u || args[0].type() != Value::STRING) {
65 *err = Err(function_token,
66 "Target generator requires one string argument.",
67 "Otherwise I'm not sure what to call this target.");
68 return;
71 // The location of the target is the directory name with no slash at the end.
72 // FIXME(brettw) validate name.
73 const Label& toolchain_label = ToolchainLabelForScope(scope);
74 Label label(scope->GetSourceDir(), args[0].string_value(),
75 toolchain_label.dir(), toolchain_label.name());
77 if (g_scheduler->verbose_logging())
78 g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
80 Target* target =
81 scope->settings()->build_settings()->target_manager().GetTarget(
82 label, function_token.range(), NULL, err);
83 if (err->has_error())
84 return;
86 // Create and call out to the proper generator.
87 if (output_type == functions::kCopy) {
88 CopyTargetGenerator generator(target, scope, function_token, err);
89 generator.Run();
90 } else if (output_type == functions::kCustom) {
91 ScriptTargetGenerator generator(target, scope, function_token, err);
92 generator.Run();
93 } else if (output_type == functions::kExecutable) {
94 BinaryTargetGenerator generator(target, scope, function_token,
95 Target::EXECUTABLE, err);
96 generator.Run();
97 } else if (output_type == functions::kGroup) {
98 GroupTargetGenerator generator(target, scope, function_token, err);
99 generator.Run();
100 } else if (output_type == functions::kSharedLibrary) {
101 BinaryTargetGenerator generator(target, scope, function_token,
102 Target::SHARED_LIBRARY, err);
103 generator.Run();
104 } else if (output_type == functions::kSourceSet) {
105 BinaryTargetGenerator generator(target, scope, function_token,
106 Target::SOURCE_SET, err);
107 generator.Run();
108 } else if (output_type == functions::kStaticLibrary) {
109 BinaryTargetGenerator generator(target, scope, function_token,
110 Target::STATIC_LIBRARY, err);
111 generator.Run();
112 } else {
113 *err = Err(function_token, "Not a known output type",
114 "I am very confused.");
118 const BuildSettings* TargetGenerator::GetBuildSettings() const {
119 return scope_->settings()->build_settings();
122 void TargetGenerator::FillSources() {
123 const Value* value = scope_->GetValue(variables::kSources, true);
124 if (!value)
125 return;
127 Target::FileList dest_sources;
128 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
129 scope_->GetSourceDir(), &dest_sources, err_))
130 return;
131 target_->sources().swap(dest_sources);
134 void TargetGenerator::FillSourcePrereqs() {
135 const Value* value = scope_->GetValue(variables::kSourcePrereqs, true);
136 if (!value)
137 return;
139 Target::FileList dest_reqs;
140 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
141 scope_->GetSourceDir(), &dest_reqs, err_))
142 return;
143 target_->source_prereqs().swap(dest_reqs);
146 void TargetGenerator::FillConfigs() {
147 FillGenericConfigs(variables::kConfigs, &target_->configs());
150 void TargetGenerator::FillDependentConfigs() {
151 FillGenericConfigs(variables::kAllDependentConfigs,
152 &target_->all_dependent_configs());
153 FillGenericConfigs(variables::kDirectDependentConfigs,
154 &target_->direct_dependent_configs());
157 void TargetGenerator::FillData() {
158 // TODO(brettW) hook this up to the constant when we have cleaned up
159 // how data files are used.
160 const Value* value = scope_->GetValue(variables::kData, true);
161 if (!value)
162 return;
164 Target::FileList dest_data;
165 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
166 scope_->GetSourceDir(), &dest_data, err_))
167 return;
168 target_->data().swap(dest_data);
171 void TargetGenerator::FillDependencies() {
172 FillGenericDeps(variables::kDeps, &target_->deps());
173 FillGenericDeps(variables::kDatadeps, &target_->datadeps());
175 // This is a list of dependent targets to have their configs fowarded, so
176 // it goes here rather than in FillConfigs.
177 FillForwardDependentConfigs();
179 FillHardDep();
182 void TargetGenerator::FillGypFile() {
183 const Value* gyp_file_value = scope_->GetValue(variables::kGypFile, true);
184 if (!gyp_file_value)
185 return;
186 if (!gyp_file_value->VerifyTypeIs(Value::STRING, err_))
187 return;
189 target_->set_gyp_file(scope_->GetSourceDir().ResolveRelativeFile(
190 gyp_file_value->string_value()));
193 void TargetGenerator::FillHardDep() {
194 const Value* hard_dep_value = scope_->GetValue(variables::kHardDep, true);
195 if (!hard_dep_value)
196 return;
197 if (!hard_dep_value->VerifyTypeIs(Value::BOOLEAN, err_))
198 return;
199 target_->set_hard_dep(hard_dep_value->boolean_value());
202 void TargetGenerator::FillExternal() {
203 const Value* value = scope_->GetValue(variables::kExternal, true);
204 if (!value)
205 return;
206 if (!value->VerifyTypeIs(Value::BOOLEAN, err_))
207 return;
208 target_->set_external(value->boolean_value());
211 void TargetGenerator::FillOutputs() {
212 const Value* value = scope_->GetValue(variables::kOutputs, true);
213 if (!value)
214 return;
216 Target::FileList outputs;
217 if (!ExtractListOfRelativeFiles(scope_->settings()->build_settings(), *value,
218 scope_->GetSourceDir(), &outputs, err_))
219 return;
221 // Validate that outputs are in the output dir.
222 CHECK(outputs.size() == value->list_value().size());
223 for (size_t i = 0; i < outputs.size(); i++) {
224 if (!EnsureStringIsInOutputDir(
225 GetBuildSettings()->build_dir(),
226 outputs[i].value(), value->list_value()[i], err_))
227 return;
229 target_->script_values().outputs().swap(outputs);
232 void TargetGenerator::SetToolchainDependency() {
233 // TODO(brettw) currently we lock separately for each config, dep, and
234 // toolchain we add which is bad! Do this in one lock.
235 ItemTree* tree = &GetBuildSettings()->item_tree();
236 base::AutoLock lock(tree->lock());
237 ItemNode* tc_node =
238 tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
239 target_->item_node()->AddDependency(
240 GetBuildSettings(), function_token_.range(), tc_node, err_);
243 void TargetGenerator::FillGenericConfigs(const char* var_name,
244 LabelConfigVector* dest) {
245 const Value* value = scope_->GetValue(var_name, true);
246 if (!value)
247 return;
248 if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
249 ToolchainLabelForScope(scope_), dest, err_))
250 return;
252 for (size_t i = 0; i < dest->size(); i++) {
253 LabelConfigPair& cur = (*dest)[i];
254 cur.ptr = Config::GetConfig(scope_->settings(),
255 value->list_value()[i].origin()->GetRange(),
256 cur.label, target_, err_);
257 if (err_->has_error())
258 return;
262 void TargetGenerator::FillGenericDeps(const char* var_name,
263 LabelTargetVector* dest) {
264 const Value* value = scope_->GetValue(var_name, true);
265 if (!value)
266 return;
267 if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
268 ToolchainLabelForScope(scope_), dest, err_))
269 return;
271 for (size_t i = 0; i < dest->size(); i++) {
272 LabelTargetPair& cur = (*dest)[i];
273 cur.ptr = GetBuildSettings()->target_manager().GetTarget(
274 cur.label, value->list_value()[i].origin()->GetRange(), target_, err_);
275 if (err_->has_error())
276 return;
280 void TargetGenerator::FillForwardDependentConfigs() {
281 const Value* value = scope_->GetValue(
282 variables::kForwardDependentConfigsFrom, true);
283 if (!value)
284 return;
286 LabelTargetVector& dest = target_->forward_dependent_configs();
287 if (!ExtractListOfLabels(*value, scope_->GetSourceDir(),
288 ToolchainLabelForScope(scope_), &dest, err_))
289 return;
291 // We currently assume that the list is very small and do a brute-force
292 // search in the deps for the labeled target. This could be optimized.
293 const LabelTargetVector& deps = target_->deps();
294 std::vector<const Target*> forward_from_list;
295 for (size_t dest_index = 0; dest_index < dest.size(); dest_index++) {
296 LabelTargetPair& cur_dest = dest[dest_index];
297 for (size_t dep_index = 0; dep_index < deps.size(); dep_index++) {
298 if (deps[dep_index].label == cur_dest.label) {
299 cur_dest.ptr = deps[dep_index].ptr;
300 break;
303 if (!cur_dest.ptr) {
304 *err_ = Err(cur_dest.origin,
305 "Can't forward from this target.",
306 "forward_dependent_configs_from must contain a list of labels that\n"
307 "must all appear in the deps of the same target.");
308 return;