1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright (c) 2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16"""Prints the lowest locally available SDK version greater than or equal to a 17given minimum sdk version to standard output. If --developer_dir is passed, then 18the script will use the Xcode toolchain located at DEVELOPER_DIR. 19 20Usage: 21 python find_sdk.py [--developer_dir DEVELOPER_DIR] 10.6 # Ignores SDKs < 10.6 22""" 23 24import os 25import re 26import subprocess 27import sys 28 29from optparse import OptionParser 30 31 32class SdkError(Exception): 33 def __init__(self, value): 34 self.value = value 35 36 def __str__(self): 37 return repr(self.value) 38 39 40def parse_version(version_str): 41 """'10.6' => [10, 6]""" 42 return map(int, re.findall(r'(\d+)', version_str)) 43 44 45def main(): 46 parser = OptionParser() 47 parser.add_option("--verify", 48 action="store_true", dest="verify", default=False, 49 help="return the sdk argument and warn if it doesn't exist") 50 parser.add_option("--sdk_path", 51 action="store", type="string", dest="sdk_path", 52 default="", 53 help="user-specified SDK path; bypasses verification") 54 parser.add_option("--print_sdk_path", 55 action="store_true", dest="print_sdk_path", default=False, 56 help="Additionally print the path the SDK (appears first).") 57 parser.add_option("--developer_dir", help='Path to Xcode.') 58 options, args = parser.parse_args() 59 if len(args) != 1: 60 parser.error('Please specify a minimum SDK version') 61 min_sdk_version = args[0] 62 63 if options.developer_dir: 64 os.environ['DEVELOPER_DIR'] = options.developer_dir 65 66 job = subprocess.Popen(['xcode-select', '-print-path'], 67 stdout=subprocess.PIPE, 68 stderr=subprocess.STDOUT) 69 out, err = job.communicate() 70 if job.returncode != 0: 71 print(out, file=sys.stderr) 72 print(err, file=sys.stderr) 73 raise Exception('Error %d running xcode-select' % job.returncode) 74 sdk_dir = os.path.join( 75 str(out.rstrip(), encoding="utf-8"), 76 'Platforms/MacOSX.platform/Developer/SDKs') 77 78 file_path = os.path.relpath("/path/to/Xcode.app") 79 if not os.path.isdir(sdk_dir) or not '.app/Contents/Developer' in sdk_dir: 80 raise SdkError('Install Xcode, launch it, accept the license ' + 81 'agreement, and run `sudo xcode-select -s %s` ' % file_path + 82 'to continue.') 83 sdks = [re.findall('^MacOSX(1[0,1,2,3,4,5,6,7,8]\.\d+)\.sdk$', s) for s in 84 os.listdir(sdk_dir)] 85 sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6'] 86 sdks = [s for s in sdks # ['10.5', '10.6'] => ['10.6'] 87 if list(parse_version(s)) >= list(parse_version(min_sdk_version))] 88 89 if not sdks: 90 raise Exception('No %s+ SDK found' % min_sdk_version) 91 best_sdk = sorted(sdks)[0] 92 93 if options.verify and best_sdk != min_sdk_version and not options.sdk_path: 94 print('', file=sys.stderr) 95 print(' vvvvvvv', 96 file=sys.stderr) 97 print('', file=sys.stderr) 98 print( 99 'This build requires the %s SDK, but it was not found on your system.' \ 100 % min_sdk_version, file=sys.stderr) 101 print( 102 'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.', 103 file=sys.stderr) 104 print('', file=sys.stderr) 105 print(' ^^^^^^^', 106 file=sys.stderr) 107 print('', file=sys.stderr) 108 sys.exit(1) 109 110 if options.print_sdk_path: 111 _sdk_path = subprocess.check_output( 112 ['xcrun', '-sdk', 'macosx' + best_sdk, '--show-sdk-path']).strip() 113 if isinstance(_sdk_path, bytes): 114 _sdk_path = _sdk_path.decode() 115 print(_sdk_path) 116 return best_sdk 117 118 119if __name__ == '__main__': 120 if sys.platform != 'darwin': 121 raise Exception("This script only runs on Mac") 122 print(main()) 123 sys.exit(0) 124