OLD | NEW |
| (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/gyp_binary_target_writer.h" | |
6 | |
7 #include <set> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "tools/gn/builder_record.h" | |
12 #include "tools/gn/config_values_extractors.h" | |
13 #include "tools/gn/err.h" | |
14 #include "tools/gn/escape.h" | |
15 #include "tools/gn/filesystem_utils.h" | |
16 #include "tools/gn/settings.h" | |
17 #include "tools/gn/target.h" | |
18 | |
19 namespace { | |
20 | |
21 // This functor is used to capture the output of RecursiveTargetConfigToStream | |
22 // in an vector. | |
23 template<typename T> | |
24 struct Accumulator { | |
25 Accumulator(std::vector<T>* result_in) : result(result_in) {} | |
26 | |
27 void operator()(const T& s, std::ostream&) const { | |
28 result->push_back(s); | |
29 } | |
30 | |
31 std::vector<T>* result; | |
32 }; | |
33 | |
34 // Writes the given array values. The array should already be declared with the | |
35 // opening "[" written to the output. The function will not write the | |
36 // terminating "]" either. | |
37 void WriteArrayValues(std::ostream& out, | |
38 const std::vector<std::string>& values) { | |
39 EscapeOptions options; | |
40 options.mode = ESCAPE_JSON; | |
41 for (size_t i = 0; i < values.size(); i++) { | |
42 out << " '"; | |
43 EscapeStringToStream(out, values[i], options); | |
44 out << "',"; | |
45 } | |
46 } | |
47 | |
48 // Returns the value from the already-filled in cflags_* for the optimization | |
49 // level to set in the GYP file. Additionally, this removes the flag from the | |
50 // given vector so we don't get duplicates. | |
51 std::string GetVCOptimization(std::vector<std::string>* cflags) { | |
52 // Searches for the "/O?" option and returns the corresponding GYP value. | |
53 for (size_t i = 0; i < cflags->size(); i++) { | |
54 const std::string& cur = (*cflags)[i]; | |
55 if (cur.size() == 3 && cur[0] == '/' && cur[1] == 'O') { | |
56 char level = cur[2]; | |
57 cflags->erase(cflags->begin() + i); // Invalidates |cur|! | |
58 switch (level) { | |
59 case 'd': return "'0'"; | |
60 case '1': return "'1'"; | |
61 case '2': return "'2'"; | |
62 case 'x': return "'3'"; | |
63 default: return "'2'"; | |
64 } | |
65 } | |
66 } | |
67 return "'2'"; // Default value. | |
68 } | |
69 | |
70 // Returns the value from the already-filled in cflags for the processor | |
71 // architecture to set in the GYP file. Additionally, this removes the flag | |
72 // from the given vector so we don't get duplicates. | |
73 std::string GetMacArch(std::vector<std::string>* cflags) { | |
74 // Searches for the "-arch" option and returns the corresponding GYP value. | |
75 for (size_t i = 0; i < cflags->size(); i++) { | |
76 const std::string& cur = (*cflags)[i]; | |
77 if (cur == "-arch") { | |
78 // This is the first part of a list with ["-arch", "i386"], return the | |
79 // following item, and delete both of them. | |
80 if (i < cflags->size() - 1) { | |
81 std::string ret = (*cflags)[i + 1]; | |
82 cflags->erase(cflags->begin() + i, cflags->begin() + i + 2); | |
83 return ret; | |
84 } | |
85 } else if (StartsWithASCII(cur, "-arch ", true)) { | |
86 // The arch was passed as one GN string value, e.g. "-arch i386". Return | |
87 // the stuff following the space and delete the item. | |
88 std::string ret = cur.substr(6); | |
89 cflags->erase(cflags->begin() + i); | |
90 return ret; | |
91 } | |
92 } | |
93 return std::string(); | |
94 } | |
95 | |
96 // Searches for -miphoneos-version-min, returns the resulting value, and | |
97 // removes it from the list. Returns the empty string if it's not found. | |
98 std::string GetIPhoneVersionMin(std::vector<std::string>* cflags) { | |
99 // Searches for the "-arch" option and returns the corresponding GYP value. | |
100 const char prefix[] = "-miphoneos-version-min="; | |
101 for (size_t i = 0; i < cflags->size(); i++) { | |
102 const std::string& cur = (*cflags)[i]; | |
103 if (StartsWithASCII(cur, prefix, true)) { | |
104 std::string result = cur.substr(arraysize(prefix) - 1); | |
105 cflags->erase(cflags->begin() + i); | |
106 return result; | |
107 } | |
108 } | |
109 return std::string(); | |
110 } | |
111 | |
112 // Finds all values from the given getter from all configs in the given list, | |
113 // and adds them to the given result vector. | |
114 template<typename T> | |
115 void FillConfigListValues( | |
116 const LabelConfigVector& configs, | |
117 const std::vector<T>& (ConfigValues::* getter)() const, | |
118 std::vector<T>* result) { | |
119 for (size_t config_i = 0; config_i < configs.size(); config_i++) { | |
120 const std::vector<T>& values = | |
121 (configs[config_i].ptr->config_values().*getter)(); | |
122 for (size_t val_i = 0; val_i < values.size(); val_i++) | |
123 result->push_back(values[val_i]); | |
124 } | |
125 } | |
126 | |
127 bool IsClang(const Target* target) { | |
128 const Value* is_clang = | |
129 target->settings()->base_config()->GetValue("is_clang"); | |
130 return is_clang && is_clang->type() == Value::BOOLEAN && | |
131 is_clang->boolean_value(); | |
132 } | |
133 | |
134 bool IsIOS(const Target* target) { | |
135 const Value* is_ios = target->settings()->base_config()->GetValue("is_ios"); | |
136 return is_ios && is_ios->type() == Value::BOOLEAN && is_ios->boolean_value(); | |
137 } | |
138 | |
139 // Returns true if the current target is an iOS simulator build. | |
140 bool IsIOSSimulator(const std::vector<std::string>& cflags) { | |
141 // Search for the sysroot flag. We expect one flag to be the | |
142 // switch, and the following one to be the value. | |
143 const char sysroot[] = "-isysroot"; | |
144 for (size_t i = 0; i < cflags.size(); i++) { | |
145 const std::string& cur = cflags[i]; | |
146 if (cur == sysroot) { | |
147 if (i == cflags.size() - 1) | |
148 return false; // No following value. | |
149 | |
150 // The argument is a file path, we check the prefix of the file name. | |
151 base::FilePath path(UTF8ToFilePath(cflags[i + 1])); | |
152 std::string path_file_part = FilePathToUTF8(path.BaseName()); | |
153 return StartsWithASCII(path_file_part, "iphonesimulator", false); | |
154 } | |
155 } | |
156 return false; | |
157 } | |
158 | |
159 } // namespace | |
160 | |
161 GypBinaryTargetWriter::Flags::Flags() {} | |
162 GypBinaryTargetWriter::Flags::~Flags() {} | |
163 | |
164 GypBinaryTargetWriter::GypBinaryTargetWriter(const TargetGroup& group, | |
165 const Toolchain* debug_toolchain, | |
166 const SourceDir& gyp_dir, | |
167 std::ostream& out) | |
168 : GypTargetWriter(group.get()->item()->AsTarget(), debug_toolchain, | |
169 gyp_dir, out), | |
170 group_(group) { | |
171 } | |
172 | |
173 GypBinaryTargetWriter::~GypBinaryTargetWriter() { | |
174 } | |
175 | |
176 void GypBinaryTargetWriter::Run() { | |
177 int indent = 4; | |
178 | |
179 Indent(indent) << "{\n"; | |
180 | |
181 WriteName(indent + kExtraIndent); | |
182 WriteType(indent + kExtraIndent); | |
183 | |
184 if (target_->settings()->IsLinux()) | |
185 WriteLinuxConfiguration(indent + kExtraIndent); | |
186 else if (target_->settings()->IsWin()) | |
187 WriteVCConfiguration(indent + kExtraIndent); | |
188 else if (target_->settings()->IsMac()) | |
189 WriteMacConfiguration(indent + kExtraIndent); | |
190 WriteDirectDependentSettings(indent + kExtraIndent); | |
191 WriteAllDependentSettings(indent + kExtraIndent); | |
192 | |
193 Indent(indent) << "},\n"; | |
194 } | |
195 | |
196 void GypBinaryTargetWriter::WriteName(int indent) { | |
197 std::string name = helper_.GetNameForTarget(target_); | |
198 Indent(indent) << "'target_name': '" << name << "',\n"; | |
199 | |
200 std::string product_name; | |
201 if (target_->output_name().empty()) | |
202 product_name = target_->label().name(); | |
203 else | |
204 product_name = name; | |
205 | |
206 // TODO(brettw) GN knows not to prefix targets starting with "lib" with | |
207 // another "lib" on Linux, but GYP doesn't. We need to rename applicable | |
208 // targets here. | |
209 | |
210 Indent(indent) << "'product_name': '" << product_name << "',\n"; | |
211 | |
212 std::string product_extension = target_->output_extension(); | |
213 if (!product_extension.empty()) | |
214 Indent(indent) << "'product_extension': '" << product_extension << "',\n"; | |
215 } | |
216 | |
217 void GypBinaryTargetWriter::WriteType(int indent) { | |
218 Indent(indent) << "'type': "; | |
219 switch (target_->output_type()) { | |
220 case Target::EXECUTABLE: | |
221 out_ << "'executable',\n"; | |
222 break; | |
223 case Target::STATIC_LIBRARY: | |
224 out_ << "'static_library',\n"; | |
225 break; | |
226 case Target::SHARED_LIBRARY: | |
227 out_ << "'shared_library',\n"; | |
228 break; | |
229 case Target::SOURCE_SET: | |
230 out_ << "'static_library',\n"; // TODO(brettw) fixme. | |
231 break; | |
232 default: | |
233 NOTREACHED(); | |
234 } | |
235 | |
236 if (target_->hard_dep()) | |
237 Indent(indent) << "'hard_dependency': 1,\n"; | |
238 | |
239 // Write out the toolsets depending on whether there is a host build. If no | |
240 // toolset is specified, GYP assumes a target build. | |
241 if (group_.debug && group_.host_debug) | |
242 Indent(indent) << "'toolsets': ['target', 'host'],\n"; | |
243 else if (group_.host_debug) | |
244 Indent(indent) << "'toolsets': ['host'],\n"; | |
245 } | |
246 | |
247 void GypBinaryTargetWriter::WriteVCConfiguration(int indent) { | |
248 Indent(indent) << "'configurations': {\n"; | |
249 | |
250 Indent(indent + kExtraIndent) << "'Debug': {\n"; | |
251 Indent(indent + kExtraIndent * 2) << | |
252 "'msvs_configuration_platform': 'Win32',\n"; | |
253 Flags debug_flags(FlagsFromTarget(group_.debug->item()->AsTarget())); | |
254 WriteVCFlags(debug_flags, indent + kExtraIndent * 2); | |
255 Indent(indent + kExtraIndent) << "},\n"; | |
256 | |
257 Indent(indent + kExtraIndent) << "'Release': {\n"; | |
258 Indent(indent + kExtraIndent * 2) << | |
259 "'msvs_configuration_platform': 'Win32',\n"; | |
260 Flags release_flags(FlagsFromTarget(group_.release->item()->AsTarget())); | |
261 WriteVCFlags(release_flags, indent + kExtraIndent * 2); | |
262 Indent(indent + kExtraIndent) << "},\n"; | |
263 | |
264 // Note that we always need Debug_x64 and Release_x64 defined or GYP will get | |
265 // confused, but we ca leave them empty if there's no 64-bit target. | |
266 Indent(indent + kExtraIndent) << "'Debug_x64': {\n"; | |
267 if (group_.debug64) { | |
268 Indent(indent + kExtraIndent * 2) << | |
269 "'msvs_configuration_platform': 'x64',\n"; | |
270 Flags flags(FlagsFromTarget(group_.debug64->item()->AsTarget())); | |
271 WriteVCFlags(flags, indent + kExtraIndent * 2); | |
272 } | |
273 Indent(indent + kExtraIndent) << "},\n"; | |
274 | |
275 Indent(indent + kExtraIndent) << "'Release_x64': {\n"; | |
276 if (group_.release64) { | |
277 Indent(indent + kExtraIndent * 2) << | |
278 "'msvs_configuration_platform': 'x64',\n"; | |
279 Flags flags(FlagsFromTarget(group_.release64->item()->AsTarget())); | |
280 WriteVCFlags(flags, indent + kExtraIndent * 2); | |
281 } | |
282 Indent(indent + kExtraIndent) << "},\n"; | |
283 | |
284 Indent(indent) << "},\n"; | |
285 | |
286 WriteSources(target_, indent); | |
287 WriteDeps(target_, indent); | |
288 } | |
289 | |
290 void GypBinaryTargetWriter::WriteLinuxConfiguration(int indent) { | |
291 // The Linux stuff works differently. On Linux we support cross-compiles and | |
292 // all ninja generators know to look for target conditions. Other platforms' | |
293 // generators don't all do this, so we can't have the same GYP structure. | |
294 Indent(indent) << "'target_conditions': [\n"; | |
295 // The host toolset is configured for the current computer, we will only have | |
296 // this when doing cross-compiles. | |
297 if (group_.host_debug && group_.host_release) { | |
298 Indent(indent + kExtraIndent) << "['_toolset == \"host\"', {\n"; | |
299 Indent(indent + kExtraIndent * 2) << "'configurations': {\n"; | |
300 Indent(indent + kExtraIndent * 3) << "'Debug': {\n"; | |
301 WriteLinuxFlagsForTarget(group_.host_debug->item()->AsTarget(), | |
302 indent + kExtraIndent * 4); | |
303 Indent(indent + kExtraIndent * 3) << "},\n"; | |
304 Indent(indent + kExtraIndent * 3) << "'Release': {\n"; | |
305 WriteLinuxFlagsForTarget(group_.host_release->item()->AsTarget(), | |
306 indent + kExtraIndent * 4); | |
307 Indent(indent + kExtraIndent * 3) << "},\n"; | |
308 Indent(indent + kExtraIndent * 2) << "}\n"; | |
309 | |
310 // The sources are per-toolset but shared between debug & release. | |
311 WriteSources(group_.host_debug->item()->AsTarget(), | |
312 indent + kExtraIndent * 2); | |
313 | |
314 Indent(indent + kExtraIndent) << "],\n"; | |
315 } | |
316 | |
317 // The target toolset is the "regular" one. | |
318 Indent(indent + kExtraIndent) << "['_toolset == \"target\"', {\n"; | |
319 Indent(indent + kExtraIndent * 2) << "'configurations': {\n"; | |
320 Indent(indent + kExtraIndent * 3) << "'Debug': {\n"; | |
321 WriteLinuxFlagsForTarget(group_.debug->item()->AsTarget(), | |
322 indent + kExtraIndent * 4); | |
323 Indent(indent + kExtraIndent * 3) << "},\n"; | |
324 Indent(indent + kExtraIndent * 3) << "'Release': {\n"; | |
325 WriteLinuxFlagsForTarget(group_.release->item()->AsTarget(), | |
326 indent + kExtraIndent * 4); | |
327 Indent(indent + kExtraIndent * 3) << "},\n"; | |
328 Indent(indent + kExtraIndent * 2) << "},\n"; | |
329 | |
330 WriteSources(target_, indent + kExtraIndent * 2); | |
331 | |
332 Indent(indent + kExtraIndent) << "},],\n"; | |
333 Indent(indent) << "],\n"; | |
334 | |
335 // Deps in GYP can not vary based on the toolset. | |
336 WriteDeps(target_, indent); | |
337 } | |
338 | |
339 void GypBinaryTargetWriter::WriteMacConfiguration(int indent) { | |
340 // The Mac flags are parameterized by the GYP generator (Ninja vs. XCode). | |
341 const char kNinjaGeneratorCondition[] = | |
342 "'conditions': [['\"<(GENERATOR)\"==\"ninja\"', {\n"; | |
343 const char kNinjaGeneratorElse[] = "}, {\n"; | |
344 const char kNinjaGeneratorEnd[] = "}]],\n"; | |
345 | |
346 Indent(indent) << "'configurations': {\n"; | |
347 | |
348 // Debug. | |
349 Indent(indent + kExtraIndent) << "'Debug': {\n"; | |
350 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorCondition; | |
351 { | |
352 // Ninja generator. | |
353 WriteMacTargetAndHostFlags(group_.debug, group_.host_debug, | |
354 indent + kExtraIndent * 3); | |
355 } | |
356 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorElse; | |
357 if (group_.xcode_debug) { | |
358 // XCode generator. | |
359 WriteMacTargetAndHostFlags(group_.xcode_debug, group_.xcode_host_debug, | |
360 indent + kExtraIndent * 3); | |
361 } | |
362 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorEnd; | |
363 Indent(indent + kExtraIndent) << "},\n"; | |
364 | |
365 // Release. | |
366 Indent(indent + kExtraIndent) << "'Release': {\n"; | |
367 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorCondition; | |
368 { | |
369 // Ninja generator. | |
370 WriteMacTargetAndHostFlags(group_.release, group_.host_release, | |
371 indent + kExtraIndent * 3); | |
372 } | |
373 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorElse; | |
374 if (group_.xcode_release) { | |
375 // XCode generator. | |
376 WriteMacTargetAndHostFlags(group_.xcode_release, group_.xcode_host_release, | |
377 indent + kExtraIndent * 3); | |
378 } | |
379 Indent(indent + kExtraIndent * 2) << kNinjaGeneratorEnd; | |
380 Indent(indent + kExtraIndent) << "},\n"; | |
381 | |
382 Indent(indent) << "},\n"; | |
383 | |
384 WriteSources(target_, indent); | |
385 WriteDeps(target_, indent); | |
386 } | |
387 | |
388 void GypBinaryTargetWriter::WriteVCFlags(Flags& flags, int indent) { | |
389 // Defines and includes go outside of the msvs settings. | |
390 WriteNamedArray("defines", flags.defines, indent); | |
391 WriteIncludeDirs(flags, indent); | |
392 | |
393 // C flags. | |
394 Indent(indent) << "'msvs_settings': {\n"; | |
395 Indent(indent + kExtraIndent) << "'VCCLCompilerTool': {\n"; | |
396 | |
397 // GYP always uses the VC optimization flag to add a /O? on Visual Studio. | |
398 // This can produce duplicate values. So look up the GYP value corresponding | |
399 // to the flags used, and set the same one. | |
400 std::string optimization = GetVCOptimization(&flags.cflags); | |
401 WriteNamedArray("AdditionalOptions", flags.cflags, indent + kExtraIndent * 2); | |
402 // TODO(brettw) cflags_c and cflags_cc! | |
403 Indent(indent + kExtraIndent * 2) << "'Optimization': " | |
404 << optimization << ",\n"; | |
405 Indent(indent + kExtraIndent) << "},\n"; | |
406 | |
407 // Linker tool stuff. | |
408 Indent(indent + kExtraIndent) << "'VCLinkerTool': {\n"; | |
409 | |
410 // ...Library dirs. | |
411 EscapeOptions escape_options; | |
412 escape_options.mode = ESCAPE_JSON; | |
413 if (!flags.lib_dirs.empty()) { | |
414 Indent(indent + kExtraIndent * 2) << "'AdditionalLibraryDirectories': ["; | |
415 for (size_t i = 0; i < flags.lib_dirs.size(); i++) { | |
416 out_ << " '"; | |
417 EscapeStringToStream(out_, | |
418 helper_.GetDirReference(flags.lib_dirs[i], false), | |
419 escape_options); | |
420 out_ << "',"; | |
421 } | |
422 out_ << " ],\n"; | |
423 } | |
424 | |
425 // ...Libraries. | |
426 WriteNamedArray("AdditionalDependencies", flags.libs, | |
427 indent + kExtraIndent * 2); | |
428 | |
429 // ...LD flags. | |
430 // TODO(brettw) EnableUAC defaults to on and needs to be set. Also | |
431 // UACExecutionLevel and UACUIAccess depends on that and defaults to 0/false. | |
432 WriteNamedArray("AdditionalOptions", flags.ldflags, 14); | |
433 Indent(indent + kExtraIndent) << "},\n"; | |
434 Indent(indent) << "},\n"; | |
435 } | |
436 | |
437 void GypBinaryTargetWriter::WriteMacFlags(const Target* target, | |
438 Flags& flags, | |
439 int indent) { | |
440 WriteNamedArray("defines", flags.defines, indent); | |
441 WriteIncludeDirs(flags, indent); | |
442 | |
443 // Libraries and library directories. | |
444 EscapeOptions escape_options; | |
445 escape_options.mode = ESCAPE_JSON; | |
446 if (!flags.lib_dirs.empty()) { | |
447 Indent(indent + kExtraIndent) << "'library_dirs': ["; | |
448 for (size_t i = 0; i < flags.lib_dirs.size(); i++) { | |
449 out_ << " '"; | |
450 EscapeStringToStream(out_, | |
451 helper_.GetDirReference(flags.lib_dirs[i], false), | |
452 escape_options); | |
453 out_ << "',"; | |
454 } | |
455 out_ << " ],\n"; | |
456 } | |
457 if (!flags.libs.empty()) { | |
458 Indent(indent) << "'link_settings': {\n"; | |
459 Indent(indent + kExtraIndent) << "'libraries': ["; | |
460 for (size_t i = 0; i < flags.libs.size(); i++) { | |
461 out_ << " '-l"; | |
462 EscapeStringToStream(out_, flags.libs[i], escape_options); | |
463 out_ << "',"; | |
464 } | |
465 out_ << " ],\n"; | |
466 Indent(indent) << "},\n"; | |
467 } | |
468 | |
469 Indent(indent) << "'xcode_settings': {\n"; | |
470 | |
471 // Architecture. GYP reads this value and uses it to generate the -arch | |
472 // flag, so we always want to remove it from the cflags (which is a side | |
473 // effect of what GetMacArch does), even in cases where we don't use the | |
474 // value (in the iOS arm below). | |
475 std::string arch = GetMacArch(&flags.cflags); | |
476 if (IsIOS(target)) { | |
477 // When writing an iOS "target" (not host) target, we set VALID_ARCHS | |
478 // instead of ARCHS and always use this hardcoded value. This matches the | |
479 // GYP build. | |
480 Indent(indent + kExtraIndent) << "'VALID_ARCHS': ['armv7', 'i386'],\n"; | |
481 | |
482 // Tell XCode to target both iPhone and iPad. GN has no such concept. | |
483 Indent(indent + kExtraIndent) << "'TARGETED_DEVICE_FAMILY': '1,2',\n"; | |
484 | |
485 if (IsIOSSimulator(flags.cflags)) { | |
486 Indent(indent + kExtraIndent) << "'SDKROOT': 'iphonesimulator',\n"; | |
487 } else { | |
488 Indent(indent + kExtraIndent) << "'SDKROOT': 'iphoneos',\n"; | |
489 std::string min_ver = GetIPhoneVersionMin(&flags.cflags); | |
490 if (!min_ver.empty()) { | |
491 Indent(indent + kExtraIndent) << "'IPHONEOS_DEPLOYMENT_TARGET': '" | |
492 << min_ver << "',\n"; | |
493 } | |
494 } | |
495 } else { | |
496 // When doing regular Mac and "host" iOS (which look like regular Mac) | |
497 // builds, we can set the ARCHS value to what's specified in the build. | |
498 if (arch == "i386") | |
499 Indent(indent + kExtraIndent) << "'ARCHS': [ 'i386' ],\n"; | |
500 else if (arch == "x86_64") | |
501 Indent(indent + kExtraIndent) << "'ARCHS': [ 'x86_64' ],\n"; | |
502 } | |
503 | |
504 // C/C++ flags. | |
505 if (!flags.cflags.empty() || !flags.cflags_c.empty() || | |
506 !flags.cflags_objc.empty()) { | |
507 Indent(indent + kExtraIndent) << "'OTHER_CFLAGS': ["; | |
508 WriteArrayValues(out_, flags.cflags); | |
509 WriteArrayValues(out_, flags.cflags_c); | |
510 WriteArrayValues(out_, flags.cflags_objc); | |
511 out_ << " ],\n"; | |
512 } | |
513 if (!flags.cflags.empty() || !flags.cflags_cc.empty() || | |
514 !flags.cflags_objcc.empty()) { | |
515 Indent(indent + kExtraIndent) << "'OTHER_CPLUSPLUSFLAGS': ["; | |
516 WriteArrayValues(out_, flags.cflags); | |
517 WriteArrayValues(out_, flags.cflags_cc); | |
518 WriteArrayValues(out_, flags.cflags_objcc); | |
519 out_ << " ],\n"; | |
520 } | |
521 | |
522 // Ld flags. Don't write these for static libraries. Otherwise, they'll be | |
523 // passed to the library tool which doesn't expect it (the toolchain does | |
524 // not use ldflags so these are ignored in the normal build). | |
525 if (target->output_type() != Target::STATIC_LIBRARY) | |
526 WriteNamedArray("OTHER_LDFLAGS", flags.ldflags, indent + kExtraIndent); | |
527 | |
528 // Write the compiler that XCode should use. When we're using clang, we want | |
529 // the custom one, otherwise don't add this and the default compiler will be | |
530 // used. | |
531 // | |
532 // TODO(brettw) this is a hack. We could add a way for the GN build to set | |
533 // these values but as far as I can see this is the only use for them, so | |
534 // currently we manually check the build config's is_clang value. | |
535 if (IsClang(target)) { | |
536 base::FilePath clang_path = | |
537 target_->settings()->build_settings()->GetFullPath(SourceFile( | |
538 "//third_party/llvm-build/Release+Asserts/bin/clang")); | |
539 base::FilePath clang_pp_path = | |
540 target_->settings()->build_settings()->GetFullPath(SourceFile( | |
541 "//third_party/llvm-build/Release+Asserts/bin/clang++")); | |
542 | |
543 Indent(indent + kExtraIndent) | |
544 << "'CC': '" << FilePathToUTF8(clang_path) << "',\n"; | |
545 Indent(indent + kExtraIndent) | |
546 << "'LDPLUSPLUS': '" << FilePathToUTF8(clang_pp_path) << "',\n"; | |
547 } | |
548 | |
549 Indent(indent) << "},\n"; | |
550 } | |
551 | |
552 void GypBinaryTargetWriter::WriteLinuxFlagsForTarget(const Target* target, | |
553 int indent) { | |
554 Flags flags(FlagsFromTarget(target)); | |
555 WriteLinuxFlags(flags, indent); | |
556 } | |
557 | |
558 void GypBinaryTargetWriter::WriteLinuxFlags(const Flags& flags, int indent) { | |
559 WriteIncludeDirs(flags, indent); | |
560 WriteNamedArray("defines", flags.defines, indent); | |
561 WriteNamedArray("cflags", flags.cflags, indent); | |
562 WriteNamedArray("cflags_c", flags.cflags_c, indent); | |
563 WriteNamedArray("cflags_cc", flags.cflags_cc, indent); | |
564 WriteNamedArray("cflags_objc", flags.cflags_objc, indent); | |
565 WriteNamedArray("cflags_objcc", flags.cflags_objcc, indent); | |
566 | |
567 // Put libraries and library directories in with ldflags. | |
568 Indent(indent) << "'ldflags': ["; \ | |
569 WriteArrayValues(out_, flags.ldflags); | |
570 | |
571 EscapeOptions escape_options; | |
572 escape_options.mode = ESCAPE_JSON; | |
573 for (size_t i = 0; i < flags.lib_dirs.size(); i++) { | |
574 out_ << " '-L"; | |
575 EscapeStringToStream(out_, | |
576 helper_.GetDirReference(flags.lib_dirs[i], false), | |
577 escape_options); | |
578 out_ << "',"; | |
579 } | |
580 | |
581 for (size_t i = 0; i < flags.libs.size(); i++) { | |
582 out_ << " '-l"; | |
583 EscapeStringToStream(out_, flags.libs[i], escape_options); | |
584 out_ << "',"; | |
585 } | |
586 out_ << " ],\n"; | |
587 } | |
588 | |
589 void GypBinaryTargetWriter::WriteMacTargetAndHostFlags( | |
590 const BuilderRecord* target, | |
591 const BuilderRecord* host, | |
592 int indent) { | |
593 // The Mac flags are sometimes (when cross-compiling) also parameterized on | |
594 // the toolset. | |
595 const char kToolsetTargetCondition[] = | |
596 "'target_conditions': [['_toolset==\"target\"', {\n"; | |
597 const char kToolsetTargetElse[] = "}, {\n"; | |
598 const char kToolsetTargetEnd[] = "}]],\n"; | |
599 | |
600 int extra_indent = 0; | |
601 if (host) { | |
602 // Write out the first part of the conditional. | |
603 Indent(indent) << kToolsetTargetCondition; | |
604 extra_indent = kExtraIndent; | |
605 } | |
606 | |
607 // Always write the target flags (may or may not be inside a target | |
608 // conditional). | |
609 { | |
610 Flags flags(FlagsFromTarget(target->item()->AsTarget())); | |
611 WriteMacFlags(target->item()->AsTarget(), flags, indent + extra_indent); | |
612 } | |
613 | |
614 // Now optionally write the host conditional arm. | |
615 if (host) { | |
616 Indent(indent) << kToolsetTargetElse; | |
617 Flags flags(FlagsFromTarget(host->item()->AsTarget())); | |
618 WriteMacFlags(host->item()->AsTarget(), flags, indent + kExtraIndent); | |
619 Indent(indent) << kToolsetTargetEnd; | |
620 } | |
621 } | |
622 | |
623 void GypBinaryTargetWriter::WriteSources(const Target* target, int indent) { | |
624 Indent(indent) << "'sources': [\n"; | |
625 | |
626 const Target::FileList& sources = target->sources(); | |
627 for (size_t i = 0; i < sources.size(); i++) { | |
628 const SourceFile& input_file = sources[i]; | |
629 Indent(indent + kExtraIndent) << "'" << helper_.GetFileReference(input_file) | |
630 << "',\n"; | |
631 } | |
632 | |
633 Indent(indent) << "],\n"; | |
634 } | |
635 | |
636 void GypBinaryTargetWriter::WriteDeps(const Target* target, int indent) { | |
637 const LabelTargetVector& deps = target->deps(); | |
638 if (deps.empty()) | |
639 return; | |
640 | |
641 EscapeOptions escape_options; | |
642 escape_options.mode = ESCAPE_JSON; | |
643 | |
644 Indent(indent) << "'dependencies': [\n"; | |
645 for (size_t i = 0; i < deps.size(); i++) { | |
646 Indent(indent + kExtraIndent) << "'"; | |
647 EscapeStringToStream(out_, helper_.GetFullRefForTarget(deps[i].ptr), | |
648 escape_options); | |
649 out_ << "',\n"; | |
650 } | |
651 Indent(indent) << "],\n"; | |
652 } | |
653 | |
654 void GypBinaryTargetWriter::WriteIncludeDirs(const Flags& flags, int indent) { | |
655 if (flags.include_dirs.empty()) | |
656 return; | |
657 | |
658 EscapeOptions options; | |
659 options.mode = ESCAPE_JSON; | |
660 | |
661 Indent(indent) << "'include_dirs': ["; | |
662 for (size_t i = 0; i < flags.include_dirs.size(); i++) { | |
663 out_ << " '"; | |
664 EscapeStringToStream(out_, | |
665 helper_.GetDirReference(flags.include_dirs[i], false), | |
666 options); | |
667 out_ << "',"; | |
668 } | |
669 out_ << " ],\n"; | |
670 } | |
671 | |
672 void GypBinaryTargetWriter::WriteDirectDependentSettings(int indent) { | |
673 if (target_->direct_dependent_configs().empty()) | |
674 return; | |
675 Indent(indent) << "'direct_dependent_settings': {\n"; | |
676 | |
677 Flags flags(FlagsFromConfigList(target_->direct_dependent_configs())); | |
678 if (target_->settings()->IsLinux()) | |
679 WriteLinuxFlags(flags, indent + kExtraIndent); | |
680 else if (target_->settings()->IsWin()) | |
681 WriteVCFlags(flags, indent + kExtraIndent); | |
682 else if (target_->settings()->IsMac()) | |
683 WriteMacFlags(target_, flags, indent + kExtraIndent); | |
684 Indent(indent) << "},\n"; | |
685 } | |
686 | |
687 void GypBinaryTargetWriter::WriteAllDependentSettings(int indent) { | |
688 if (target_->all_dependent_configs().empty()) | |
689 return; | |
690 Indent(indent) << "'all_dependent_settings': {\n"; | |
691 | |
692 Flags flags(FlagsFromConfigList(target_->all_dependent_configs())); | |
693 if (target_->settings()->IsLinux()) | |
694 WriteLinuxFlags(flags, indent + kExtraIndent); | |
695 else if (target_->settings()->IsWin()) | |
696 WriteVCFlags(flags, indent + kExtraIndent); | |
697 else if (target_->settings()->IsMac()) | |
698 WriteMacFlags(target_, flags, indent + kExtraIndent); | |
699 Indent(indent) << "},\n"; | |
700 } | |
701 | |
702 GypBinaryTargetWriter::Flags GypBinaryTargetWriter::FlagsFromTarget( | |
703 const Target* target) const { | |
704 Flags ret; | |
705 | |
706 // Extracts a vector of the given type and name from the config values. | |
707 #define EXTRACT(type, name) \ | |
708 { \ | |
709 Accumulator<type> acc(&ret.name); \ | |
710 RecursiveTargetConfigToStream<type>(target, &ConfigValues::name, \ | |
711 acc, out_); \ | |
712 } | |
713 | |
714 EXTRACT(std::string, defines); | |
715 EXTRACT(SourceDir, include_dirs); | |
716 EXTRACT(std::string, cflags); | |
717 EXTRACT(std::string, cflags_c); | |
718 EXTRACT(std::string, cflags_cc); | |
719 EXTRACT(std::string, cflags_objc); | |
720 EXTRACT(std::string, cflags_objcc); | |
721 EXTRACT(std::string, ldflags); | |
722 | |
723 #undef EXTRACT | |
724 | |
725 const OrderedSet<SourceDir>& all_lib_dirs = target->all_lib_dirs(); | |
726 for (size_t i = 0; i < all_lib_dirs.size(); i++) | |
727 ret.lib_dirs.push_back(all_lib_dirs[i]); | |
728 | |
729 const OrderedSet<std::string> all_libs = target->all_libs(); | |
730 for (size_t i = 0; i < all_libs.size(); i++) | |
731 ret.libs.push_back(all_libs[i]); | |
732 | |
733 return ret; | |
734 } | |
735 | |
736 GypBinaryTargetWriter::Flags GypBinaryTargetWriter::FlagsFromConfigList( | |
737 const LabelConfigVector& configs) const { | |
738 Flags ret; | |
739 | |
740 #define EXTRACT(type, name) \ | |
741 FillConfigListValues<type>(configs, &ConfigValues::name, &ret.name); | |
742 | |
743 EXTRACT(std::string, defines); | |
744 EXTRACT(SourceDir, include_dirs); | |
745 EXTRACT(std::string, cflags); | |
746 EXTRACT(std::string, cflags_c); | |
747 EXTRACT(std::string, cflags_cc); | |
748 EXTRACT(std::string, cflags_objc); | |
749 EXTRACT(std::string, cflags_objcc); | |
750 EXTRACT(std::string, ldflags); | |
751 EXTRACT(SourceDir, lib_dirs); | |
752 EXTRACT(std::string, libs); | |
753 | |
754 #undef EXTRACT | |
755 | |
756 return ret; | |
757 } | |
758 | |
759 void GypBinaryTargetWriter::WriteNamedArray( | |
760 const char* name, | |
761 const std::vector<std::string>& values, | |
762 int indent) { | |
763 if (values.empty()) | |
764 return; | |
765 | |
766 EscapeOptions options; | |
767 options.mode = ESCAPE_JSON; | |
768 | |
769 Indent(indent) << "'" << name << "': ["; | |
770 WriteArrayValues(out_, values); | |
771 out_ << " ],\n"; | |
772 } | |
773 | |
OLD | NEW |