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 // Like the above version but extracts to a UniqueVector and sets the error if
38 // there are duplicates.
39 template <typename T, class Converter>
ListValueUniqueExtractor(const Value & value,UniqueVector<T> * dest,Err * err,const Converter & converter)40 bool ListValueUniqueExtractor(const Value& value,
41 UniqueVector<T>* dest,
42 Err* err,
43 const Converter& converter) {
44 if (!value.VerifyTypeIs(Value::LIST, err))
45 return false;
46 const std::vector<Value>& input_list = value.list_value();
47
48 for (const auto& item : input_list) {
49 T new_one;
50 if (!converter(item, &new_one, err))
51 return false;
52 if (!dest->push_back(new_one)) {
53 // Already in the list, throw error.
54 *err = Err(item, "Duplicate item in list");
55 size_t previous_index = dest->IndexOf(new_one);
56 err->AppendSubErr(
57 Err(input_list[previous_index], "This was the previous definition."));
58 return false;
59 }
60 }
61 return true;
62 }
63
64 struct RelativeFileConverter {
RelativeFileConverter__anonb8f867620111::RelativeFileConverter65 RelativeFileConverter(const BuildSettings* build_settings_in,
66 const SourceDir& current_dir_in)
67 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonb8f867620111::RelativeFileConverter68 bool operator()(const Value& v, SourceFile* out, Err* err) const {
69 *out = current_dir.ResolveRelativeFile(v, err,
70 build_settings->root_path_utf8());
71 return !err->has_error();
72 }
73 const BuildSettings* build_settings;
74 const SourceDir& current_dir;
75 };
76
77 struct LibFileConverter {
LibFileConverter__anonb8f867620111::LibFileConverter78 LibFileConverter(const BuildSettings* build_settings_in,
79 const SourceDir& current_dir_in)
80 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonb8f867620111::LibFileConverter81 bool operator()(const Value& v, LibFile* out, Err* err) const {
82 if (!v.VerifyTypeIs(Value::STRING, err))
83 return false;
84 if (!GetFrameworkName(v.string_value()).empty()) {
85 *err = Err(v, "Unsupported value in libs.",
86 "Use frameworks to list framework dependencies.");
87 return false;
88 }
89 if (v.string_value().find('/') == std::string::npos) {
90 *out = LibFile(v.string_value());
91 } else {
92 *out = LibFile(current_dir.ResolveRelativeFile(
93 v, err, build_settings->root_path_utf8()));
94 }
95 return !err->has_error();
96 }
97 const BuildSettings* build_settings;
98 const SourceDir& current_dir;
99 };
100
101 struct RelativeDirConverter {
RelativeDirConverter__anonb8f867620111::RelativeDirConverter102 RelativeDirConverter(const BuildSettings* build_settings_in,
103 const SourceDir& current_dir_in)
104 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonb8f867620111::RelativeDirConverter105 bool operator()(const Value& v, SourceDir* out, Err* err) const {
106 *out = current_dir.ResolveRelativeDir(v, err,
107 build_settings->root_path_utf8());
108 return true;
109 }
110 const BuildSettings* build_settings;
111 const SourceDir& current_dir;
112 };
113
114 struct ExternConverter {
ExternConverter__anonb8f867620111::ExternConverter115 ExternConverter(const BuildSettings* build_settings_in,
116 const SourceDir& current_dir_in)
117 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonb8f867620111::ExternConverter118 bool operator()(const Value& v,
119 std::pair<std::string, LibFile>* out,
120 Err* err) const {
121 if (!v.VerifyTypeIs(Value::SCOPE, err))
122 return false;
123 Scope::KeyValueMap scope;
124 v.scope_value()->GetCurrentScopeValues(&scope);
125 std::string cratename;
126 if (auto it = scope.find("crate_name"); it != scope.end()) {
127 if (!it->second.VerifyTypeIs(Value::STRING, err))
128 return false;
129 cratename = it->second.string_value();
130 } else {
131 return false;
132 }
133 LibFile path;
134 if (auto it = scope.find("path"); it != scope.end()) {
135 if (!it->second.VerifyTypeIs(Value::STRING, err))
136 return false;
137 if (it->second.string_value().find('/') == std::string::npos) {
138 path = LibFile(it->second.string_value());
139 } else {
140 path = LibFile(current_dir.ResolveRelativeFile(
141 it->second, err, build_settings->root_path_utf8()));
142 }
143 } else {
144 return false;
145 }
146 *out = std::pair(cratename, path);
147 return !err->has_error();
148 }
149 const BuildSettings* build_settings;
150 const SourceDir& current_dir;
151 };
152
153 // Fills in a label.
154 template <typename T>
155 struct LabelResolver {
LabelResolver__anonb8f867620111::LabelResolver156 LabelResolver(const BuildSettings* build_settings_in,
157 const SourceDir& current_dir_in,
158 const Label& current_toolchain_in)
159 : build_settings(build_settings_in),
160 current_dir(current_dir_in),
161 current_toolchain(current_toolchain_in) {}
operator ()__anonb8f867620111::LabelResolver162 bool operator()(const Value& v, Label* out, Err* err) const {
163 if (!v.VerifyTypeIs(Value::STRING, err))
164 return false;
165 *out = Label::Resolve(current_dir, build_settings->root_path_utf8(),
166 current_toolchain, v, err);
167 return !err->has_error();
168 }
169 const BuildSettings* build_settings;
170 const SourceDir& current_dir;
171 const Label& current_toolchain;
172 };
173
174 // Fills the label part of a LabelPtrPair, leaving the pointer null.
175 template <typename T>
176 struct LabelPtrResolver {
LabelPtrResolver__anonb8f867620111::LabelPtrResolver177 LabelPtrResolver(const BuildSettings* build_settings_in,
178 const SourceDir& current_dir_in,
179 const Label& current_toolchain_in)
180 : build_settings(build_settings_in),
181 current_dir(current_dir_in),
182 current_toolchain(current_toolchain_in) {}
operator ()__anonb8f867620111::LabelPtrResolver183 bool operator()(const Value& v, LabelPtrPair<T>* out, Err* err) const {
184 if (!v.VerifyTypeIs(Value::STRING, err))
185 return false;
186 out->label = Label::Resolve(current_dir, build_settings->root_path_utf8(),
187 current_toolchain, v, err);
188 out->origin = v.origin();
189 return !err->has_error();
190 }
191 const BuildSettings* build_settings;
192 const SourceDir& current_dir;
193 const Label& current_toolchain;
194 };
195
196 struct LabelPatternResolver {
LabelPatternResolver__anonb8f867620111::LabelPatternResolver197 LabelPatternResolver(const BuildSettings* build_settings_in,
198 const SourceDir& current_dir_in)
199 : build_settings(build_settings_in), current_dir(current_dir_in) {}
operator ()__anonb8f867620111::LabelPatternResolver200 bool operator()(const Value& v, LabelPattern* out, Err* err) const {
201 *out = LabelPattern::GetPattern(current_dir,
202 build_settings->root_path_utf8(), v, err);
203 return !err->has_error();
204 }
205
206 const BuildSettings* build_settings;
207 const SourceDir& current_dir;
208 };
209
210 } // namespace
211
ExtractListOfStringValues(const Value & value,std::vector<std::string> * dest,Err * err)212 bool ExtractListOfStringValues(const Value& value,
213 std::vector<std::string>* dest,
214 Err* err) {
215 if (!value.VerifyTypeIs(Value::LIST, err))
216 return false;
217 const std::vector<Value>& input_list = value.list_value();
218 dest->reserve(input_list.size());
219 for (const auto& item : input_list) {
220 if (!item.VerifyTypeIs(Value::STRING, err))
221 return false;
222 dest->push_back(item.string_value());
223 }
224 return true;
225 }
226
ExtractListOfRelativeFiles(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<SourceFile> * files,Err * err)227 bool ExtractListOfRelativeFiles(const BuildSettings* build_settings,
228 const Value& value,
229 const SourceDir& current_dir,
230 std::vector<SourceFile>* files,
231 Err* err) {
232 return ListValueExtractor(value, files, err,
233 RelativeFileConverter(build_settings, current_dir));
234 }
235
ExtractListOfLibs(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<LibFile> * libs,Err * err)236 bool ExtractListOfLibs(const BuildSettings* build_settings,
237 const Value& value,
238 const SourceDir& current_dir,
239 std::vector<LibFile>* libs,
240 Err* err) {
241 return ListValueExtractor(value, libs, err,
242 LibFileConverter(build_settings, current_dir));
243 }
244
ExtractListOfRelativeDirs(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<SourceDir> * dest,Err * err)245 bool ExtractListOfRelativeDirs(const BuildSettings* build_settings,
246 const Value& value,
247 const SourceDir& current_dir,
248 std::vector<SourceDir>* dest,
249 Err* err) {
250 return ListValueExtractor(value, dest, err,
251 RelativeDirConverter(build_settings, current_dir));
252 }
253
ExtractListOfLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,LabelTargetVector * dest,Err * err)254 bool ExtractListOfLabels(const BuildSettings* build_settings,
255 const Value& value,
256 const SourceDir& current_dir,
257 const Label& current_toolchain,
258 LabelTargetVector* dest,
259 Err* err) {
260 return ListValueExtractor(
261 value, dest, err,
262 LabelPtrResolver<Target>(build_settings, current_dir, current_toolchain));
263 }
264
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<Label> * dest,Err * err)265 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
266 const Value& value,
267 const SourceDir& current_dir,
268 const Label& current_toolchain,
269 UniqueVector<Label>* dest,
270 Err* err) {
271 return ListValueUniqueExtractor(
272 value, dest, err,
273 LabelResolver<Config>(build_settings, current_dir, current_toolchain));
274 }
275
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<LabelConfigPair> * dest,Err * err)276 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
277 const Value& value,
278 const SourceDir& current_dir,
279 const Label& current_toolchain,
280 UniqueVector<LabelConfigPair>* dest,
281 Err* err) {
282 return ListValueUniqueExtractor(
283 value, dest, err,
284 LabelPtrResolver<Config>(build_settings, current_dir, current_toolchain));
285 }
286
ExtractListOfUniqueLabels(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,const Label & current_toolchain,UniqueVector<LabelTargetPair> * dest,Err * err)287 bool ExtractListOfUniqueLabels(const BuildSettings* build_settings,
288 const Value& value,
289 const SourceDir& current_dir,
290 const Label& current_toolchain,
291 UniqueVector<LabelTargetPair>* dest,
292 Err* err) {
293 return ListValueUniqueExtractor(
294 value, dest, err,
295 LabelPtrResolver<Target>(build_settings, current_dir, current_toolchain));
296 }
297
ExtractRelativeFile(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,SourceFile * file,Err * err)298 bool ExtractRelativeFile(const BuildSettings* build_settings,
299 const Value& value,
300 const SourceDir& current_dir,
301 SourceFile* file,
302 Err* err) {
303 RelativeFileConverter converter(build_settings, current_dir);
304 return converter(value, file, err);
305 }
306
ExtractListOfLabelPatterns(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<LabelPattern> * patterns,Err * err)307 bool ExtractListOfLabelPatterns(const BuildSettings* build_settings,
308 const Value& value,
309 const SourceDir& current_dir,
310 std::vector<LabelPattern>* patterns,
311 Err* err) {
312 return ListValueExtractor(value, patterns, err,
313 LabelPatternResolver(build_settings, current_dir));
314 }
315
ExtractListOfExterns(const BuildSettings * build_settings,const Value & value,const SourceDir & current_dir,std::vector<std::pair<std::string,LibFile>> * externs,Err * err)316 bool ExtractListOfExterns(const BuildSettings* build_settings,
317 const Value& value,
318 const SourceDir& current_dir,
319 std::vector<std::pair<std::string, LibFile>>* externs,
320 Err* err) {
321 return ListValueExtractor(value, externs, err,
322 ExternConverter(build_settings, current_dir));
323 }
324