diff options
Diffstat (limited to 'deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py')
-rw-r--r-- | deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py | 224 |
1 files changed, 170 insertions, 54 deletions
diff --git a/deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py b/deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py index d50eac004..30f27d583 100644 --- a/deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py +++ b/deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py @@ -9,11 +9,13 @@ other build systems, such as make and ninja. import copy import gyp.common +import os import os.path import re import shlex import subprocess import sys +import tempfile from gyp.common import GypError class XcodeSettings(object): @@ -22,6 +24,7 @@ class XcodeSettings(object): # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached # at class-level for efficiency. _sdk_path_cache = {} + _sdk_root_cache = {} # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so # cached at class-level for efficiency. @@ -31,6 +34,10 @@ class XcodeSettings(object): # cached at class-level for efficiency. _codesigning_key_cache = {} + # Populated lazily by _XcodeVersion. Shared by all XcodeSettings, so cached + # at class-level for efficiency. + _xcode_version_cache = () + def __init__(self, spec): self.spec = spec @@ -262,7 +269,7 @@ class XcodeSettings(object): """Returns the architectures this target should be built for.""" # TODO: Look at VALID_ARCHS, ONLY_ACTIVE_ARCH; possibly set # CURRENT_ARCH / NATIVE_ARCH env vars? - return self.xcode_settings[configname].get('ARCHS', ['i386']) + return self.xcode_settings[configname].get('ARCHS', [self._DefaultArch()]) def _GetStdout(self, cmdlist): job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) @@ -291,9 +298,14 @@ class XcodeSettings(object): sdk_root = self._SdkRoot(configname) if sdk_root.startswith('/'): return sdk_root + return self._XcodeSdkPath(sdk_root) + + def _XcodeSdkPath(self, sdk_root): if sdk_root not in XcodeSettings._sdk_path_cache: - XcodeSettings._sdk_path_cache[sdk_root] = self._GetSdkVersionInfoItem( - sdk_root, 'Path') + sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path') + XcodeSettings._sdk_path_cache[sdk_root] = sdk_path + if sdk_root: + XcodeSettings._sdk_root_cache[sdk_path] = sdk_root return XcodeSettings._sdk_path_cache[sdk_root] def _AppendPlatformVersionMinFlags(self, lst): @@ -318,7 +330,7 @@ class XcodeSettings(object): cflags = [] sdk_root = self._SdkPath() - if 'SDKROOT' in self._Settings(): + if 'SDKROOT' in self._Settings() and sdk_root: cflags.append('-isysroot %s' % sdk_root) if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'): @@ -384,7 +396,7 @@ class XcodeSettings(object): if arch is not None: archs = [arch] else: - archs = self._Settings().get('ARCHS', ['i386']) + archs = self._Settings().get('ARCHS', [self._DefaultArch()]) if len(archs) != 1: # TODO: Supporting fat binaries will be annoying. self._WarnUnimplemented('ARCHS') @@ -404,11 +416,14 @@ class XcodeSettings(object): cflags += self._Settings().get('WARNING_CFLAGS', []) - if 'SDKROOT' in self._Settings(): - config = self.spec['configurations'][self.configname] - framework_dirs = config.get('mac_framework_dirs', []) - for directory in framework_dirs: - cflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root)) + if sdk_root: + framework_root = sdk_root + else: + framework_root = '' + config = self.spec['configurations'][self.configname] + framework_dirs = config.get('mac_framework_dirs', []) + for directory in framework_dirs: + cflags.append('-F' + directory.replace('$(SDKROOT)', framework_root)) self.configname = None return cflags @@ -624,7 +639,7 @@ class XcodeSettings(object): self._AppendPlatformVersionMinFlags(ldflags) - if 'SDKROOT' in self._Settings(): + if 'SDKROOT' in self._Settings() and self._SdkPath(): ldflags.append('-isysroot ' + self._SdkPath()) for library_path in self._Settings().get('LIBRARY_SEARCH_PATHS', []): @@ -638,7 +653,7 @@ class XcodeSettings(object): if arch is not None: archs = [arch] else: - archs = self._Settings().get('ARCHS', ['i386']) + archs = self._Settings().get('ARCHS', [self._DefaultArch()]) if len(archs) != 1: # TODO: Supporting fat binaries will be annoying. self._WarnUnimplemented('ARCHS') @@ -655,11 +670,13 @@ class XcodeSettings(object): for rpath in self._Settings().get('LD_RUNPATH_SEARCH_PATHS', []): ldflags.append('-Wl,-rpath,' + rpath) - if 'SDKROOT' in self._Settings(): - config = self.spec['configurations'][self.configname] - framework_dirs = config.get('mac_framework_dirs', []) - for directory in framework_dirs: - ldflags.append('-F' + directory.replace('$(SDKROOT)', self._SdkPath())) + sdk_root = self._SdkPath() + if not sdk_root: + sdk_root = '' + config = self.spec['configurations'][self.configname] + framework_dirs = config.get('mac_framework_dirs', []) + for directory in framework_dirs: + ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root)) self.configname = None return ldflags @@ -789,33 +806,40 @@ class XcodeSettings(object): if not (self.isIOS and self.spec['type'] == "executable"): return [] - identity = self.xcode_settings[configname].get('CODE_SIGN_IDENTITY', '') - if identity == '': + settings = self.xcode_settings[configname] + key = self._GetIOSCodeSignIdentityKey(settings) + if not key: return [] + + # Warn for any unimplemented signing xcode keys. + unimpl = ['OTHER_CODE_SIGN_FLAGS'] + unimpl = set(unimpl) & set(self.xcode_settings[configname].keys()) + if unimpl: + print 'Warning: Some codesign keys not implemented, ignoring: %s' % ( + ', '.join(sorted(unimpl))) + + return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % ( + os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key, + settings.get('CODE_SIGN_RESOURCE_RULES_PATH', ''), + settings.get('CODE_SIGN_ENTITLEMENTS', ''), + settings.get('PROVISIONING_PROFILE', '')) + ] + + def _GetIOSCodeSignIdentityKey(self, settings): + identity = settings.get('CODE_SIGN_IDENTITY') + if not identity: + return None if identity not in XcodeSettings._codesigning_key_cache: - proc = subprocess.Popen(['security', 'find-identity', '-p', 'codesigning', - '-v'], stdout=subprocess.PIPE) - output = proc.communicate()[0].strip() - key = None - for item in output.split("\n"): - if identity in item: - assert key == None, ( - "Multiple codesigning identities for identity: %s" % - identity) - key = item.split(' ')[1] - XcodeSettings._codesigning_key_cache[identity] = key - key = XcodeSettings._codesigning_key_cache[identity] - if key: - # Warn for any unimplemented signing xcode keys. - unimpl = ['CODE_SIGN_RESOURCE_RULES_PATH', 'OTHER_CODE_SIGN_FLAGS', - 'CODE_SIGN_ENTITLEMENTS'] - keys = set(self.xcode_settings[configname].keys()) - unimpl = set(unimpl) & keys - if unimpl: - print 'Warning: Some codesign keys not implemented, ignoring:', \ - ' '.join(unimpl) - return ['codesign --force --sign %s %s' % (key, output_binary)] - return [] + output = subprocess.check_output( + ['security', 'find-identity', '-p', 'codesigning', '-v']) + for line in output.splitlines(): + if identity in line: + fingerprint = line.split()[1] + cache = XcodeSettings._codesigning_key_cache + assert identity not in cache or fingerprint == cache[identity], ( + "Multiple codesigning fingerprints for identity: %s" % identity) + XcodeSettings._codesigning_key_cache[identity] = fingerprint + return XcodeSettings._codesigning_key_cache.get(identity, '') def AddImplicitPostbuilds(self, configname, output, output_binary, postbuilds=[], quiet=False): @@ -835,10 +859,11 @@ class XcodeSettings(object): l = '-l' + m.group(1) else: l = library - if self._SdkPath(): - return l.replace('$(SDKROOT)', self._SdkPath(config_name)) - else: - return l + + sdk_root = self._SdkPath(config_name) + if not sdk_root: + sdk_root = '' + return l.replace('$(SDKROOT)', sdk_root) def AdjustLibraries(self, libraries, config_name=None): """Transforms entries like 'Cocoa.framework' in libraries into entries like @@ -851,6 +876,27 @@ class XcodeSettings(object): def _BuildMachineOSBuild(self): return self._GetStdout(['sw_vers', '-buildVersion']) + # This method ported from the logic in Homebrew's CLT version check + def _CLTVersion(self): + # pkgutil output looks like + # package-id: com.apple.pkg.CLTools_Executables + # version: 5.0.1.0.1.1382131676 + # volume: / + # location: / + # install-time: 1382544035 + # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-group com.apple.DevToolsNonRelocatableShared.pkg-group + STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" + FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" + MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" + + regex = re.compile('version: (?P<version>.+)') + for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: + try: + output = self._GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) + return re.search(regex, output).groupdict()['version'] + except: + continue + def _XcodeVersion(self): # `xcodebuild -version` output looks like # Xcode 4.6.3 @@ -860,14 +906,33 @@ class XcodeSettings(object): # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 # BuildVersion: 10M2518 # Convert that to '0463', '4H1503'. - version_list = self._GetStdout(['xcodebuild', '-version']).splitlines() - version = version_list[0] - build = version_list[-1] - # Be careful to convert "4.2" to "0420": - version = version.split()[-1].replace('.', '') - version = (version + '0' * (3 - len(version))).zfill(4) - build = build.split()[-1] - return version, build + if len(XcodeSettings._xcode_version_cache) == 0: + try: + version_list = self._GetStdout(['xcodebuild', '-version']).splitlines() + # In some circumstances xcodebuild exits 0 but doesn't return + # the right results; for example, a user on 10.7 or 10.8 with + # a bogus path set via xcode-select + # In that case this may be a CLT-only install so fall back to + # checking that version. + if len(version_list) < 2: + raise GypError, "xcodebuild returned unexpected results" + except: + version = self._CLTVersion() + if version: + version = re.match('(\d\.\d\.?\d*)', version).groups()[0] + else: + raise GypError, "No Xcode or CLT version detected!" + # The CLT has no build information, so we return an empty string. + version_list = [version, ''] + version = version_list[0] + build = version_list[-1] + # Be careful to convert "4.2" to "0420": + version = version.split()[-1].replace('.', '') + version = (version + '0' * (3 - len(version))).zfill(4) + if build: + build = build.split()[-1] + XcodeSettings._xcode_version_cache = (version, build) + return XcodeSettings._xcode_version_cache def _XcodeIOSDeviceFamily(self, configname): family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') @@ -884,6 +949,8 @@ class XcodeSettings(object): cache['DTXcodeBuild'] = xcode_build sdk_root = self._SdkRoot(configname) + if not sdk_root: + sdk_root = self._DefaultSdkRoot() cache['DTSDKName'] = sdk_root if xcode >= '0430': cache['DTSDKBuild'] = self._GetSdkVersionInfoItem( @@ -908,6 +975,55 @@ class XcodeSettings(object): items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname) return items + def _DefaultSdkRoot(self): + """Returns the default SDKROOT to use. + + Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode + project, then the environment variable was empty. Starting with this + version, Xcode uses the name of the newest SDK installed. + """ + if self._XcodeVersion() < '0500': + return '' + default_sdk_path = self._XcodeSdkPath('') + default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) + if default_sdk_root: + return default_sdk_root + try: + all_sdks = self._GetStdout(['xcodebuild', '-showsdks']) + except: + # If xcodebuild fails, there will be no valid SDKs + return '' + for line in all_sdks.splitlines(): + items = line.split() + if len(items) >= 3 and items[-2] == '-sdk': + sdk_root = items[-1] + sdk_path = self._XcodeSdkPath(sdk_root) + if sdk_path == default_sdk_path: + return sdk_root + return '' + + def _DefaultArch(self): + # For Mac projects, Xcode changed the default value used when ARCHS is not + # set from "i386" to "x86_64". + # + # For iOS projects, if ARCHS is unset, it defaults to "armv7 armv7s" when + # building for a device, and the simulator binaries are always build for + # "i386". + # + # For new projects, ARCHS is set to $(ARCHS_STANDARD_INCLUDING_64_BIT), + # which correspond to "armv7 armv7s arm64", and when building the simulator + # the architecture is either "i386" or "x86_64" depending on the simulated + # device (respectively 32-bit or 64-bit device). + # + # Since the value returned by this function is only used when ARCHS is not + # set, then on iOS we return "i386", as the default xcode project generator + # does not set ARCHS if it is not set in the .gyp file. + if self.isIOS: + return 'i386' + version, build = self._XcodeVersion() + if version >= '0500': + return 'x86_64' + return 'i386' class MacPrefixHeader(object): """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature. |