Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Side by Side Diff: tools/gn/target_generator.cc

Issue 21114002: Add initial prototype for the GN meta-buildsystem. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add owners and readme Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/gn/target_generator.h ('k') | tools/gn/target_generator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "tools/gn/target_generator.h"
6
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "tools/gn/build_settings.h"
10 #include "tools/gn/config.h"
11 #include "tools/gn/config_values_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/input_file.h"
16 #include "tools/gn/item_node.h"
17 #include "tools/gn/ninja_target_writer.h"
18 #include "tools/gn/parse_tree.h"
19 #include "tools/gn/scheduler.h"
20 #include "tools/gn/scope.h"
21 #include "tools/gn/target_manager.h"
22 #include "tools/gn/token.h"
23 #include "tools/gn/value.h"
24 #include "tools/gn/value_extractors.h"
25
26 namespace {
27
28 bool TypeHasConfigs(Target::OutputType type) {
29 return type == Target::EXECUTABLE ||
30 type == Target::SHARED_LIBRARY ||
31 type == Target::STATIC_LIBRARY ||
32 type == Target::LOADABLE_MODULE;
33 }
34
35 bool TypeHasConfigValues(Target::OutputType type) {
36 return type == Target::EXECUTABLE ||
37 type == Target::SHARED_LIBRARY ||
38 type == Target::STATIC_LIBRARY ||
39 type == Target::LOADABLE_MODULE;
40 }
41
42 bool TypeHasSources(Target::OutputType type) {
43 return type != Target::NONE;
44 }
45
46 bool TypeHasData(Target::OutputType type) {
47 return type != Target::NONE;
48 }
49
50 bool TypeHasDestDir(Target::OutputType type) {
51 return type == Target::COPY_FILES;
52 }
53
54 bool TypeHasOutputs(Target::OutputType type) {
55 return type == Target::CUSTOM;
56 }
57
58 } // namespace
59
60 TargetGenerator::TargetGenerator(Target* target,
61 Scope* scope,
62 const Token& function_token,
63 const std::vector<Value>& args,
64 const std::string& output_type,
65 Err* err)
66 : target_(target),
67 scope_(scope),
68 function_token_(function_token),
69 args_(args),
70 output_type_(output_type),
71 err_(err),
72 input_directory_(function_token.location().file()->dir()) {
73 }
74
75 TargetGenerator::~TargetGenerator() {
76 }
77
78 void TargetGenerator::Run() {
79 // Output type.
80 Target::OutputType output_type = GetOutputType();
81 target_->set_output_type(output_type);
82 if (err_->has_error())
83 return;
84
85 if (TypeHasConfigs(output_type)) {
86 FillConfigs();
87 FillAllDependentConfigs();
88 FillDirectDependentConfigs();
89 }
90 if (TypeHasSources(output_type))
91 FillSources();
92 if (TypeHasData(output_type))
93 FillData();
94 if (output_type == Target::CUSTOM) {
95 FillScript();
96 FillScriptArgs();
97 }
98 if (TypeHasOutputs(output_type))
99 FillOutputs();
100 FillDependencies(); // All types have dependencies.
101
102 if (TypeHasConfigValues(output_type)) {
103 ConfigValuesGenerator gen(&target_->config_values(), scope_,
104 function_token_, input_directory_, err_);
105 gen.Run();
106 if (err_->has_error())
107 return;
108 }
109
110 if (TypeHasDestDir(output_type))
111 FillDestDir();
112
113 // Set the toolchain as a dependency of the target.
114 // TODO(brettw) currently we lock separately for each config, dep, and
115 // toolchain we add which is bad! Do this in one lock.
116 {
117 ItemTree* tree = &GetBuildSettings()->item_tree();
118 base::AutoLock lock(tree->lock());
119 ItemNode* tc_node =
120 tree->GetExistingNodeLocked(ToolchainLabelForScope(scope_));
121 tree->GetExistingNodeLocked(target_->label())->AddDependency(tc_node);
122 }
123
124 target_->SetGenerated(&function_token_);
125 GetBuildSettings()->target_manager().TargetGenerationComplete(
126 target_->label());
127 }
128
129 // static
130 void TargetGenerator::GenerateTarget(Scope* scope,
131 const Token& function_token,
132 const std::vector<Value>& args,
133 const std::string& output_type,
134 Err* err) {
135 // Name is the argument to the function.
136 if (args.size() != 1u || args[0].type() != Value::STRING) {
137 *err = Err(function_token,
138 "Target generator requires one string argument.",
139 "Otherwise I'm not sure what to call this target.");
140 return;
141 }
142
143 // The location of the target is the directory name with no slash at the end.
144 // FIXME(brettw) validate name.
145 const Label& toolchain_label = ToolchainLabelForScope(scope);
146 Label label(function_token.location().file()->dir(),
147 args[0].string_value(),
148 toolchain_label.dir(), toolchain_label.name());
149
150 if (g_scheduler->verbose_logging())
151 g_scheduler->Log("Generating target", label.GetUserVisibleName(true));
152
153 Target* t = scope->settings()->build_settings()->target_manager().GetTarget(
154 label, function_token.range(), NULL, err);
155 if (err->has_error())
156 return;
157
158 TargetGenerator gen(t, scope, function_token, args, output_type, err);
159 gen.Run();
160 }
161
162 Target::OutputType TargetGenerator::GetOutputType() const {
163 if (output_type_ == functions::kGroup)
164 return Target::NONE;
165 if (output_type_ == functions::kExecutable)
166 return Target::EXECUTABLE;
167 if (output_type_ == functions::kSharedLibrary)
168 return Target::SHARED_LIBRARY;
169 if (output_type_ == functions::kStaticLibrary)
170 return Target::STATIC_LIBRARY;
171 // TODO(brettw) what does loadable module mean?
172 //if (output_type_ == ???)
173 // return Target::LOADABLE_MODULE;
174 if (output_type_ == functions::kCopy)
175 return Target::COPY_FILES;
176 if (output_type_ == functions::kCustom)
177 return Target::CUSTOM;
178
179 *err_ = Err(function_token_, "Not a known output type",
180 "I am very confused.");
181 return Target::NONE;
182 }
183
184 void TargetGenerator::FillGenericConfigs(
185 const char* var_name,
186 void (Target::*setter)(std::vector<const Config*>*)) {
187 const Value* value = scope_->GetValue(var_name, true);
188 if (!value)
189 return;
190
191 std::vector<Label> labels;
192 if (!ExtractListOfLabels(*value, input_directory_,
193 ToolchainLabelForScope(scope_), &labels, err_))
194 return;
195
196 std::vector<const Config*> dest_configs;
197 dest_configs.resize(labels.size());
198 for (size_t i = 0; i < labels.size(); i++) {
199 dest_configs[i] = Config::GetConfig(
200 scope_->settings(),
201 value->list_value()[i].origin()->GetRange(),
202 labels[i], target_, err_);
203 if (err_->has_error())
204 return;
205 }
206 (target_->*setter)(&dest_configs);
207 }
208
209 void TargetGenerator::FillConfigs() {
210 FillGenericConfigs("configs", &Target::swap_in_configs);
211 }
212
213 void TargetGenerator::FillAllDependentConfigs() {
214 FillGenericConfigs("all_dependent_configs",
215 &Target::swap_in_all_dependent_configs);
216 }
217
218 void TargetGenerator::FillDirectDependentConfigs() {
219 FillGenericConfigs("direct_dependent_configs",
220 &Target::swap_in_direct_dependent_configs);
221 }
222
223 void TargetGenerator::FillSources() {
224 const Value* value = scope_->GetValue("sources", true);
225 if (!value)
226 return;
227
228 Target::FileList dest_sources;
229 if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_sources,
230 err_))
231 return;
232 target_->swap_in_sources(&dest_sources);
233 }
234
235 void TargetGenerator::FillData() {
236 const Value* value = scope_->GetValue("data", true);
237 if (!value)
238 return;
239
240 Target::FileList dest_data;
241 if (!ExtractListOfRelativeFiles(*value, input_directory_, &dest_data,
242 err_))
243 return;
244 target_->swap_in_data(&dest_data);
245 }
246
247 void TargetGenerator::FillDependencies() {
248 const Value* value = scope_->GetValue("deps", true);
249 if (!value)
250 return;
251
252 std::vector<Label> labels;
253 if (!ExtractListOfLabels(*value, input_directory_,
254 ToolchainLabelForScope(scope_), &labels, err_))
255 return;
256
257 std::vector<const Target*> dest_deps;
258 dest_deps.resize(labels.size());
259 for (size_t i = 0; i < labels.size(); i++) {
260 dest_deps[i] = GetBuildSettings()->target_manager().GetTarget(
261 labels[i], value->list_value()[i].origin()->GetRange(), target_, err_);
262 if (err_->has_error())
263 return;
264 }
265
266 target_->swap_in_deps(&dest_deps);
267 }
268
269 void TargetGenerator::FillDestDir() {
270 // Destdir is required for all targets that use it.
271 const Value* value = scope_->GetValue("destdir", true);
272 if (!value) {
273 *err_ = Err(function_token_, "This target type requires a \"destdir\".");
274 return;
275 }
276 if (!value->VerifyTypeIs(Value::STRING, err_))
277 return;
278
279 if (!EnsureStringIsInOutputDir(
280 GetBuildSettings()->build_dir(),
281 value->string_value(), *value, err_))
282 return;
283 target_->set_destdir(SourceDir(value->string_value()));
284 }
285
286 void TargetGenerator::FillScript() {
287 // If this gets called, the target type requires a script, so error out
288 // if it doesn't have one.
289 const Value* value = scope_->GetValue("script", true);
290 if (!value) {
291 *err_ = Err(function_token_, "This target type requires a \"script\".");
292 return;
293 }
294 if (!value->VerifyTypeIs(Value::STRING, err_))
295 return;
296
297 target_->set_script(
298 input_directory_.ResolveRelativeFile(value->string_value()));
299 }
300
301 void TargetGenerator::FillScriptArgs() {
302 const Value* value = scope_->GetValue("args", true);
303 if (!value)
304 return;
305
306 std::vector<std::string> args;
307 if (!ExtractListOfStringValues(*value, &args, err_))
308 return;
309 target_->swap_in_script_args(&args);
310 }
311
312 void TargetGenerator::FillOutputs() {
313 const Value* value = scope_->GetValue("outputs", true);
314 if (!value)
315 return;
316
317 Target::FileList outputs;
318 if (!ExtractListOfRelativeFiles(*value, input_directory_, &outputs, err_))
319 return;
320
321 // Validate that outputs are in the output dir.
322 CHECK(outputs.size() == value->list_value().size());
323 for (size_t i = 0; i < outputs.size(); i++) {
324 if (!EnsureStringIsInOutputDir(
325 GetBuildSettings()->build_dir(),
326 outputs[i].value(), value->list_value()[i], err_))
327 return;
328 }
329 target_->swap_in_outputs(&outputs);
330 }
331
332 const BuildSettings* TargetGenerator::GetBuildSettings() const {
333 return scope_->settings()->build_settings();
334 }
OLDNEW
« no previous file with comments | « tools/gn/target_generator.h ('k') | tools/gn/target_generator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698