OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """ | 5 """ |
6 This module contains classes that help to emulate xcodebuild behavior on top of | 6 This module contains classes that help to emulate xcodebuild behavior on top of |
7 other build systems, such as make and ninja. | 7 other build systems, such as make and ninja. |
8 """ | 8 """ |
9 | 9 |
10 import gyp.common | 10 import gyp.common |
11 import os.path | 11 import os.path |
12 import re | 12 import re |
13 import shlex | 13 import shlex |
14 import subprocess | |
15 import sys | |
16 from gyp.common import GypError | |
14 | 17 |
15 class XcodeSettings(object): | 18 class XcodeSettings(object): |
16 """A class that understands the gyp 'xcode_settings' object.""" | 19 """A class that understands the gyp 'xcode_settings' object.""" |
17 | 20 |
18 # Computed lazily by _GetSdkBaseDir(). Shared by all XcodeSettings, so cached | 21 # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached |
19 # at class-level for efficiency. | 22 # at class-level for efficiency. |
20 _sdk_base_dir = None | 23 _sdk_path_cache = {} |
21 | 24 |
22 def __init__(self, spec): | 25 def __init__(self, spec): |
23 self.spec = spec | 26 self.spec = spec |
24 | 27 |
25 # Per-target 'xcode_settings' are pushed down into configs earlier by gyp. | 28 # Per-target 'xcode_settings' are pushed down into configs earlier by gyp. |
26 # This means self.xcode_settings[config] always contains all settings | 29 # This means self.xcode_settings[config] always contains all settings |
27 # for that config -- the per-target settings as well. Settings that are | 30 # for that config -- the per-target settings as well. Settings that are |
28 # the same for all configs are implicitly per-target settings. | 31 # the same for all configs are implicitly per-target settings. |
29 self.xcode_settings = {} | 32 self.xcode_settings = {} |
30 configs = spec['configurations'] | 33 configs = spec['configurations'] |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 return self._GetStandaloneBinaryPath() | 215 return self._GetStandaloneBinaryPath() |
213 | 216 |
214 def GetExecutablePath(self): | 217 def GetExecutablePath(self): |
215 """Returns the directory name of the bundle represented by this target. E.g. | 218 """Returns the directory name of the bundle represented by this target. E.g. |
216 Chromium.app/Contents/MacOS/Chromium.""" | 219 Chromium.app/Contents/MacOS/Chromium.""" |
217 if self._IsBundle(): | 220 if self._IsBundle(): |
218 return self._GetBundleBinaryPath() | 221 return self._GetBundleBinaryPath() |
219 else: | 222 else: |
220 return self._GetStandaloneBinaryPath() | 223 return self._GetStandaloneBinaryPath() |
221 | 224 |
222 def _GetSdkBaseDir(self): | 225 def _GetSdkVersionInfoItem(self, sdk, infoitem): |
223 """Returns the root of the 'Developer' directory. On Xcode 4.2 and prior, | 226 job = subprocess.Popen(['xcodebuild', '-version', '-sdk', sdk, infoitem], |
Nico
2013/03/18 15:17:05
As it turns out, this doesn't work with Xcode 4.2:
Nico
2013/03/18 15:32:31
Durr, it works if you say "macosx10.6" instead of
kal
2013/03/18 15:32:32
The SDK name is "macosx10.6". "10.6" is not a vali
Nico
2013/04/12 20:28:39
Zombie thread: Why do you redirect stderr at all?
| |
224 this is usually just /Developer. Xcode 4.3 moved that folder into the Xcode | 227 stdout=subprocess.PIPE, |
225 bundle.""" | 228 stderr=subprocess.STDOUT) |
226 if not XcodeSettings._sdk_base_dir: | 229 out = job.communicate()[0] |
227 import subprocess | 230 if job.returncode != 0: |
228 job = subprocess.Popen(['xcode-select', '-print-path'], | 231 sys.stderr.write(out + '\n') |
229 stdout=subprocess.PIPE, | 232 raise GypError('Error %d running xcodebuild' % job.returncode) |
230 stderr=subprocess.STDOUT) | 233 return out.rstrip('\n') |
231 out, err = job.communicate() | |
232 if job.returncode != 0: | |
233 print out | |
234 raise Exception('Error %d running xcode-select' % job.returncode) | |
235 # The Developer folder moved in Xcode 4.3. | |
236 xcode43_sdk_path = os.path.join( | |
237 out.rstrip(), 'Platforms/MacOSX.platform/Developer/SDKs') | |
238 if os.path.isdir(xcode43_sdk_path): | |
239 XcodeSettings._sdk_base_dir = xcode43_sdk_path | |
240 else: | |
241 XcodeSettings._sdk_base_dir = os.path.join(out.rstrip(), 'SDKs') | |
242 return XcodeSettings._sdk_base_dir | |
243 | 234 |
244 def _SdkPath(self): | 235 def _SdkPath(self): |
245 sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx10.5') | 236 sdk_root = self.GetPerTargetSetting('SDKROOT', default='macosx') |
246 if sdk_root.startswith('macosx'): | 237 if sdk_root not in XcodeSettings._sdk_path_cache: |
247 return os.path.join(self._GetSdkBaseDir(), | 238 XcodeSettings._sdk_path_cache[sdk_root] = self._GetSdkVersionInfoItem( |
248 'MacOSX' + sdk_root[len('macosx'):] + '.sdk') | 239 sdk_root, 'Path') |
249 return sdk_root | 240 return XcodeSettings._sdk_path_cache[sdk_root] |
241 | |
242 def _AppendPlatformVersionMinFlags(self, lst): | |
243 self._Appendf(lst, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | |
244 if 'IPHONEOS_DEPLOYMENT_TARGET' in self._Settings(): | |
245 # TODO: Implement this better? | |
Nico
2013/03/13 17:45:25
nit: remove this TODO, it's not actionable and mys
| |
246 sdk_path_basename = os.path.basename(self._SdkPath()) | |
247 if sdk_path_basename.lower().startswith('iphonesimulator'): | |
248 self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', | |
249 '-mios-simulator-version-min=%s') | |
250 else: | |
251 self._Appendf(lst, 'IPHONEOS_DEPLOYMENT_TARGET', | |
252 '-miphoneos-version-min=%s') | |
250 | 253 |
251 def GetCflags(self, configname): | 254 def GetCflags(self, configname): |
252 """Returns flags that need to be added to .c, .cc, .m, and .mm | 255 """Returns flags that need to be added to .c, .cc, .m, and .mm |
253 compilations.""" | 256 compilations.""" |
254 # This functions (and the similar ones below) do not offer complete | 257 # This functions (and the similar ones below) do not offer complete |
255 # emulation of all xcode_settings keys. They're implemented on demand. | 258 # emulation of all xcode_settings keys. They're implemented on demand. |
256 | 259 |
257 self.configname = configname | 260 self.configname = configname |
258 cflags = [] | 261 cflags = [] |
259 | 262 |
260 sdk_root = self._SdkPath() | 263 sdk_root = self._SdkPath() |
261 if 'SDKROOT' in self._Settings(): | 264 if 'SDKROOT' in self._Settings(): |
262 cflags.append('-isysroot %s' % sdk_root) | 265 cflags.append('-isysroot %s' % sdk_root) |
263 | 266 |
267 if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'): | |
268 cflags.append('-Wconstant-conversion') | |
269 | |
264 if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'): | 270 if self._Test('GCC_CHAR_IS_UNSIGNED_CHAR', 'YES', default='NO'): |
265 cflags.append('-funsigned-char') | 271 cflags.append('-funsigned-char') |
266 | 272 |
267 if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'): | 273 if self._Test('GCC_CW_ASM_SYNTAX', 'YES', default='YES'): |
268 cflags.append('-fasm-blocks') | 274 cflags.append('-fasm-blocks') |
269 | 275 |
270 if 'GCC_DYNAMIC_NO_PIC' in self._Settings(): | 276 if 'GCC_DYNAMIC_NO_PIC' in self._Settings(): |
271 if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES': | 277 if self._Settings()['GCC_DYNAMIC_NO_PIC'] == 'YES': |
272 cflags.append('-mdynamic-no-pic') | 278 cflags.append('-mdynamic-no-pic') |
273 else: | 279 else: |
(...skipping 20 matching lines...) Expand all Loading... | |
294 | 300 |
295 if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'): | 301 if self._Test('GCC_SYMBOLS_PRIVATE_EXTERN', 'YES', default='NO'): |
296 cflags.append('-fvisibility=hidden') | 302 cflags.append('-fvisibility=hidden') |
297 | 303 |
298 if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'): | 304 if self._Test('GCC_TREAT_WARNINGS_AS_ERRORS', 'YES', default='NO'): |
299 cflags.append('-Werror') | 305 cflags.append('-Werror') |
300 | 306 |
301 if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'): | 307 if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'): |
302 cflags.append('-Wnewline-eof') | 308 cflags.append('-Wnewline-eof') |
303 | 309 |
304 self._Appendf(cflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | 310 self._AppendPlatformVersionMinFlags(cflags) |
305 | 311 |
306 # TODO: | 312 # TODO: |
307 if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'): | 313 if self._Test('COPY_PHASE_STRIP', 'YES', default='NO'): |
308 self._WarnUnimplemented('COPY_PHASE_STRIP') | 314 self._WarnUnimplemented('COPY_PHASE_STRIP') |
309 self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') | 315 self._WarnUnimplemented('GCC_DEBUGGING_SYMBOLS') |
310 self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') | 316 self._WarnUnimplemented('GCC_ENABLE_OBJC_EXCEPTIONS') |
311 | 317 |
312 # TODO: This is exported correctly, but assigning to it is not supported. | 318 # TODO: This is exported correctly, but assigning to it is not supported. |
313 self._WarnUnimplemented('MACH_O_TYPE') | 319 self._WarnUnimplemented('MACH_O_TYPE') |
314 self._WarnUnimplemented('PRODUCT_TYPE') | 320 self._WarnUnimplemented('PRODUCT_TYPE') |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
347 cflags_c = [] | 353 cflags_c = [] |
348 self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s') | 354 self._Appendf(cflags_c, 'GCC_C_LANGUAGE_STANDARD', '-std=%s') |
349 cflags_c += self._Settings().get('OTHER_CFLAGS', []) | 355 cflags_c += self._Settings().get('OTHER_CFLAGS', []) |
350 self.configname = None | 356 self.configname = None |
351 return cflags_c | 357 return cflags_c |
352 | 358 |
353 def GetCflagsCC(self, configname): | 359 def GetCflagsCC(self, configname): |
354 """Returns flags that need to be added to .cc, and .mm compilations.""" | 360 """Returns flags that need to be added to .cc, and .mm compilations.""" |
355 self.configname = configname | 361 self.configname = configname |
356 cflags_cc = [] | 362 cflags_cc = [] |
363 | |
364 clang_cxx_language_standard = self._Settings().get( | |
365 'CLANG_CXX_LANGUAGE_STANDARD') | |
366 if clang_cxx_language_standard == 'c++0x': | |
367 cflags_cc.append('-std=c++11') | |
368 elif clang_cxx_language_standard == 'gnu++0x': | |
369 cflags_cc.append('-std=gnu++11') | |
370 elif clang_cxx_language_standard: | |
371 cflags_cc.append('-std=%s' % clang_cxx_language_standard) | |
372 | |
373 self._Appendf(cflags_cc, 'CLANG_CXX_LIBRARY', '-stdlib=%s') | |
374 | |
357 if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'): | 375 if self._Test('GCC_ENABLE_CPP_RTTI', 'NO', default='YES'): |
358 cflags_cc.append('-fno-rtti') | 376 cflags_cc.append('-fno-rtti') |
359 if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'): | 377 if self._Test('GCC_ENABLE_CPP_EXCEPTIONS', 'NO', default='YES'): |
360 cflags_cc.append('-fno-exceptions') | 378 cflags_cc.append('-fno-exceptions') |
361 if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'): | 379 if self._Test('GCC_INLINES_ARE_PRIVATE_EXTERN', 'YES', default='NO'): |
362 cflags_cc.append('-fvisibility-inlines-hidden') | 380 cflags_cc.append('-fvisibility-inlines-hidden') |
363 if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'): | 381 if self._Test('GCC_THREADSAFE_STATICS', 'NO', default='YES'): |
364 cflags_cc.append('-fno-threadsafe-statics') | 382 cflags_cc.append('-fno-threadsafe-statics') |
365 if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'): | 383 if self._Test('GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO', 'NO', default='YES'): |
366 cflags_cc.append('-Wno-invalid-offsetof') | 384 cflags_cc.append('-Wno-invalid-offsetof') |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
517 if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'): | 535 if self._Test('DEAD_CODE_STRIPPING', 'YES', default='NO'): |
518 ldflags.append('-Wl,-dead_strip') | 536 ldflags.append('-Wl,-dead_strip') |
519 | 537 |
520 if self._Test('PREBINDING', 'YES', default='NO'): | 538 if self._Test('PREBINDING', 'YES', default='NO'): |
521 ldflags.append('-Wl,-prebind') | 539 ldflags.append('-Wl,-prebind') |
522 | 540 |
523 self._Appendf( | 541 self._Appendf( |
524 ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') | 542 ldflags, 'DYLIB_COMPATIBILITY_VERSION', '-compatibility_version %s') |
525 self._Appendf( | 543 self._Appendf( |
526 ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') | 544 ldflags, 'DYLIB_CURRENT_VERSION', '-current_version %s') |
527 self._Appendf( | 545 |
528 ldflags, 'MACOSX_DEPLOYMENT_TARGET', '-mmacosx-version-min=%s') | 546 self._AppendPlatformVersionMinFlags(ldflags) |
547 | |
529 if 'SDKROOT' in self._Settings(): | 548 if 'SDKROOT' in self._Settings(): |
530 ldflags.append('-isysroot ' + self._SdkPath()) | 549 ldflags.append('-isysroot ' + self._SdkPath()) |
531 | 550 |
532 for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): | 551 for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): |
533 ldflags.append('-L' + gyp_to_build_path(library_path)) | 552 ldflags.append('-L' + gyp_to_build_path(library_path)) |
534 | 553 |
535 if 'ORDER_FILE' in self._Settings(): | 554 if 'ORDER_FILE' in self._Settings(): |
536 ldflags.append('-Wl,-order_file ' + | 555 ldflags.append('-Wl,-order_file ' + |
537 '-Wl,' + gyp_to_build_path( | 556 '-Wl,' + gyp_to_build_path( |
538 self._Settings()['ORDER_FILE'])) | 557 self._Settings()['ORDER_FILE'])) |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1035 return matches | 1054 return matches |
1036 | 1055 |
1037 try: | 1056 try: |
1038 # Topologically sort, and then reverse, because we used an edge definition | 1057 # Topologically sort, and then reverse, because we used an edge definition |
1039 # that's inverted from the expected result of this function (see comment | 1058 # that's inverted from the expected result of this function (see comment |
1040 # above). | 1059 # above). |
1041 order = gyp.common.TopologicallySorted(env.keys(), GetEdges) | 1060 order = gyp.common.TopologicallySorted(env.keys(), GetEdges) |
1042 order.reverse() | 1061 order.reverse() |
1043 return order | 1062 return order |
1044 except gyp.common.CycleError, e: | 1063 except gyp.common.CycleError, e: |
1045 raise Exception( | 1064 raise GypError( |
1046 'Xcode environment variables are cyclically dependent: ' + str(e.nodes)) | 1065 'Xcode environment variables are cyclically dependent: ' + str(e.nodes)) |
1047 | 1066 |
1048 | 1067 |
1049 def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot, | 1068 def GetSortedXcodeEnv(xcode_settings, built_products_dir, srcroot, |
1050 configuration, additional_settings=None): | 1069 configuration, additional_settings=None): |
1051 env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration, | 1070 env = _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration, |
1052 additional_settings) | 1071 additional_settings) |
1053 return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)] | 1072 return [(key, env[key]) for key in _TopologicallySortedEnvVarKeys(env)] |
1054 | 1073 |
1055 | 1074 |
1056 def GetSpecPostbuildCommands(spec, quiet=False): | 1075 def GetSpecPostbuildCommands(spec, quiet=False): |
1057 """Returns the list of postbuilds explicitly defined on |spec|, in a form | 1076 """Returns the list of postbuilds explicitly defined on |spec|, in a form |
1058 executable by a shell.""" | 1077 executable by a shell.""" |
1059 postbuilds = [] | 1078 postbuilds = [] |
1060 for postbuild in spec.get('postbuilds', []): | 1079 for postbuild in spec.get('postbuilds', []): |
1061 if not quiet: | 1080 if not quiet: |
1062 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( | 1081 postbuilds.append('echo POSTBUILD\\(%s\\) %s' % ( |
1063 spec['target_name'], postbuild['postbuild_name'])) | 1082 spec['target_name'], postbuild['postbuild_name'])) |
1064 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) | 1083 postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action'])) |
1065 return postbuilds | 1084 return postbuilds |
OLD | NEW |