Source release v3.1.0
This commit is contained in:
557
third_party/gyp/xcode_emulation.py
vendored
557
third_party/gyp/xcode_emulation.py
vendored
@@ -18,12 +18,136 @@ import sys
|
||||
import tempfile
|
||||
from gyp.common import GypError
|
||||
|
||||
# Populated lazily by XcodeVersion, for efficiency, and to fix an issue when
|
||||
# "xcodebuild" is called too quickly (it has been found to return incorrect
|
||||
# version number).
|
||||
XCODE_VERSION_CACHE = None
|
||||
|
||||
# Populated lazily by GetXcodeArchsDefault, to an |XcodeArchsDefault| instance
|
||||
# corresponding to the installed version of Xcode.
|
||||
XCODE_ARCHS_DEFAULT_CACHE = None
|
||||
|
||||
|
||||
def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
|
||||
"""Constructs a dictionary with expansion for $(ARCHS_STANDARD) variable,
|
||||
and optionally for $(ARCHS_STANDARD_INCLUDING_64_BIT)."""
|
||||
mapping = {'$(ARCHS_STANDARD)': archs}
|
||||
if archs_including_64_bit:
|
||||
mapping['$(ARCHS_STANDARD_INCLUDING_64_BIT)'] = archs_including_64_bit
|
||||
return mapping
|
||||
|
||||
class XcodeArchsDefault(object):
|
||||
"""A class to resolve ARCHS variable from xcode_settings, resolving Xcode
|
||||
macros and implementing filtering by VALID_ARCHS. The expansion of macros
|
||||
depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
|
||||
on the version of Xcode.
|
||||
"""
|
||||
|
||||
# Match variable like $(ARCHS_STANDARD).
|
||||
variable_pattern = re.compile(r'\$\([a-zA-Z_][a-zA-Z0-9_]*\)$')
|
||||
|
||||
def __init__(self, default, mac, iphonesimulator, iphoneos):
|
||||
self._default = (default,)
|
||||
self._archs = {'mac': mac, 'ios': iphoneos, 'iossim': iphonesimulator}
|
||||
|
||||
def _VariableMapping(self, sdkroot):
|
||||
"""Returns the dictionary of variable mapping depending on the SDKROOT."""
|
||||
sdkroot = sdkroot.lower()
|
||||
if 'iphoneos' in sdkroot:
|
||||
return self._archs['ios']
|
||||
elif 'iphonesimulator' in sdkroot:
|
||||
return self._archs['iossim']
|
||||
else:
|
||||
return self._archs['mac']
|
||||
|
||||
def _ExpandArchs(self, archs, sdkroot):
|
||||
"""Expands variables references in ARCHS, and remove duplicates."""
|
||||
variable_mapping = self._VariableMapping(sdkroot)
|
||||
expanded_archs = []
|
||||
for arch in archs:
|
||||
if self.variable_pattern.match(arch):
|
||||
variable = arch
|
||||
try:
|
||||
variable_expansion = variable_mapping[variable]
|
||||
for arch in variable_expansion:
|
||||
if arch not in expanded_archs:
|
||||
expanded_archs.append(arch)
|
||||
except KeyError as e:
|
||||
print 'Warning: Ignoring unsupported variable "%s".' % variable
|
||||
elif arch not in expanded_archs:
|
||||
expanded_archs.append(arch)
|
||||
return expanded_archs
|
||||
|
||||
def ActiveArchs(self, archs, valid_archs, sdkroot):
|
||||
"""Expands variables references in ARCHS, and filter by VALID_ARCHS if it
|
||||
is defined (if not set, Xcode accept any value in ARCHS, otherwise, only
|
||||
values present in VALID_ARCHS are kept)."""
|
||||
expanded_archs = self._ExpandArchs(archs or self._default, sdkroot or '')
|
||||
if valid_archs:
|
||||
filtered_archs = []
|
||||
for arch in expanded_archs:
|
||||
if arch in valid_archs:
|
||||
filtered_archs.append(arch)
|
||||
expanded_archs = filtered_archs
|
||||
return expanded_archs
|
||||
|
||||
|
||||
def GetXcodeArchsDefault():
|
||||
"""Returns the |XcodeArchsDefault| object to use to expand ARCHS for the
|
||||
installed version of Xcode. The default values used by Xcode for ARCHS
|
||||
and the expansion of the variables depends on the version of Xcode used.
|
||||
|
||||
For all version anterior to Xcode 5.0 or posterior to Xcode 5.1 included
|
||||
uses $(ARCHS_STANDARD) if ARCHS is unset, while Xcode 5.0 to 5.0.2 uses
|
||||
$(ARCHS_STANDARD_INCLUDING_64_BIT). This variable was added to Xcode 5.0
|
||||
and deprecated with Xcode 5.1.
|
||||
|
||||
For "macosx" SDKROOT, all version starting with Xcode 5.0 includes 64-bit
|
||||
architecture as part of $(ARCHS_STANDARD) and default to only building it.
|
||||
|
||||
For "iphoneos" and "iphonesimulator" SDKROOT, 64-bit architectures are part
|
||||
of $(ARCHS_STANDARD_INCLUDING_64_BIT) from Xcode 5.0. From Xcode 5.1, they
|
||||
are also part of $(ARCHS_STANDARD).
|
||||
|
||||
All thoses rules are coded in the construction of the |XcodeArchsDefault|
|
||||
object to use depending on the version of Xcode detected. The object is
|
||||
for performance reason."""
|
||||
global XCODE_ARCHS_DEFAULT_CACHE
|
||||
if XCODE_ARCHS_DEFAULT_CACHE:
|
||||
return XCODE_ARCHS_DEFAULT_CACHE
|
||||
xcode_version, _ = XcodeVersion()
|
||||
if xcode_version < '0500':
|
||||
XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
|
||||
'$(ARCHS_STANDARD)',
|
||||
XcodeArchsVariableMapping(['i386']),
|
||||
XcodeArchsVariableMapping(['i386']),
|
||||
XcodeArchsVariableMapping(['armv7']))
|
||||
elif xcode_version < '0510':
|
||||
XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
|
||||
'$(ARCHS_STANDARD_INCLUDING_64_BIT)',
|
||||
XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
|
||||
XcodeArchsVariableMapping(['i386'], ['i386', 'x86_64']),
|
||||
XcodeArchsVariableMapping(
|
||||
['armv7', 'armv7s'],
|
||||
['armv7', 'armv7s', 'arm64']))
|
||||
else:
|
||||
XCODE_ARCHS_DEFAULT_CACHE = XcodeArchsDefault(
|
||||
'$(ARCHS_STANDARD)',
|
||||
XcodeArchsVariableMapping(['x86_64'], ['x86_64']),
|
||||
XcodeArchsVariableMapping(['i386', 'x86_64'], ['i386', 'x86_64']),
|
||||
XcodeArchsVariableMapping(
|
||||
['armv7', 'armv7s', 'arm64'],
|
||||
['armv7', 'armv7s', 'arm64']))
|
||||
return XCODE_ARCHS_DEFAULT_CACHE
|
||||
|
||||
|
||||
class XcodeSettings(object):
|
||||
"""A class that understands the gyp 'xcode_settings' object."""
|
||||
|
||||
# Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
|
||||
# at class-level for efficiency.
|
||||
_sdk_path_cache = {}
|
||||
_platform_path_cache = {}
|
||||
_sdk_root_cache = {}
|
||||
|
||||
# Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
|
||||
@@ -34,14 +158,12 @@ 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
|
||||
|
||||
self.isIOS = False
|
||||
self.mac_toolchain_dir = None
|
||||
self.header_map_path = None
|
||||
|
||||
# Per-target 'xcode_settings' are pushed down into configs earlier by gyp.
|
||||
# This means self.xcode_settings[config] always contains all settings
|
||||
@@ -96,8 +218,34 @@ class XcodeSettings(object):
|
||||
if test_key in self._Settings():
|
||||
print 'Warning: Ignoring not yet implemented key "%s".' % test_key
|
||||
|
||||
def IsBinaryOutputFormat(self, configname):
|
||||
default = "binary" if self.isIOS else "xml"
|
||||
format = self.xcode_settings[configname].get('INFOPLIST_OUTPUT_FORMAT',
|
||||
default)
|
||||
return format == "binary"
|
||||
|
||||
def IsIosFramework(self):
|
||||
return self.spec['type'] == 'shared_library' and self._IsBundle() and \
|
||||
self.isIOS
|
||||
|
||||
def _IsBundle(self):
|
||||
return int(self.spec.get('mac_bundle', 0)) != 0
|
||||
return int(self.spec.get('mac_bundle', 0)) != 0 or self._IsXCTest() or \
|
||||
self._IsXCUiTest()
|
||||
|
||||
def _IsXCTest(self):
|
||||
return int(self.spec.get('mac_xctest_bundle', 0)) != 0
|
||||
|
||||
def _IsXCUiTest(self):
|
||||
return int(self.spec.get('mac_xcuitest_bundle', 0)) != 0
|
||||
|
||||
def _IsIosAppExtension(self):
|
||||
return int(self.spec.get('ios_app_extension', 0)) != 0
|
||||
|
||||
def _IsIosWatchKitExtension(self):
|
||||
return int(self.spec.get('ios_watchkit_extension', 0)) != 0
|
||||
|
||||
def _IsIosWatchApp(self):
|
||||
return int(self.spec.get('ios_watch_app', 0)) != 0
|
||||
|
||||
def GetFrameworkVersion(self):
|
||||
"""Returns the framework version of the current target. Only valid for
|
||||
@@ -118,7 +266,10 @@ class XcodeSettings(object):
|
||||
'WRAPPER_EXTENSION', default=default_wrapper_extension)
|
||||
return '.' + self.spec.get('product_extension', wrapper_extension)
|
||||
elif self.spec['type'] == 'executable':
|
||||
return '.' + self.spec.get('product_extension', 'app')
|
||||
if self._IsIosAppExtension() or self._IsIosWatchKitExtension():
|
||||
return '.' + self.spec.get('product_extension', 'appex')
|
||||
else:
|
||||
return '.' + self.spec.get('product_extension', 'app')
|
||||
else:
|
||||
assert False, "Don't know extension for '%s', target '%s'" % (
|
||||
self.spec['type'], self.spec['target_name'])
|
||||
@@ -165,7 +316,8 @@ class XcodeSettings(object):
|
||||
"""Returns the qualified path to the bundle's plist file. E.g.
|
||||
Chromium.app/Contents/Info.plist. Only valid for bundles."""
|
||||
assert self._IsBundle()
|
||||
if self.spec['type'] in ('executable', 'loadable_module'):
|
||||
if self.spec['type'] in ('executable', 'loadable_module') or \
|
||||
self.IsIosFramework():
|
||||
return os.path.join(self.GetBundleContentsFolderPath(), 'Info.plist')
|
||||
else:
|
||||
return os.path.join(self.GetBundleContentsFolderPath(),
|
||||
@@ -173,6 +325,22 @@ class XcodeSettings(object):
|
||||
|
||||
def GetProductType(self):
|
||||
"""Returns the PRODUCT_TYPE of this target."""
|
||||
if self._IsIosAppExtension():
|
||||
assert self._IsBundle(), ('ios_app_extension flag requires mac_bundle '
|
||||
'(target %s)' % self.spec['target_name'])
|
||||
return 'com.apple.product-type.app-extension'
|
||||
if self._IsIosWatchKitExtension():
|
||||
assert self._IsBundle(), ('ios_watchkit_extension flag requires '
|
||||
'mac_bundle (target %s)' % self.spec['target_name'])
|
||||
return 'com.apple.product-type.watchkit-extension'
|
||||
if self._IsIosWatchApp():
|
||||
assert self._IsBundle(), ('ios_watch_app flag requires mac_bundle '
|
||||
'(target %s)' % self.spec['target_name'])
|
||||
return 'com.apple.product-type.application.watchapp'
|
||||
if self._IsXCUiTest():
|
||||
assert self._IsBundle(), ('mac_xcuitest_bundle flag requires mac_bundle '
|
||||
'(target %s)' % self.spec['target_name'])
|
||||
return 'com.apple.product-type.bundle.ui-testing'
|
||||
if self._IsBundle():
|
||||
return {
|
||||
'executable': 'com.apple.product-type.application',
|
||||
@@ -267,17 +435,12 @@ class XcodeSettings(object):
|
||||
|
||||
def GetActiveArchs(self, configname):
|
||||
"""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', [self._DefaultArch()])
|
||||
|
||||
def _GetStdout(self, cmdlist):
|
||||
job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
|
||||
out = job.communicate()[0]
|
||||
if job.returncode != 0:
|
||||
sys.stderr.write(out + '\n')
|
||||
raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
|
||||
return out.rstrip('\n')
|
||||
config_settings = self.xcode_settings[configname]
|
||||
xcode_archs_default = GetXcodeArchsDefault()
|
||||
return xcode_archs_default.ActiveArchs(
|
||||
config_settings.get('ARCHS'),
|
||||
config_settings.get('VALID_ARCHS'),
|
||||
config_settings.get('SDKROOT'))
|
||||
|
||||
def _GetSdkVersionInfoItem(self, sdk, infoitem):
|
||||
# xcodebuild requires Xcode and can't run on Command Line Tools-only
|
||||
@@ -285,7 +448,7 @@ class XcodeSettings(object):
|
||||
# Since the CLT has no SDK paths anyway, returning None is the
|
||||
# most sensible route and should still do the right thing.
|
||||
try:
|
||||
return self._GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem])
|
||||
return GetStdout(['xcrun', '--sdk', sdk, infoitem])
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -294,6 +457,14 @@ class XcodeSettings(object):
|
||||
configname = self.configname
|
||||
return self.GetPerConfigSetting('SDKROOT', configname, default='')
|
||||
|
||||
def _XcodePlatformPath(self, configname=None):
|
||||
sdk_root = self._SdkRoot(configname)
|
||||
if sdk_root not in XcodeSettings._platform_path_cache:
|
||||
platform_path = self._GetSdkVersionInfoItem(sdk_root,
|
||||
'--show-sdk-platform-path')
|
||||
XcodeSettings._platform_path_cache[sdk_root] = platform_path
|
||||
return XcodeSettings._platform_path_cache[sdk_root]
|
||||
|
||||
def _SdkPath(self, configname=None):
|
||||
sdk_root = self._SdkRoot(configname)
|
||||
if sdk_root.startswith('/'):
|
||||
@@ -302,7 +473,7 @@ class XcodeSettings(object):
|
||||
|
||||
def _XcodeSdkPath(self, sdk_root):
|
||||
if sdk_root not in XcodeSettings._sdk_path_cache:
|
||||
sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path')
|
||||
sdk_path = self._GetSdkVersionInfoItem(sdk_root, '--show-sdk-path')
|
||||
XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
|
||||
if sdk_root:
|
||||
XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
|
||||
@@ -333,6 +504,9 @@ class XcodeSettings(object):
|
||||
if 'SDKROOT' in self._Settings() and sdk_root:
|
||||
cflags.append('-isysroot %s' % sdk_root)
|
||||
|
||||
if self.header_map_path:
|
||||
cflags.append('-I%s' % self.header_map_path)
|
||||
|
||||
if self._Test('CLANG_WARN_CONSTANT_CONVERSION', 'YES', default='NO'):
|
||||
cflags.append('-Wconstant-conversion')
|
||||
|
||||
@@ -381,6 +555,13 @@ class XcodeSettings(object):
|
||||
if self._Test('GCC_WARN_ABOUT_MISSING_NEWLINE', 'YES', default='NO'):
|
||||
cflags.append('-Wnewline-eof')
|
||||
|
||||
# In Xcode, this is only activated when GCC_COMPILER_VERSION is clang or
|
||||
# llvm-gcc. It also requires a fairly recent libtool, and
|
||||
# if the system clang isn't used, DYLD_LIBRARY_PATH needs to contain the
|
||||
# path to the libLTO.dylib that matches the used clang.
|
||||
if self._Test('LLVM_LTO', 'YES', default='NO'):
|
||||
cflags.append('-flto')
|
||||
|
||||
self._AppendPlatformVersionMinFlags(cflags)
|
||||
|
||||
# TODO:
|
||||
@@ -396,7 +577,8 @@ class XcodeSettings(object):
|
||||
if arch is not None:
|
||||
archs = [arch]
|
||||
else:
|
||||
archs = self._Settings().get('ARCHS', [self._DefaultArch()])
|
||||
assert self.configname
|
||||
archs = self.GetActiveArchs(self.configname)
|
||||
if len(archs) != 1:
|
||||
# TODO: Supporting fat binaries will be annoying.
|
||||
self._WarnUnimplemented('ARCHS')
|
||||
@@ -416,6 +598,10 @@ class XcodeSettings(object):
|
||||
|
||||
cflags += self._Settings().get('WARNING_CFLAGS', [])
|
||||
|
||||
platform_root = self._XcodePlatformPath(configname)
|
||||
if platform_root and self._IsXCTest():
|
||||
cflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
|
||||
|
||||
if sdk_root:
|
||||
framework_root = sdk_root
|
||||
else:
|
||||
@@ -588,8 +774,8 @@ class XcodeSettings(object):
|
||||
# -exported_symbols_list file
|
||||
# -Wl,exported_symbols_list file
|
||||
# -Wl,exported_symbols_list,file
|
||||
LINKER_FILE = '(\S+)'
|
||||
WORD = '\S+'
|
||||
LINKER_FILE = r'(\S+)'
|
||||
WORD = r'\S+'
|
||||
linker_flags = [
|
||||
['-exported_symbols_list', LINKER_FILE], # Needed for NaCl.
|
||||
['-unexported_symbols_list', LINKER_FILE],
|
||||
@@ -653,7 +839,8 @@ class XcodeSettings(object):
|
||||
if arch is not None:
|
||||
archs = [arch]
|
||||
else:
|
||||
archs = self._Settings().get('ARCHS', [self._DefaultArch()])
|
||||
assert self.configname
|
||||
archs = self.GetActiveArchs(self.configname)
|
||||
if len(archs) != 1:
|
||||
# TODO: Supporting fat binaries will be annoying.
|
||||
self._WarnUnimplemented('ARCHS')
|
||||
@@ -661,7 +848,8 @@ class XcodeSettings(object):
|
||||
ldflags.append('-arch ' + archs[0])
|
||||
|
||||
# Xcode adds the product directory by default.
|
||||
ldflags.append('-L' + product_dir)
|
||||
# Rewrite -L. to -L./ to work around http://www.openradar.me/25313838
|
||||
ldflags.append('-L' + (product_dir if product_dir != '.' else './'))
|
||||
|
||||
install_name = self.GetInstallName()
|
||||
if install_name and self.spec['type'] != 'loadable_module':
|
||||
@@ -678,6 +866,27 @@ class XcodeSettings(object):
|
||||
for directory in framework_dirs:
|
||||
ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
|
||||
|
||||
platform_root = self._XcodePlatformPath(configname)
|
||||
if sdk_root and platform_root and self._IsXCTest():
|
||||
ldflags.append('-F' + platform_root + '/Developer/Library/Frameworks/')
|
||||
ldflags.append('-framework XCTest')
|
||||
|
||||
is_extension = self._IsIosAppExtension() or self._IsIosWatchKitExtension()
|
||||
if sdk_root and is_extension:
|
||||
# Adds the link flags for extensions. These flags are common for all
|
||||
# extensions and provide loader and main function.
|
||||
# These flags reflect the compilation options used by xcode to compile
|
||||
# extensions.
|
||||
if XcodeVersion() < '0900':
|
||||
ldflags.append('-lpkstart')
|
||||
ldflags.append(sdk_root +
|
||||
'/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
|
||||
else:
|
||||
ldflags.append('-e _NSExtensionMain')
|
||||
ldflags.append('-fapplication-extension')
|
||||
|
||||
self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
|
||||
|
||||
self.configname = None
|
||||
return ldflags
|
||||
|
||||
@@ -748,7 +957,8 @@ class XcodeSettings(object):
|
||||
self._Test('STRIP_INSTALLED_PRODUCT', 'YES', default='NO')):
|
||||
|
||||
default_strip_style = 'debugging'
|
||||
if self.spec['type'] == 'loadable_module' and self._IsBundle():
|
||||
if ((self.spec['type'] == 'loadable_module' or self._IsIosAppExtension())
|
||||
and self._IsBundle()):
|
||||
default_strip_style = 'non-global'
|
||||
elif self.spec['type'] == 'executable':
|
||||
default_strip_style = 'all'
|
||||
@@ -803,13 +1013,25 @@ class XcodeSettings(object):
|
||||
"""Return a shell command to codesign the iOS output binary so it can
|
||||
be deployed to a device. This should be run as the very last step of the
|
||||
build."""
|
||||
if not (self.isIOS and self.spec['type'] == "executable"):
|
||||
if not (self.isIOS and
|
||||
(self.spec['type'] == 'executable' or self._IsXCTest()) or
|
||||
self.IsIosFramework()):
|
||||
return []
|
||||
|
||||
postbuilds = []
|
||||
product_name = self.GetFullProductName()
|
||||
settings = self.xcode_settings[configname]
|
||||
|
||||
# Xcode expects XCTests to be copied into the TEST_HOST dir.
|
||||
if self._IsXCTest():
|
||||
source = os.path.join("${BUILT_PRODUCTS_DIR}", product_name)
|
||||
test_host = os.path.dirname(settings.get('TEST_HOST'));
|
||||
xctest_destination = os.path.join(test_host, 'PlugIns', product_name)
|
||||
postbuilds.extend(['ditto %s %s' % (source, xctest_destination)])
|
||||
|
||||
key = self._GetIOSCodeSignIdentityKey(settings)
|
||||
if not key:
|
||||
return []
|
||||
return postbuilds
|
||||
|
||||
# Warn for any unimplemented signing xcode keys.
|
||||
unimpl = ['OTHER_CODE_SIGN_FLAGS']
|
||||
@@ -818,12 +1040,41 @@ class XcodeSettings(object):
|
||||
print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
|
||||
', '.join(sorted(unimpl)))
|
||||
|
||||
return ['%s code-sign-bundle "%s" "%s" "%s" "%s"' % (
|
||||
if self._IsXCTest():
|
||||
# For device xctests, Xcode copies two extra frameworks into $TEST_HOST.
|
||||
test_host = os.path.dirname(settings.get('TEST_HOST'));
|
||||
frameworks_dir = os.path.join(test_host, 'Frameworks')
|
||||
platform_root = self._XcodePlatformPath(configname)
|
||||
frameworks = \
|
||||
['Developer/Library/PrivateFrameworks/IDEBundleInjection.framework',
|
||||
'Developer/Library/Frameworks/XCTest.framework']
|
||||
for framework in frameworks:
|
||||
source = os.path.join(platform_root, framework)
|
||||
destination = os.path.join(frameworks_dir, os.path.basename(framework))
|
||||
postbuilds.extend(['ditto %s %s' % (source, destination)])
|
||||
|
||||
# Then re-sign everything with 'preserve=True'
|
||||
postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
|
||||
os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
|
||||
settings.get('CODE_SIGN_ENTITLEMENTS', ''),
|
||||
settings.get('PROVISIONING_PROFILE', ''), destination, True)
|
||||
])
|
||||
plugin_dir = os.path.join(test_host, 'PlugIns')
|
||||
targets = [os.path.join(plugin_dir, product_name), test_host]
|
||||
for target in targets:
|
||||
postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
|
||||
os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
|
||||
settings.get('CODE_SIGN_ENTITLEMENTS', ''),
|
||||
settings.get('PROVISIONING_PROFILE', ''), target, True)
|
||||
])
|
||||
|
||||
postbuilds.extend(['%s code-sign-bundle "%s" "%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', ''))
|
||||
]
|
||||
settings.get('PROVISIONING_PROFILE', ''),
|
||||
os.path.join("${BUILT_PRODUCTS_DIR}", product_name), False)
|
||||
])
|
||||
return postbuilds
|
||||
|
||||
def _GetIOSCodeSignIdentityKey(self, settings):
|
||||
identity = settings.get('CODE_SIGN_IDENTITY')
|
||||
@@ -863,7 +1114,23 @@ class XcodeSettings(object):
|
||||
sdk_root = self._SdkPath(config_name)
|
||||
if not sdk_root:
|
||||
sdk_root = ''
|
||||
return l.replace('$(SDKROOT)', sdk_root)
|
||||
# Xcode 7 started shipping with ".tbd" (text based stubs) files instead of
|
||||
# ".dylib" without providing a real support for them. What it does, for
|
||||
# "/usr/lib" libraries, is do "-L/usr/lib -lname" which is dependent on the
|
||||
# library order and cause collision when building Chrome.
|
||||
#
|
||||
# Instead substitude ".tbd" to ".dylib" in the generated project when the
|
||||
# following conditions are both true:
|
||||
# - library is referenced in the gyp file as "$(SDKROOT)/**/*.dylib",
|
||||
# - the ".dylib" file does not exists but a ".tbd" file do.
|
||||
library = l.replace('$(SDKROOT)', sdk_root)
|
||||
if l.startswith('$(SDKROOT)'):
|
||||
basename, ext = os.path.splitext(library)
|
||||
if ext == '.dylib' and not os.path.exists(library):
|
||||
tbd_library = basename + '.tbd'
|
||||
if os.path.exists(tbd_library):
|
||||
library = tbd_library
|
||||
return library
|
||||
|
||||
def AdjustLibraries(self, libraries, config_name=None):
|
||||
"""Transforms entries like 'Cocoa.framework' in libraries into entries like
|
||||
@@ -874,65 +1141,7 @@ class XcodeSettings(object):
|
||||
return libraries
|
||||
|
||||
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
|
||||
# Build version 4H1503
|
||||
# or like
|
||||
# Xcode 3.2.6
|
||||
# Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
|
||||
# BuildVersion: 10M2518
|
||||
# Convert that to '0463', '4H1503'.
|
||||
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
|
||||
return GetStdout(['sw_vers', '-buildVersion'])
|
||||
|
||||
def _XcodeIOSDeviceFamily(self, configname):
|
||||
family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1')
|
||||
@@ -944,28 +1153,40 @@ class XcodeSettings(object):
|
||||
cache = {}
|
||||
cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild()
|
||||
|
||||
xcode, xcode_build = self._XcodeVersion()
|
||||
xcode, xcode_build = XcodeVersion()
|
||||
cache['DTXcode'] = xcode
|
||||
cache['DTXcodeBuild'] = xcode_build
|
||||
compiler = self.xcode_settings[configname].get('GCC_VERSION')
|
||||
if compiler is not None:
|
||||
cache['DTCompiler'] = compiler
|
||||
|
||||
sdk_root = self._SdkRoot(configname)
|
||||
if not sdk_root:
|
||||
sdk_root = self._DefaultSdkRoot()
|
||||
cache['DTSDKName'] = sdk_root
|
||||
if xcode >= '0430':
|
||||
sdk_version = self._GetSdkVersionInfoItem(sdk_root, '--show-sdk-version')
|
||||
cache['DTSDKName'] = sdk_root + (sdk_version or '')
|
||||
if xcode >= '0720':
|
||||
cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
|
||||
sdk_root, 'ProductBuildVersion')
|
||||
sdk_root, '--show-sdk-build-version')
|
||||
elif xcode >= '0430':
|
||||
cache['DTSDKBuild'] = sdk_version
|
||||
else:
|
||||
cache['DTSDKBuild'] = cache['BuildMachineOSBuild']
|
||||
|
||||
if self.isIOS:
|
||||
cache['DTPlatformName'] = cache['DTSDKName']
|
||||
cache['MinimumOSVersion'] = self.xcode_settings[configname].get(
|
||||
'IPHONEOS_DEPLOYMENT_TARGET')
|
||||
cache['DTPlatformName'] = sdk_root
|
||||
cache['DTPlatformVersion'] = sdk_version
|
||||
|
||||
if configname.endswith("iphoneos"):
|
||||
cache['DTPlatformVersion'] = self._GetSdkVersionInfoItem(
|
||||
sdk_root, 'ProductVersion')
|
||||
cache['CFBundleSupportedPlatforms'] = ['iPhoneOS']
|
||||
cache['DTPlatformBuild'] = cache['DTSDKBuild']
|
||||
else:
|
||||
cache['CFBundleSupportedPlatforms'] = ['iPhoneSimulator']
|
||||
# This is weird, but Xcode sets DTPlatformBuild to an empty field
|
||||
# for simulator builds.
|
||||
cache['DTPlatformBuild'] = ""
|
||||
XcodeSettings._plist_cache[configname] = cache
|
||||
|
||||
# Include extra plist items that are per-target, not per global
|
||||
@@ -982,14 +1203,15 @@ class XcodeSettings(object):
|
||||
project, then the environment variable was empty. Starting with this
|
||||
version, Xcode uses the name of the newest SDK installed.
|
||||
"""
|
||||
if self._XcodeVersion() < '0500':
|
||||
xcode_version, xcode_build = XcodeVersion()
|
||||
if xcode_version < '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'])
|
||||
all_sdks = GetStdout(['xcodebuild', '-showsdks'])
|
||||
except:
|
||||
# If xcodebuild fails, there will be no valid SDKs
|
||||
return ''
|
||||
@@ -1002,28 +1224,6 @@ class XcodeSettings(object):
|
||||
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.
|
||||
@@ -1131,6 +1331,81 @@ class MacPrefixHeader(object):
|
||||
]
|
||||
|
||||
|
||||
def XcodeVersion():
|
||||
"""Returns a tuple of version and build version of installed Xcode."""
|
||||
# `xcodebuild -version` output looks like
|
||||
# Xcode 4.6.3
|
||||
# Build version 4H1503
|
||||
# or like
|
||||
# Xcode 3.2.6
|
||||
# Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0
|
||||
# BuildVersion: 10M2518
|
||||
# Convert that to '0463', '4H1503'.
|
||||
global XCODE_VERSION_CACHE
|
||||
if XCODE_VERSION_CACHE:
|
||||
return XCODE_VERSION_CACHE
|
||||
try:
|
||||
version_list = 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 = CLTVersion()
|
||||
if version:
|
||||
version = re.match(r'(\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]
|
||||
XCODE_VERSION_CACHE = (version, build)
|
||||
return XCODE_VERSION_CACHE
|
||||
|
||||
|
||||
# This function ported from the logic in Homebrew's CLT version check
|
||||
def CLTVersion():
|
||||
"""Returns the version of command-line tools from pkgutil."""
|
||||
# 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 = GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key])
|
||||
return re.search(regex, output).groupdict()['version']
|
||||
except:
|
||||
continue
|
||||
|
||||
|
||||
def GetStdout(cmdlist):
|
||||
"""Returns the content of standard output returned by invoking |cmdlist|.
|
||||
Raises |GypError| if the command return with a non-zero return code."""
|
||||
job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE)
|
||||
out = job.communicate()[0]
|
||||
if job.returncode != 0:
|
||||
sys.stderr.write(out + '\n')
|
||||
raise GypError('Error %d running %s' % (job.returncode, cmdlist[0]))
|
||||
return out.rstrip('\n')
|
||||
|
||||
|
||||
def MergeGlobalXcodeSettingsToSpec(global_dict, spec):
|
||||
"""Merges the global xcode_settings dictionary into each configuration of the
|
||||
target represented by spec. For keys that are both in the global and the local
|
||||
@@ -1153,7 +1428,10 @@ def IsMacBundle(flavor, spec):
|
||||
Bundles are directories with a certain subdirectory structure, instead of
|
||||
just a single file. Bundle rules do not produce a binary but also package
|
||||
resources into that directory."""
|
||||
is_mac_bundle = (int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
|
||||
is_mac_bundle = int(spec.get('mac_xctest_bundle', 0)) != 0 or \
|
||||
int(spec.get('mac_xcuitest_bundle', 0)) != 0 or \
|
||||
(int(spec.get('mac_bundle', 0)) != 0 and flavor == 'mac')
|
||||
|
||||
if is_mac_bundle:
|
||||
assert spec['type'] != 'none', (
|
||||
'mac_bundle targets cannot have type none (target "%s")' %
|
||||
@@ -1271,6 +1549,7 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
|
||||
|
||||
# These are filled in on a as-needed basis.
|
||||
env = {
|
||||
'BUILT_FRAMEWORKS_DIR' : built_products_dir,
|
||||
'BUILT_PRODUCTS_DIR' : built_products_dir,
|
||||
'CONFIGURATION' : configuration,
|
||||
'PRODUCT_NAME' : xcode_settings.GetProductName(),
|
||||
@@ -1281,12 +1560,16 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
|
||||
# written for bundles:
|
||||
'TARGET_BUILD_DIR' : built_products_dir,
|
||||
'TEMP_DIR' : '${TMPDIR}',
|
||||
'XCODE_VERSION_ACTUAL' : XcodeVersion()[0],
|
||||
}
|
||||
if xcode_settings.GetPerConfigSetting('SDKROOT', configuration):
|
||||
env['SDKROOT'] = xcode_settings._SdkPath(configuration)
|
||||
else:
|
||||
env['SDKROOT'] = ''
|
||||
|
||||
if xcode_settings.mac_toolchain_dir:
|
||||
env['DEVELOPER_DIR'] = xcode_settings.mac_toolchain_dir
|
||||
|
||||
if spec['type'] in (
|
||||
'executable', 'static_library', 'shared_library', 'loadable_module'):
|
||||
env['EXECUTABLE_NAME'] = xcode_settings.GetExecutableName()
|
||||
@@ -1310,6 +1593,11 @@ def _GetXcodeEnv(xcode_settings, built_products_dir, srcroot, configuration,
|
||||
install_name_base = xcode_settings.GetInstallNameBase()
|
||||
if install_name_base:
|
||||
env['DYLIB_INSTALL_NAME_BASE'] = install_name_base
|
||||
if XcodeVersion() >= '0500' and not env.get('SDKROOT'):
|
||||
sdk_root = xcode_settings._SdkRoot(configuration)
|
||||
if not sdk_root:
|
||||
sdk_root = xcode_settings._XcodeSdkPath('')
|
||||
env['SDKROOT'] = sdk_root
|
||||
|
||||
if not additional_settings:
|
||||
additional_settings = {}
|
||||
@@ -1420,16 +1708,17 @@ def _HasIOSTarget(targets):
|
||||
|
||||
def _AddIOSDeviceConfigurations(targets):
|
||||
"""Clone all targets and append -iphoneos to the name. Configure these targets
|
||||
to build for iOS devices."""
|
||||
for target_dict in targets.values():
|
||||
for config_name in target_dict['configurations'].keys():
|
||||
config = target_dict['configurations'][config_name]
|
||||
new_config_name = config_name + '-iphoneos'
|
||||
new_config_dict = copy.deepcopy(config)
|
||||
if target_dict['toolset'] == 'target':
|
||||
new_config_dict['xcode_settings']['ARCHS'] = ['armv7']
|
||||
new_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos'
|
||||
target_dict['configurations'][new_config_name] = new_config_dict
|
||||
to build for iOS devices and use correct architectures for those builds."""
|
||||
for target_dict in targets.itervalues():
|
||||
toolset = target_dict['toolset']
|
||||
configs = target_dict['configurations']
|
||||
for config_name, simulator_config_dict in dict(configs).iteritems():
|
||||
iphoneos_config_dict = copy.deepcopy(simulator_config_dict)
|
||||
configs[config_name + '-iphoneos'] = iphoneos_config_dict
|
||||
configs[config_name + '-iphonesimulator'] = simulator_config_dict
|
||||
if toolset == 'target':
|
||||
simulator_config_dict['xcode_settings']['SDKROOT'] = 'iphonesimulator'
|
||||
iphoneos_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos'
|
||||
return targets
|
||||
|
||||
def CloneConfigurationForDeviceAndEmulator(target_dicts):
|
||||
|
||||
Reference in New Issue
Block a user