summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/node-gyp/gyp/pylib/gyp/xcode_emulation.py
diff options
context:
space:
mode:
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.py224
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.