1# Copyright 2019 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Collects information about the SDK and return them as JSON file.""" 6 7import argparse 8import json 9import os 10import re 11import subprocess 12import sys 13 14# Patterns used to extract the Xcode version and build version. 15XCODE_VERSION_PATTERN = re.compile(r'Xcode (\d+)\.(\d+)') 16XCODE_BUILD_PATTERN = re.compile(r'Build version (.*)') 17 18 19def GetCommandOutput(command): 20 """Returns the output of `command` as a string.""" 21 return subprocess.check_output(command, encoding='utf-8') 22 23 24def GetAppleCpuName(target_cpu): 25 """Returns the name of the |target_cpu| using Apple's convention.""" 26 return { 27 'x64': 'x86_64', 28 'arm': 'armv7', 29 'x86': 'i386' 30 }.get(target_cpu, target_cpu) 31 32 33def GetPlatform(target_environment): 34 """Returns the platform for |target_environment|.""" 35 return { 36 'simulator': 'iphonesimulator', 37 'device': 'iphoneos' 38 }[target_environment] 39 40 41def GetPlaformDisplayName(target_environment): 42 """Returns the platform display name for |target_environment|.""" 43 return { 44 'simulator': 'iPhoneSimulator', 45 'device': 'iPhoneOS' 46 }[target_environment] 47 48 49def ExtractOSVersion(): 50 """Extract the version of macOS of the current machine.""" 51 return GetCommandOutput(['sw_vers', '-buildVersion']).strip() 52 53 54def ExtractXcodeInfo(): 55 """Extract Xcode version and build version.""" 56 version, build = None, None 57 for line in GetCommandOutput(['xcodebuild', '-version']).splitlines(): 58 match = XCODE_VERSION_PATTERN.search(line) 59 if match: 60 major, minor = match.group(1), match.group(2) 61 version = major.rjust(2, '0') + minor.ljust(2, '0') 62 continue 63 64 match = XCODE_BUILD_PATTERN.search(line) 65 if match: 66 build = match.group(1) 67 continue 68 69 assert version is not None and build is not None 70 return version, build 71 72 73def ExtractSDKInfo(info, sdk): 74 """Extract information about the SDK.""" 75 return GetCommandOutput(['xcrun', '--sdk', sdk, '--show-sdk-' + info]).strip() 76 77 78def GetDeveloperDir(): 79 """Returns the developer dir.""" 80 return GetCommandOutput(['xcode-select', '-print-path']).strip() 81 82 83def GetSDKInfoForCpu(target_cpu, environment, sdk_version, deployment_target): 84 """Returns a dictionary with information about the SDK.""" 85 platform = GetPlatform(environment) 86 sdk_version = sdk_version or ExtractSDKInfo('version', platform) 87 deployment_target = deployment_target or sdk_version 88 89 target = target_cpu + '-apple-ios' + deployment_target 90 if environment == 'simulator': 91 target = target + '-simulator' 92 93 xcode_version, xcode_build = ExtractXcodeInfo() 94 effective_sdk = platform + sdk_version 95 96 sdk_info = {} 97 sdk_info['compiler'] = 'com.apple.compilers.llvm.clang.1_0' 98 sdk_info['is_simulator'] = environment == 'simulator' 99 sdk_info['macos_build'] = ExtractOSVersion() 100 sdk_info['platform'] = platform 101 sdk_info['platform_name'] = GetPlaformDisplayName(environment) 102 sdk_info['sdk'] = effective_sdk 103 sdk_info['sdk_build'] = ExtractSDKInfo('build-version', effective_sdk) 104 sdk_info['sdk_path'] = ExtractSDKInfo('path', effective_sdk) 105 sdk_info['toolchain_path'] = os.path.join( 106 GetDeveloperDir(), 'Toolchains/XcodeDefault.xctoolchain') 107 sdk_info['sdk_version'] = sdk_version 108 sdk_info['target'] = target 109 sdk_info['xcode_build'] = xcode_build 110 sdk_info['xcode_version'] = xcode_version 111 112 return sdk_info 113 114 115def ParseArgs(argv): 116 """Parses command line arguments.""" 117 parser = argparse.ArgumentParser( 118 description=__doc__, 119 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 120 121 parser.add_argument( 122 '-t', '--target-cpu', default='x64', 123 choices=('x86', 'x64', 'arm', 'arm64'), 124 help='target cpu') 125 parser.add_argument( 126 '-e', 127 '--target-environment', 128 default='simulator', 129 choices=('simulator', 'device'), 130 help='target environment') 131 parser.add_argument( 132 '-s', '--sdk-version', 133 help='version of the sdk') 134 parser.add_argument( 135 '-d', '--deployment-target', 136 help='iOS deployment target') 137 parser.add_argument( 138 '-o', '--output', default='-', 139 help='path of the output file to create; - means stdout') 140 141 return parser.parse_args(argv) 142 143 144def main(argv): 145 args = ParseArgs(argv) 146 147 sdk_info = GetSDKInfoForCpu( 148 GetAppleCpuName(args.target_cpu), args.target_environment, 149 args.sdk_version, args.deployment_target) 150 151 if args.output == '-': 152 sys.stdout.write(json.dumps(sdk_info)) 153 else: 154 with open(args.output, 'w') as output: 155 output.write(json.dumps(sdk_info)) 156 157 158if __name__ == '__main__': 159 sys.exit(main(sys.argv[1:])) 160