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 copy | 10 import copy |
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
264 return self._GetBundleBinaryPath() | 264 return self._GetBundleBinaryPath() |
265 else: | 265 else: |
266 return self._GetStandaloneBinaryPath() | 266 return self._GetStandaloneBinaryPath() |
267 | 267 |
268 def GetActiveArchs(self, configname): | 268 def GetActiveArchs(self, configname): |
269 """Returns the architectures this target should be built for.""" | 269 """Returns the architectures this target should be built for.""" |
270 # TODO: Look at VALID_ARCHS, ONLY_ACTIVE_ARCH; possibly set | 270 # TODO: Look at VALID_ARCHS, ONLY_ACTIVE_ARCH; possibly set |
271 # CURRENT_ARCH / NATIVE_ARCH env vars? | 271 # CURRENT_ARCH / NATIVE_ARCH env vars? |
272 return self.xcode_settings[configname].get('ARCHS', [self._DefaultArch()]) | 272 return self.xcode_settings[configname].get('ARCHS', [self._DefaultArch()]) |
273 | 273 |
274 def _GetStdout(self, cmdlist): | 274 @classmethod |
Nico
2014/02/07 18:57:56
Why this change?
sdefresne
2014/02/07 20:19:33
I want to call this method from the module functio
| |
275 def _GetStdout(cls, cmdlist): | |
275 job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) | 276 job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) |
276 out = job.communicate()[0] | 277 out = job.communicate()[0] |
277 if job.returncode != 0: | 278 if job.returncode != 0: |
278 sys.stderr.write(out + '\n') | 279 sys.stderr.write(out + '\n') |
279 raise GypError('Error %d running %s' % (job.returncode, cmdlist[0])) | 280 raise GypError('Error %d running %s' % (job.returncode, cmdlist[0])) |
280 return out.rstrip('\n') | 281 return out.rstrip('\n') |
281 | 282 |
282 def _GetSdkVersionInfoItem(self, sdk, infoitem): | 283 def _GetSdkVersionInfoItem(self, sdk, infoitem): |
283 # xcodebuild requires Xcode and can't run on Command Line Tools-only | 284 # xcodebuild requires Xcode and can't run on Command Line Tools-only |
284 # systems from 10.7 onward. | 285 # systems from 10.7 onward. |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
870 '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc. | 871 '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc. |
871 """ | 872 """ |
872 libraries = [self._AdjustLibrary(library, config_name) | 873 libraries = [self._AdjustLibrary(library, config_name) |
873 for library in libraries] | 874 for library in libraries] |
874 return libraries | 875 return libraries |
875 | 876 |
876 def _BuildMachineOSBuild(self): | 877 def _BuildMachineOSBuild(self): |
877 return self._GetStdout(['sw_vers', '-buildVersion']) | 878 return self._GetStdout(['sw_vers', '-buildVersion']) |
878 | 879 |
879 # This method ported from the logic in Homebrew's CLT version check | 880 # This method ported from the logic in Homebrew's CLT version check |
880 def _CLTVersion(self): | 881 @classmethod |
882 def _CLTVersion(cls): | |
881 # pkgutil output looks like | 883 # pkgutil output looks like |
882 # package-id: com.apple.pkg.CLTools_Executables | 884 # package-id: com.apple.pkg.CLTools_Executables |
883 # version: 5.0.1.0.1.1382131676 | 885 # version: 5.0.1.0.1.1382131676 |
884 # volume: / | 886 # volume: / |
885 # location: / | 887 # location: / |
886 # install-time: 1382544035 | 888 # install-time: 1382544035 |
887 # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-g roup com.apple.DevToolsNonRelocatableShared.pkg-group | 889 # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-g roup com.apple.DevToolsNonRelocatableShared.pkg-group |
888 STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" | 890 STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" |
889 FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" | 891 FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" |
890 MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" | 892 MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" |
891 | 893 |
892 regex = re.compile('version: (?P<version>.+)') | 894 regex = re.compile('version: (?P<version>.+)') |
893 for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: | 895 for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: |
894 try: | 896 try: |
895 output = self._GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) | 897 output = cls._GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) |
896 return re.search(regex, output).groupdict()['version'] | 898 return re.search(regex, output).groupdict()['version'] |
897 except: | 899 except: |
898 continue | 900 continue |
899 | 901 |
900 def _XcodeVersion(self): | 902 @classmethod |
903 def _XcodeVersion(cls): | |
901 # `xcodebuild -version` output looks like | 904 # `xcodebuild -version` output looks like |
902 # Xcode 4.6.3 | 905 # Xcode 4.6.3 |
903 # Build version 4H1503 | 906 # Build version 4H1503 |
904 # or like | 907 # or like |
905 # Xcode 3.2.6 | 908 # Xcode 3.2.6 |
906 # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 | 909 # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 |
907 # BuildVersion: 10M2518 | 910 # BuildVersion: 10M2518 |
908 # Convert that to '0463', '4H1503'. | 911 # Convert that to '0463', '4H1503'. |
909 if len(XcodeSettings._xcode_version_cache) == 0: | 912 if not cls._xcode_version_cache: |
910 try: | 913 try: |
911 version_list = self._GetStdout(['xcodebuild', '-version']).splitlines() | 914 version_list = cls._GetStdout(['xcodebuild', '-version']).splitlines() |
912 # In some circumstances xcodebuild exits 0 but doesn't return | 915 # In some circumstances xcodebuild exits 0 but doesn't return |
913 # the right results; for example, a user on 10.7 or 10.8 with | 916 # the right results; for example, a user on 10.7 or 10.8 with |
914 # a bogus path set via xcode-select | 917 # a bogus path set via xcode-select |
915 # In that case this may be a CLT-only install so fall back to | 918 # In that case this may be a CLT-only install so fall back to |
916 # checking that version. | 919 # checking that version. |
917 if len(version_list) < 2: | 920 if len(version_list) < 2: |
918 raise GypError, "xcodebuild returned unexpected results" | 921 raise GypError, "xcodebuild returned unexpected results" |
919 except: | 922 except: |
920 version = self._CLTVersion() | 923 version = cls._CLTVersion() |
921 if version: | 924 if version: |
922 version = re.match('(\d\.\d\.?\d*)', version).groups()[0] | 925 version = re.match('(\d\.\d\.?\d*)', version).groups()[0] |
923 else: | 926 else: |
924 raise GypError, "No Xcode or CLT version detected!" | 927 raise GypError, "No Xcode or CLT version detected!" |
925 # The CLT has no build information, so we return an empty string. | 928 # The CLT has no build information, so we return an empty string. |
926 version_list = [version, ''] | 929 version_list = [version, ''] |
927 version = version_list[0] | 930 version = version_list[0] |
928 build = version_list[-1] | 931 build = version_list[-1] |
929 # Be careful to convert "4.2" to "0420": | 932 # Be careful to convert "4.2" to "0420": |
930 version = version.split()[-1].replace('.', '') | 933 version = version.split()[-1].replace('.', '') |
931 version = (version + '0' * (3 - len(version))).zfill(4) | 934 version = (version + '0' * (3 - len(version))).zfill(4) |
932 if build: | 935 if build: |
933 build = build.split()[-1] | 936 build = build.split()[-1] |
934 XcodeSettings._xcode_version_cache = (version, build) | 937 cls._xcode_version_cache = (version, build) |
935 return XcodeSettings._xcode_version_cache | 938 return cls._xcode_version_cache |
936 | 939 |
937 def _XcodeIOSDeviceFamily(self, configname): | 940 def _XcodeIOSDeviceFamily(self, configname): |
938 family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') | 941 family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') |
939 return [int(x) for x in family.split(',')] | 942 return [int(x) for x in family.split(',')] |
940 | 943 |
941 def GetExtraPlistItems(self, configname=None): | 944 def GetExtraPlistItems(self, configname=None): |
942 """Returns a dictionary with extra items to insert into Info.plist.""" | 945 """Returns a dictionary with extra items to insert into Info.plist.""" |
943 if configname not in XcodeSettings._plist_cache: | 946 if configname not in XcodeSettings._plist_cache: |
944 cache = {} | 947 cache = {} |
945 cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild() | 948 cache['BuildMachineOSBuild'] = self._BuildMachineOSBuild() |
(...skipping 29 matching lines...) Expand all Loading... | |
975 items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname) | 978 items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname) |
976 return items | 979 return items |
977 | 980 |
978 def _DefaultSdkRoot(self): | 981 def _DefaultSdkRoot(self): |
979 """Returns the default SDKROOT to use. | 982 """Returns the default SDKROOT to use. |
980 | 983 |
981 Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode | 984 Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode |
982 project, then the environment variable was empty. Starting with this | 985 project, then the environment variable was empty. Starting with this |
983 version, Xcode uses the name of the newest SDK installed. | 986 version, Xcode uses the name of the newest SDK installed. |
984 """ | 987 """ |
985 if self._XcodeVersion() < '0500': | 988 xcode, xcode_build = self._XcodeVersion() |
989 if xcode < '0500': | |
986 return '' | 990 return '' |
987 default_sdk_path = self._XcodeSdkPath('') | 991 default_sdk_path = self._XcodeSdkPath('') |
988 default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) | 992 default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) |
989 if default_sdk_root: | 993 if default_sdk_root: |
990 return default_sdk_root | 994 return default_sdk_root |
991 try: | 995 try: |
992 all_sdks = self._GetStdout(['xcodebuild', '-showsdks']) | 996 all_sdks = self._GetStdout(['xcodebuild', '-showsdks']) |
993 except: | 997 except: |
994 # If xcodebuild fails, there will be no valid SDKs | 998 # If xcodebuild fails, there will be no valid SDKs |
995 return '' | 999 return '' |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1411 def _HasIOSTarget(targets): | 1415 def _HasIOSTarget(targets): |
1412 """Returns true if any target contains the iOS specific key | 1416 """Returns true if any target contains the iOS specific key |
1413 IPHONEOS_DEPLOYMENT_TARGET.""" | 1417 IPHONEOS_DEPLOYMENT_TARGET.""" |
1414 for target_dict in targets.values(): | 1418 for target_dict in targets.values(): |
1415 for config in target_dict['configurations'].values(): | 1419 for config in target_dict['configurations'].values(): |
1416 if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'): | 1420 if config.get('xcode_settings', {}).get('IPHONEOS_DEPLOYMENT_TARGET'): |
1417 return True | 1421 return True |
1418 return False | 1422 return False |
1419 | 1423 |
1420 | 1424 |
1425 def _IOSIsDeviceSDKROOT(sdkroot): | |
1426 """Tests if |sdkroot| is a SDK for building for device.""" | |
1427 return 'iphoneos' in sdkroot.lower() | |
1428 | |
1429 | |
1430 def _IOSDefaultArchForSDKRoot(sdkroot): | |
1431 xcode, xcode_build = XcodeSettings._XcodeVersion() | |
1432 if xcode < '0500': | |
1433 if _IOSIsDeviceSDKROOT(sdkroot): | |
1434 return {'$(ARCHS_STANDARD)': ['armv7']} | |
1435 else: | |
1436 return {'$(ARCHS_STANDARD)': ['i386']} | |
1437 else: | |
1438 if _IOSIsDeviceSDKROOT(sdkroot): | |
1439 return { | |
1440 '$(ARCHS_STANDARD)': ['armv7', 'armv7s'], | |
1441 '$(ARCHS_STANDARD_INCLUDING_64_BIT)': ['armv7', 'armv7s', 'arm64'], | |
1442 } | |
1443 else: | |
1444 return { | |
1445 '$(ARCHS_STANDARD)': ['i386'], | |
1446 '$(ARCHS_STANDARD_INCLUDING_64_BIT)': ['i386', 'x86_64'], | |
1447 } | |
1448 | |
1449 | |
1450 def _FilterIOSArchitectureForSDKROOT(xcode_settings): | |
1451 """Filter the ARCHS value from the |xcode_settings| dictionary to only | |
1452 contains architectures valid for the sdk configured in SDKROOT value.""" | |
1453 defaults_archs = _IOSDefaultArchForSDKRoot(xcode_settings.get('SDKROOT', '')) | |
1454 allowed_archs = set() | |
1455 for archs in defaults_archs.itervalues(): | |
1456 allowed_archs.update(archs) | |
1457 selected_archs = set() | |
1458 for arch in (xcode_settings.get('ARCHS', []) or ['$(ARCHS_STANDARD)']): | |
Nico
2014/02/07 18:57:56
No need for the default [] if you do `or default`
sdefresne
2014/02/07 20:19:33
There are some xcode_settings objects that don't d
| |
1459 if arch in defaults_archs: | |
1460 selected_archs.update(defaults_archs[arch]) | |
1461 elif arch in allowed_archs: | |
1462 selected_archs.add(arch) | |
1463 valid_archs = set(xcode_settings.get('VALID_ARCHS', [])) | |
1464 if valid_archs: | |
1465 selected_archs = selected_archs & valid_archs | |
1466 xcode_settings['ARCHS'] = list(selected_archs) | |
1467 | |
1468 | |
1421 def _AddIOSDeviceConfigurations(targets): | 1469 def _AddIOSDeviceConfigurations(targets): |
1422 """Clone all targets and append -iphoneos to the name. Configure these targets | 1470 """Clone all targets and append -iphoneos to the name. Configure these targets |
1423 to build for iOS devices.""" | 1471 to build for iOS devices and use correct architectures for those builds.""" |
1424 for target_dict in targets.values(): | 1472 for target_dict in targets.itervalues(): |
1425 for config_name in target_dict['configurations'].keys(): | 1473 toolset = target_dict['toolset'] |
1426 config = target_dict['configurations'][config_name] | 1474 configs = target_dict['configurations'] |
1427 new_config_name = config_name + '-iphoneos' | 1475 for config_name, config_dict in dict(configs).iteritems(): |
1428 new_config_dict = copy.deepcopy(config) | 1476 iphoneos_config_dict = copy.deepcopy(config_dict) |
Nico
2014/02/07 18:57:56
Why this variable name change?
sdefresne
2014/02/07 20:19:33
I found the old name confusing when updating the c
| |
1429 if target_dict['toolset'] == 'target': | 1477 configs[config_name + '-iphoneos'] = iphoneos_config_dict |
1430 new_config_dict['xcode_settings']['ARCHS'] = ['armv7'] | 1478 if toolset == 'target': |
1431 new_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos' | 1479 iphoneos_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos' |
1432 target_dict['configurations'][new_config_name] = new_config_dict | 1480 _FilterIOSArchitectureForSDKROOT(iphoneos_config_dict['xcode_settings']) |
1481 _FilterIOSArchitectureForSDKROOT(config_dict['xcode_settings']) | |
1433 return targets | 1482 return targets |
1434 | 1483 |
1435 def CloneConfigurationForDeviceAndEmulator(target_dicts): | 1484 def CloneConfigurationForDeviceAndEmulator(target_dicts): |
1436 """If |target_dicts| contains any iOS targets, automatically create -iphoneos | 1485 """If |target_dicts| contains any iOS targets, automatically create -iphoneos |
1437 targets for iOS device builds.""" | 1486 targets for iOS device builds.""" |
1438 if _HasIOSTarget(target_dicts): | 1487 if _HasIOSTarget(target_dicts): |
1439 return _AddIOSDeviceConfigurations(target_dicts) | 1488 return _AddIOSDeviceConfigurations(target_dicts) |
1440 return target_dicts | 1489 return target_dicts |
OLD | NEW |