| 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): | |
| 275 job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) | |
| 276 out = job.communicate()[0] | |
| 277 if job.returncode != 0: | |
| 278 sys.stderr.write(out + '\n') | |
| 279 raise GypError('Error %d running %s' % (job.returncode, cmdlist[0])) | |
| 280 return out.rstrip('\n') | |
| 281 | |
| 282 def _GetSdkVersionInfoItem(self, sdk, infoitem): | 274 def _GetSdkVersionInfoItem(self, sdk, infoitem): |
| 283 # xcodebuild requires Xcode and can't run on Command Line Tools-only | 275 # xcodebuild requires Xcode and can't run on Command Line Tools-only |
| 284 # systems from 10.7 onward. | 276 # systems from 10.7 onward. |
| 285 # Since the CLT has no SDK paths anyway, returning None is the | 277 # Since the CLT has no SDK paths anyway, returning None is the |
| 286 # most sensible route and should still do the right thing. | 278 # most sensible route and should still do the right thing. |
| 287 try: | 279 try: |
| 288 return self._GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem]) | 280 return GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem]) |
| 289 except: | 281 except: |
| 290 pass | 282 pass |
| 291 | 283 |
| 292 def _SdkRoot(self, configname): | 284 def _SdkRoot(self, configname): |
| 293 if configname is None: | 285 if configname is None: |
| 294 configname = self.configname | 286 configname = self.configname |
| 295 return self.GetPerConfigSetting('SDKROOT', configname, default='') | 287 return self.GetPerConfigSetting('SDKROOT', configname, default='') |
| 296 | 288 |
| 297 def _SdkPath(self, configname=None): | 289 def _SdkPath(self, configname=None): |
| 298 sdk_root = self._SdkRoot(configname) | 290 sdk_root = self._SdkRoot(configname) |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 | 859 |
| 868 def AdjustLibraries(self, libraries, config_name=None): | 860 def AdjustLibraries(self, libraries, config_name=None): |
| 869 """Transforms entries like 'Cocoa.framework' in libraries into entries like | 861 """Transforms entries like 'Cocoa.framework' in libraries into entries like |
| 870 '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc. | 862 '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc. |
| 871 """ | 863 """ |
| 872 libraries = [self._AdjustLibrary(library, config_name) | 864 libraries = [self._AdjustLibrary(library, config_name) |
| 873 for library in libraries] | 865 for library in libraries] |
| 874 return libraries | 866 return libraries |
| 875 | 867 |
| 876 def _BuildMachineOSBuild(self): | 868 def _BuildMachineOSBuild(self): |
| 877 return self._GetStdout(['sw_vers', '-buildVersion']) | 869 return GetStdout(['sw_vers', '-buildVersion']) |
| 878 | |
| 879 # This method ported from the logic in Homebrew's CLT version check | |
| 880 def _CLTVersion(self): | |
| 881 # pkgutil output looks like | |
| 882 # package-id: com.apple.pkg.CLTools_Executables | |
| 883 # version: 5.0.1.0.1.1382131676 | |
| 884 # volume: / | |
| 885 # location: / | |
| 886 # install-time: 1382544035 | |
| 887 # 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" | |
| 889 FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" | |
| 890 MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" | |
| 891 | |
| 892 regex = re.compile('version: (?P<version>.+)') | |
| 893 for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: | |
| 894 try: | |
| 895 output = self._GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) | |
| 896 return re.search(regex, output).groupdict()['version'] | |
| 897 except: | |
| 898 continue | |
| 899 | 870 |
| 900 def _XcodeVersion(self): | 871 def _XcodeVersion(self): |
| 901 # `xcodebuild -version` output looks like | |
| 902 # Xcode 4.6.3 | |
| 903 # Build version 4H1503 | |
| 904 # or like | |
| 905 # Xcode 3.2.6 | |
| 906 # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 | |
| 907 # BuildVersion: 10M2518 | |
| 908 # Convert that to '0463', '4H1503'. | |
| 909 if len(XcodeSettings._xcode_version_cache) == 0: | 872 if len(XcodeSettings._xcode_version_cache) == 0: |
| 910 try: | 873 XcodeSettings._xcode_version_cache = XcodeVersion() |
| 911 version_list = self._GetStdout(['xcodebuild', '-version']).splitlines() | |
| 912 # 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 | |
| 914 # a bogus path set via xcode-select | |
| 915 # In that case this may be a CLT-only install so fall back to | |
| 916 # checking that version. | |
| 917 if len(version_list) < 2: | |
| 918 raise GypError, "xcodebuild returned unexpected results" | |
| 919 except: | |
| 920 version = self._CLTVersion() | |
| 921 if version: | |
| 922 version = re.match('(\d\.\d\.?\d*)', version).groups()[0] | |
| 923 else: | |
| 924 raise GypError, "No Xcode or CLT version detected!" | |
| 925 # The CLT has no build information, so we return an empty string. | |
| 926 version_list = [version, ''] | |
| 927 version = version_list[0] | |
| 928 build = version_list[-1] | |
| 929 # Be careful to convert "4.2" to "0420": | |
| 930 version = version.split()[-1].replace('.', '') | |
| 931 version = (version + '0' * (3 - len(version))).zfill(4) | |
| 932 if build: | |
| 933 build = build.split()[-1] | |
| 934 XcodeSettings._xcode_version_cache = (version, build) | |
| 935 return XcodeSettings._xcode_version_cache | 874 return XcodeSettings._xcode_version_cache |
| 936 | 875 |
| 937 def _XcodeIOSDeviceFamily(self, configname): | 876 def _XcodeIOSDeviceFamily(self, configname): |
| 938 family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') | 877 family = self.xcode_settings[configname].get('TARGETED_DEVICE_FAMILY', '1') |
| 939 return [int(x) for x in family.split(',')] | 878 return [int(x) for x in family.split(',')] |
| 940 | 879 |
| 941 def GetExtraPlistItems(self, configname=None): | 880 def GetExtraPlistItems(self, configname=None): |
| 942 """Returns a dictionary with extra items to insert into Info.plist.""" | 881 """Returns a dictionary with extra items to insert into Info.plist.""" |
| 943 if configname not in XcodeSettings._plist_cache: | 882 if configname not in XcodeSettings._plist_cache: |
| 944 cache = {} | 883 cache = {} |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 project, then the environment variable was empty. Starting with this | 921 project, then the environment variable was empty. Starting with this |
| 983 version, Xcode uses the name of the newest SDK installed. | 922 version, Xcode uses the name of the newest SDK installed. |
| 984 """ | 923 """ |
| 985 if self._XcodeVersion() < '0500': | 924 if self._XcodeVersion() < '0500': |
| 986 return '' | 925 return '' |
| 987 default_sdk_path = self._XcodeSdkPath('') | 926 default_sdk_path = self._XcodeSdkPath('') |
| 988 default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) | 927 default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path) |
| 989 if default_sdk_root: | 928 if default_sdk_root: |
| 990 return default_sdk_root | 929 return default_sdk_root |
| 991 try: | 930 try: |
| 992 all_sdks = self._GetStdout(['xcodebuild', '-showsdks']) | 931 all_sdks = GetStdout(['xcodebuild', '-showsdks']) |
| 993 except: | 932 except: |
| 994 # If xcodebuild fails, there will be no valid SDKs | 933 # If xcodebuild fails, there will be no valid SDKs |
| 995 return '' | 934 return '' |
| 996 for line in all_sdks.splitlines(): | 935 for line in all_sdks.splitlines(): |
| 997 items = line.split() | 936 items = line.split() |
| 998 if len(items) >= 3 and items[-2] == '-sdk': | 937 if len(items) >= 3 and items[-2] == '-sdk': |
| 999 sdk_root = items[-1] | 938 sdk_root = items[-1] |
| 1000 sdk_path = self._XcodeSdkPath(sdk_root) | 939 sdk_path = self._XcodeSdkPath(sdk_root) |
| 1001 if sdk_path == default_sdk_path: | 940 if sdk_path == default_sdk_path: |
| 1002 return sdk_root | 941 return sdk_root |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 if not self.header or not self.compile_headers: | 1063 if not self.header or not self.compile_headers: |
| 1125 return [] | 1064 return [] |
| 1126 return [ | 1065 return [ |
| 1127 (self._Gch('c', arch), '-x c-header', 'c', self.header), | 1066 (self._Gch('c', arch), '-x c-header', 'c', self.header), |
| 1128 (self._Gch('cc', arch), '-x c++-header', 'cc', self.header), | 1067 (self._Gch('cc', arch), '-x c++-header', 'cc', self.header), |
| 1129 (self._Gch('m', arch), '-x objective-c-header', 'm', self.header), | 1068 (self._Gch('m', arch), '-x objective-c-header', 'm', self.header), |
| 1130 (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header), | 1069 (self._Gch('mm', arch), '-x objective-c++-header', 'mm', self.header), |
| 1131 ] | 1070 ] |
| 1132 | 1071 |
| 1133 | 1072 |
| 1073 def XcodeVersion(): |
| 1074 """Returns a tuple of version and build version of installed Xcode.""" |
| 1075 # `xcodebuild -version` output looks like |
| 1076 # Xcode 4.6.3 |
| 1077 # Build version 4H1503 |
| 1078 # or like |
| 1079 # Xcode 3.2.6 |
| 1080 # Component versions: DevToolsCore-1809.0; DevToolsSupport-1806.0 |
| 1081 # BuildVersion: 10M2518 |
| 1082 # Convert that to '0463', '4H1503'. |
| 1083 try: |
| 1084 version_list = GetStdout(['xcodebuild', '-version']).splitlines() |
| 1085 # In some circumstances xcodebuild exits 0 but doesn't return |
| 1086 # the right results; for example, a user on 10.7 or 10.8 with |
| 1087 # a bogus path set via xcode-select |
| 1088 # In that case this may be a CLT-only install so fall back to |
| 1089 # checking that version. |
| 1090 if len(version_list) < 2: |
| 1091 raise GypError, "xcodebuild returned unexpected results" |
| 1092 except: |
| 1093 version = CLTVersion() |
| 1094 if version: |
| 1095 version = re.match('(\d\.\d\.?\d*)', version).groups()[0] |
| 1096 else: |
| 1097 raise GypError, "No Xcode or CLT version detected!" |
| 1098 # The CLT has no build information, so we return an empty string. |
| 1099 version_list = [version, ''] |
| 1100 version = version_list[0] |
| 1101 build = version_list[-1] |
| 1102 # Be careful to convert "4.2" to "0420": |
| 1103 version = version.split()[-1].replace('.', '') |
| 1104 version = (version + '0' * (3 - len(version))).zfill(4) |
| 1105 if build: |
| 1106 build = build.split()[-1] |
| 1107 return version, build |
| 1108 |
| 1109 |
| 1110 # This function ported from the logic in Homebrew's CLT version check |
| 1111 def CLTVersion(): |
| 1112 """Returns the version of command-line tools from pkgutil.""" |
| 1113 # pkgutil output looks like |
| 1114 # package-id: com.apple.pkg.CLTools_Executables |
| 1115 # version: 5.0.1.0.1.1382131676 |
| 1116 # volume: / |
| 1117 # location: / |
| 1118 # install-time: 1382544035 |
| 1119 # groups: com.apple.FindSystemFiles.pkg-group com.apple.DevToolsBoth.pkg-gro
up com.apple.DevToolsNonRelocatableShared.pkg-group |
| 1120 STANDALONE_PKG_ID = "com.apple.pkg.DeveloperToolsCLILeo" |
| 1121 FROM_XCODE_PKG_ID = "com.apple.pkg.DeveloperToolsCLI" |
| 1122 MAVERICKS_PKG_ID = "com.apple.pkg.CLTools_Executables" |
| 1123 |
| 1124 regex = re.compile('version: (?P<version>.+)') |
| 1125 for key in [MAVERICKS_PKG_ID, STANDALONE_PKG_ID, FROM_XCODE_PKG_ID]: |
| 1126 try: |
| 1127 output = GetStdout(['/usr/sbin/pkgutil', '--pkg-info', key]) |
| 1128 return re.search(regex, output).groupdict()['version'] |
| 1129 except: |
| 1130 continue |
| 1131 |
| 1132 |
| 1133 def GetStdout(cmdlist): |
| 1134 """Returns the content of standard output returned by invoking |cmdlist|. |
| 1135 Raises |GypError| if the command return with a non-zero return code.""" |
| 1136 job = subprocess.Popen(cmdlist, stdout=subprocess.PIPE) |
| 1137 out = job.communicate()[0] |
| 1138 if job.returncode != 0: |
| 1139 sys.stderr.write(out + '\n') |
| 1140 raise GypError('Error %d running %s' % (job.returncode, cmdlist[0])) |
| 1141 return out.rstrip('\n') |
| 1142 |
| 1143 |
| 1134 def MergeGlobalXcodeSettingsToSpec(global_dict, spec): | 1144 def MergeGlobalXcodeSettingsToSpec(global_dict, spec): |
| 1135 """Merges the global xcode_settings dictionary into each configuration of the | 1145 """Merges the global xcode_settings dictionary into each configuration of the |
| 1136 target represented by spec. For keys that are both in the global and the local | 1146 target represented by spec. For keys that are both in the global and the local |
| 1137 xcode_settings dict, the local key gets precendence. | 1147 xcode_settings dict, the local key gets precendence. |
| 1138 """ | 1148 """ |
| 1139 # The xcode generator special-cases global xcode_settings and does something | 1149 # The xcode generator special-cases global xcode_settings and does something |
| 1140 # that amounts to merging in the global xcode_settings into each local | 1150 # that amounts to merging in the global xcode_settings into each local |
| 1141 # xcode_settings dict. | 1151 # xcode_settings dict. |
| 1142 global_xcode_settings = global_dict.get('xcode_settings', {}) | 1152 global_xcode_settings = global_dict.get('xcode_settings', {}) |
| 1143 for config in spec['configurations'].values(): | 1153 for config in spec['configurations'].values(): |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 new_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos' | 1441 new_config_dict['xcode_settings']['SDKROOT'] = 'iphoneos' |
| 1432 target_dict['configurations'][new_config_name] = new_config_dict | 1442 target_dict['configurations'][new_config_name] = new_config_dict |
| 1433 return targets | 1443 return targets |
| 1434 | 1444 |
| 1435 def CloneConfigurationForDeviceAndEmulator(target_dicts): | 1445 def CloneConfigurationForDeviceAndEmulator(target_dicts): |
| 1436 """If |target_dicts| contains any iOS targets, automatically create -iphoneos | 1446 """If |target_dicts| contains any iOS targets, automatically create -iphoneos |
| 1437 targets for iOS device builds.""" | 1447 targets for iOS device builds.""" |
| 1438 if _HasIOSTarget(target_dicts): | 1448 if _HasIOSTarget(target_dicts): |
| 1439 return _AddIOSDeviceConfigurations(target_dicts) | 1449 return _AddIOSDeviceConfigurations(target_dicts) |
| 1440 return target_dicts | 1450 return target_dicts |
| OLD | NEW |