• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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