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
,
28 const Token
& function_token
,
32 function_token_(function_token
),
36 TargetGenerator::~TargetGenerator() {
39 void TargetGenerator::Run() {
40 // All target types use these.
41 FillDependentConfigs();
46 // To type-specific generation.
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_
);
58 void TargetGenerator::GenerateTarget(Scope
* scope
,
59 const Token
& function_token
,
60 const std::vector
<Value
>& args
,
61 const std::string
& output_type
,
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.");
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));
81 scope
->settings()->build_settings()->target_manager().GetTarget(
82 label
, function_token
.range(), NULL
, err
);
86 // Create and call out to the proper generator.
87 if (output_type
== functions::kCopy
) {
88 CopyTargetGenerator
generator(target
, scope
, function_token
, err
);
90 } else if (output_type
== functions::kCustom
) {
91 ScriptTargetGenerator
generator(target
, scope
, function_token
, err
);
93 } else if (output_type
== functions::kExecutable
) {
94 BinaryTargetGenerator
generator(target
, scope
, function_token
,
95 Target::EXECUTABLE
, err
);
97 } else if (output_type
== functions::kGroup
) {
98 GroupTargetGenerator
generator(target
, scope
, function_token
, err
);
100 } else if (output_type
== functions::kSharedLibrary
) {
101 BinaryTargetGenerator
generator(target
, scope
, function_token
,
102 Target::SHARED_LIBRARY
, err
);
104 } else if (output_type
== functions::kSourceSet
) {
105 BinaryTargetGenerator
generator(target
, scope
, function_token
,
106 Target::SOURCE_SET
, err
);
108 } else if (output_type
== functions::kStaticLibrary
) {
109 BinaryTargetGenerator
generator(target
, scope
, function_token
,
110 Target::STATIC_LIBRARY
, err
);
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);
127 Target::FileList dest_sources
;
128 if (!ExtractListOfRelativeFiles(scope_
->settings()->build_settings(), *value
,
129 scope_
->GetSourceDir(), &dest_sources
, err_
))
131 target_
->sources().swap(dest_sources
);
134 void TargetGenerator::FillSourcePrereqs() {
135 const Value
* value
= scope_
->GetValue(variables::kSourcePrereqs
, true);
139 Target::FileList dest_reqs
;
140 if (!ExtractListOfRelativeFiles(scope_
->settings()->build_settings(), *value
,
141 scope_
->GetSourceDir(), &dest_reqs
, err_
))
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);
164 Target::FileList dest_data
;
165 if (!ExtractListOfRelativeFiles(scope_
->settings()->build_settings(), *value
,
166 scope_
->GetSourceDir(), &dest_data
, err_
))
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();
182 void TargetGenerator::FillGypFile() {
183 const Value
* gyp_file_value
= scope_
->GetValue(variables::kGypFile
, true);
186 if (!gyp_file_value
->VerifyTypeIs(Value::STRING
, err_
))
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);
197 if (!hard_dep_value
->VerifyTypeIs(Value::BOOLEAN
, err_
))
199 target_
->set_hard_dep(hard_dep_value
->boolean_value());
202 void TargetGenerator::FillExternal() {
203 const Value
* value
= scope_
->GetValue(variables::kExternal
, true);
206 if (!value
->VerifyTypeIs(Value::BOOLEAN
, err_
))
208 target_
->set_external(value
->boolean_value());
211 void TargetGenerator::FillOutputs() {
212 const Value
* value
= scope_
->GetValue(variables::kOutputs
, true);
216 Target::FileList outputs
;
217 if (!ExtractListOfRelativeFiles(scope_
->settings()->build_settings(), *value
,
218 scope_
->GetSourceDir(), &outputs
, err_
))
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_
))
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());
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);
248 if (!ExtractListOfLabels(*value
, scope_
->GetSourceDir(),
249 ToolchainLabelForScope(scope_
), dest
, err_
))
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())
262 void TargetGenerator::FillGenericDeps(const char* var_name
,
263 LabelTargetVector
* dest
) {
264 const Value
* value
= scope_
->GetValue(var_name
, true);
267 if (!ExtractListOfLabels(*value
, scope_
->GetSourceDir(),
268 ToolchainLabelForScope(scope_
), dest
, err_
))
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())
280 void TargetGenerator::FillForwardDependentConfigs() {
281 const Value
* value
= scope_
->GetValue(
282 variables::kForwardDependentConfigsFrom
, true);
286 LabelTargetVector
& dest
= target_
->forward_dependent_configs();
287 if (!ExtractListOfLabels(*value
, scope_
->GetSourceDir(),
288 ToolchainLabelForScope(scope_
), &dest
, err_
))
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
;
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.");