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 "gn/value_extractors.h"
6
7 #include <stddef.h>
8
9 #include "gn/build_settings.h"
10 #include "gn/err.h"
11 #include "gn/frameworks_utils.h"
12 #include "gn/label.h"
13 #include "gn/source_dir.h"
14 #include "gn/source_file.h"
15 #include "gn/target.h"
16 #include "gn/value.h"
17
18 namespace {
19
20 // Sets the error and returns false on failure.
21 template <typename T, class Converter>
ListValueExtractor(const Value & value,std::vector<T> * dest,Err * err,const Converter & converter)22 bool ListValueExtractor(const Value& value,
23 std::vector<T>* dest,
24 Err* err,
25 const Converter& converter) {
26 if (!value.VerifyTypeIs(Value::LIST, err))
27 return false;
28 const std::vector<Value>& input_list = value.list_value();
29 dest->resize(input_list.size());
30 for (size_t i = 0; i < input_list.size(); i++) {
31 if (!converter(input_list[i], &(*dest)[i], err))
32 return false;
33 }
34 return true;
35 }
36
37 // Sets the error and returns false on failure.
38 template <typename T, class Converter>
ListValueAppender(const Value & value,std::vector<T> * dest,Err * err,const Converter & converter)39 bool ListValueAppender(const Value& value,
40 std::vector<T>* dest,
41 Err* err,
42 const Converter& converter)
43 {
44 if (!value.VerifyTypeIs(Value::LIST, err))
45 return false;
46 const std::vector<Value>& input_list = value.list_value();
47 for (const auto& item : input_list) {
48 T new_one;
49 if (!converter(item, &new_one, err))
50 return false;
51 dest->push_back(new_one);
52 }
53 return true;
54 }
55
56 // Like the above version but extracts to a UniqueVector and sets the error if
57 // there are duplicates.
58 template <typename T, class Converter>
ListValueUniqueExtractor(const Value & value,UniqueVector<T> * dest,Err * err,const Converter & converter)59 bool ListValueUniqueExtractor(const Value& value,
60 UniqueVector<T>* dest,
61 Err* err,
62 const Converter& converter) {
63 if (!value.VerifyTypeIs(Value::LIST, err))
64 return false;
65 const std::vector<Value>& input_list = value.list_value();
66
67 for (const auto& item : input_list) {
68 T new_one;
69 if (!converter(item, &new_one, err))
70 return false;
71 if (!dest->push_back(new_one)) {
72 // Already in the list, throw error.
73 *err = Err(item, "Duplicate item in list");
74 size_t previous_index = dest->IndexOf(new_one);
75 err->AppendSubErr(
76 Err(input_list[previous_index], "This was the previous definition."));
77 return false;
78 }
79 }
80 return true;
81 }
82
83 struct RelativeFileConverter {
RelativeFileConverter__anonda75a4010111::RelativeFileConverter84 RelativeFileConverter(const BuildSettings* build_settings_in,
85 const SourceDir& current_dir_in)
86 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonda75a4010111::RelativeFileConverter87 bool operator()(const Value& v, SourceFile* out, Err* err) const {
88 *out = current_dir.ResolveRelativeFile(v, err,
89 build_settings->root_path_utf8());
90 return !err->has_error();
91 }
92 const BuildSettings* build_settings;
93 const SourceDir& current_dir;
94 };
95
96 struct LibFileConverter {
LibFileConverter__anonda75a4010111::LibFileConverter97 LibFileConverter(const BuildSettings* build_settings_in,
98 const SourceDir& current_dir_in)
99 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonda75a4010111::LibFileConverter100 bool operator()(const Value& v, LibFile* out, Err* err) const {
101 if (!v.VerifyTypeIs(Value::STRING, err))
102 return false;
103 if (!GetFrameworkName(v.string_value()).empty()) {
104 *err = Err(v, "Unsupported value in libs.",
105 "Use frameworks to list framework dependencies.");
106 return false;
107 }
108 if (v.string_value().find('/') == std::string::npos) {
109 *out = LibFile(v.string_value());
110 } else {
111 *out = LibFile(current_dir.ResolveRelativeFile(
112 v, err, build_settings->root_path_utf8()));
113 }
114 return !err->has_error();
115 }
116 const BuildSettings* build_settings;
117 const SourceDir& current_dir;
118 };
119
120 struct RelativeDirConverter {
RelativeDirConverter__anonda75a4010111::RelativeDirConverter121 RelativeDirConverter(const BuildSettings* build_settings_in,
122 const SourceDir& current_dir_in)
123 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonda75a4010111::RelativeDirConverter124 bool operator()(const Value& v, SourceDir* out, Err* err) const {
125 *out = current_dir.ResolveRelativeDir(v, err,
126 build_settings->root_path_utf8());
127 return true;
128 }
129 const BuildSettings* build_settings;
130 const SourceDir& current_dir;
131 };
132
133 struct ExternConverter {
ExternConverter__anonda75a4010111::ExternConverter134 ExternConverter(const BuildSettings* build_settings_in,
135 const SourceDir& current_dir_in)
136 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonda75a4010111::ExternConverter137 bool operator()(const Value& v,
138 std::pair<std::string, LibFile>* out,
139 Err* err) const {
140 if (!v.VerifyTypeIs(Value::SCOPE, err))
141 return false;
142 Scope::KeyValueMap scope;
143 v.scope_value()->GetCurrentScopeValues(&scope);
144 std::string cratename;
145 if (auto it = scope.find("crate_name"); it != scope.end()) {
146 if (!it->second.VerifyTypeIs(Value::STRING, err))
147 return false;
148 cratename = it->second.string_value();
149 } else {
150 return false;
151 }
152 LibFile path;
153 if (auto it = scope.find("path"); it != scope.end()) {
154 if (!it->second.VerifyTypeIs(Value::STRING, err))
155 return false;
156 if (it->second.string_value().find('/') == std::string::npos) {
157 path = LibFile(it->second.string_value());
158 } else {
159 path = LibFile(current_dir.ResolveRelativeFile(
160 it->second, err, build_settings->root_path_utf8()));
161 }
162 } else {
163 return false;
164 }
165 *out = std::pair(cratename, path);
166 return !err->has_error();
167 }
168 const BuildSettings* build_settings;
169 const SourceDir& current_dir;
170 };
171
172 // Fills in a label.
173 template <typename T>
174 struct LabelResolver {
LabelResolver__anonda75a4010111::LabelResolver175 LabelResolver(const BuildSettings* build_settings_in,
176 const SourceDir& current_dir_in,
177 const Label& current_toolchain_in)
178 : build_settings(build_settings_in),
179 current_dir(current_dir_in),
180 current_toolchain(current_toolchain_in) {}
operator ()__anonda75a4010111::LabelResolver181 bool operator()(const Value& v, Label* out, Err* err) const {
182 if (!v.VerifyTypeIs(Value::STRING, err))
183 return false;
184 *out = Label::Resolve(current_dir, build_settings->root_path_utf8(),
185 current_toolchain, v, err);
186 return !err->has_error();
187 }
188 const BuildSettings* build_settings;
189 const SourceDir& current_dir;
190 const Label& current_toolchain;
191 };
192
193 // Fills the label part of a LabelPtrPair, leaving the pointer null.
194 template <typename T>
195 struct LabelPtrResolver {
LabelPtrResolver__anonda75a4010111::LabelPtrResolver196 LabelPtrResolver(const BuildSettings* build_settings_in,
197 const SourceDir& current_dir_in,
198 const Label& current_toolchain_in)
199 : build_settings(build_settings_in),
200 current_dir(current_dir_in),
201 current_toolchain(current_toolchain_in) {}
operator ()__anonda75a4010111::LabelPtrResolver202 bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const {
203 if (!v.VerifyTypeIs(Value::STRING, err))
204 return false;
205 out->label = Label::Resolve(current_dir, build_settings->root_path_utf8(),
206 current_toolchain, v, err);
207 out->origin = v.origin();
208 return !err->has_error();
209 }
210 const BuildSettings* build_settings;
211 const SourceDir& current_dir;
212 const Label& current_toolchain;
213 };
214
215 // Fills the label part of a LabelPtrPair, leaving the pointer null.
216 template <typename T>
217 struct ExternalDepPtrResolver {
ExternalDepPtrResolver__anonda75a4010111::ExternalDepPtrResolver218 ExternalDepPtrResolver(const BuildSettings* build_settings_in,
219 const SourceDir& current_dir_in,
220 const Label& current_toolchain_in)
221 : build_settings(build_settings_in),
222 current_dir(current_dir_in),
223 current_toolchain(current_toolchain_in) {}
operator ()__anonda75a4010111::ExternalDepPtrResolver224 bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const
225 {
226 if (!v.VerifyTypeIs(Value::STRING, err)) {
227 return false;
228 }
229 std::string label;
230 if (!build_settings->GetExternalDepsLabel(v, label, err)) {
231 return false;
232 }
233 Value external_dep(v.origin(), label);
234 out->label = Label::Resolve(current_dir, build_settings->root_path_utf8(),
235 current_toolchain, external_dep, err);
236 out->origin = v.origin();
237 out->is_external_deps = true;
238 return !err->has_error();
239 }
240 const BuildSettings* build_settings;
241 const SourceDir& current_dir;
242 const Label& current_toolchain;
243 };
244
245 struct LabelPatternResolver {
LabelPatternResolver__anonda75a4010111::LabelPatternResolver246 LabelPatternResolver(const BuildSettings* build_settings_in,
247 const SourceDir& current_dir_in)
248 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonda75a4010111::LabelPatternResolver249 bool operator()(const Value& v, LabelPattern* out, Err* err) const {
250 *out = LabelPattern::GetPattern(current_dir,
251 build_settings->root_path_utf8(), v, err);
252 return !err->has_error();
253 }
254
255 const BuildSettings* build_settings;
256 const SourceDir& current_dir;
257 };
258
259 } // namespace
260
ExtractListOfStringValues(const Value & value,std::vector<std::string> * dest,Err * err)261 bool ExtractListOfStringValues(const Value& value,
262 std::vector<std::string>* dest,
263 Err* err) {
264 if (!value.VerifyTypeIs(Value::LIST, err))
265 return false;
266 const std::vector<Value>& input_list = value.list_value();
267 dest->reserve(input_list.size());
268 for (const auto& item : input_list) {
269 if (!item.VerifyTypeIs(Value::STRING, err))
270 return false;
271 dest->push_back(item.string_value());
272 }
273 return true;
274 }
275
ExtractListOfRelativeFiles(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<SourceFile> * files,Err * err)276 bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
277 const Value& value,
278 const SourceDir& current_dir,
279 std::vector<SourceFile>* files,
280 Err* err) {
281 return ListValueExtractor(value, files, err,
282 RelativeFileConverter(build_settings, current_dir));
283 }
284
ExtractListOfLibs(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<LibFile> * libs,Err * err)285 bool ExtractListOfLibs(const BuildSettings* build_settings,
286 const Value& value,
287 const SourceDir& current_dir,
288 std::vector<LibFile>* libs,
289 Err* err) {
290 return ListValueExtractor(value, libs, err,
291 LibFileConverter(build_settings, current_dir));
292 }
293
ExtractListOfRelativeDirs(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<SourceDir> * dest,Err * err)294 bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
295 const Value& value,
296 const SourceDir& current_dir,
297 std::vector<SourceDir>* dest,
298 Err* err) {
299 return ListValueExtractor(value, dest, err,
300 RelativeDirConverter(build_settings, current_dir));
301 }
302
ExtractListOfLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,LabelTargetVector * dest,Err * err)303 bool ExtractListOfLabels(const BuildSettings* build_settings,
304 const Value& value,
305 const SourceDir& current_dir,
306 const Label& current_toolchain,
307 LabelTargetVector* dest,
308 Err* err) {
309 return ListValueExtractor(
310 value, dest, err,
311 LabelPtrResolver<Target>(build_settings, current_dir, current_toolchain));
312 }
313
ExtractListOfExternalDeps(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,LabelTargetVector * dest,Err * err)314 bool ExtractListOfExternalDeps(const BuildSettings* build_settings,
315 const Value& value,
316 const SourceDir& current_dir,
317 const Label& current_toolchain,
318 LabelTargetVector* dest,
319 Err* err) {
320 return ListValueAppender(
321 value, dest, err,
322 ExternalDepPtrResolver<Target>(build_settings, current_dir, current_toolchain));
323 }
324
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<Label> * dest,Err * err)325 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
326 const Value& value,
327 const SourceDir& current_dir,
328 const Label& current_toolchain,
329 UniqueVector<Label>* dest,
330 Err* err) {
331 return ListValueUniqueExtractor(
332 value, dest, err,
333 LabelResolver<Config>(build_settings, current_dir, current_toolchain));
334 }
335
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<LabelConfigPair> * dest,Err * err)336 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
337 const Value& value,
338 const SourceDir& current_dir,
339 const Label& current_toolchain,
340 UniqueVector<LabelConfigPair>* dest,
341 Err* err) {
342 return ListValueUniqueExtractor(
343 value, dest, err,
344 LabelPtrResolver<Config>(build_settings, current_dir, current_toolchain));
345 }
346
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<LabelTargetPair> * dest,Err * err)347 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
348 const Value& value,
349 const SourceDir& current_dir,
350 const Label& current_toolchain,
351 UniqueVector<LabelTargetPair>* dest,
352 Err* err) {
353 return ListValueUniqueExtractor(
354 value, dest, err,
355 LabelPtrResolver<Target>(build_settings, current_dir, current_toolchain));
356 }
357
ExtractRelativeFile(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,SourceFile * file,Err * err)358 bool ExtractRelativeFile(const BuildSettings* build_settings,
359 const Value& value,
360 const SourceDir& current_dir,
361 SourceFile* file,
362 Err* err) {
363 RelativeFileConverter converter(build_settings, current_dir);
364 return converter(value, file, err);
365 }
366
ExtractListOfLabelPatterns(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<LabelPattern> * patterns,Err * err)367 bool ExtractListOfLabelPatterns(const BuildSettings* build_settings,
368 const Value& value,
369 const SourceDir& current_dir,
370 std::vector<LabelPattern>* patterns,
371 Err* err) {
372 return ListValueExtractor(value, patterns, err,
373 LabelPatternResolver(build_settings, current_dir));
374 }
375
ExtractListOfExterns(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<std::pair<std::string,LibFile>> * externs,Err * err)376 bool ExtractListOfExterns(const BuildSettings* build_settings,
377 const Value& value,
378 const SourceDir& current_dir,
379 std::vector<std::pair<std::string, LibFile>>* externs,
380 Err* err) {
381 return ListValueExtractor(value, externs, err,
382 ExternConverter(build_settings, current_dir));
383 }
384