blob: 755680300f6df23ab4df274ef213c3fcda3c8c6f [file] [log] [blame]
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import os
import shutil
import subprocess
import sys
from dataclasses import dataclass
# Imports from //flutter/build/pyutil.
sys.path.insert(1, os.path.join(os.path.dirname(__file__), os.pardir))
from pyutil.file_util import symlink
# This script creates symlinks to Apple SDKs, Platforms, and host toolchain
# under //flutter/prebuilts.
PREBUILTS = os.path.realpath(os.path.join(
os.path.dirname(__file__), os.pardir, os.pardir, 'flutter', 'prebuilts',
))
# Supported SDKs.
SDKS = ['iphoneos', 'iphonesimulator', 'macosx']
def parse_arguments():
"""Parses command-line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument(
'--as-gclient-hook',
default=False,
action='store_true',
help='Whether the script is running as a gclient hook.',
)
parser.add_argument(
'--print-paths',
default=False,
action='store_true',
help='Print the SDK paths in key=value form.',
)
parser.add_argument(
'--symlink',
type=str,
help='Whether to create a symlink in the buildroot to the SDK.',
)
parser.add_argument(
'--sdk',
choices=SDKS,
help='Which SDK to find.',
)
return parser.parse_args()
def get_toolchain_path() -> str:
"""Returns path for the host toolchain."""
xcode_path = subprocess.check_output(['xcode-select', '-print-path'], timeout=300).decode('utf-8').strip()
return os.path.join(xcode_path, 'Toolchains/XcodeDefault.xctoolchain')
def get_platform_path(sdk) -> str:
"""Returns the platform path for the specified SDK."""
return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-platform-path'], timeout=300).decode('utf-8').strip()
def get_sdk_path(sdk) -> str:
"""Returns the SDK path for the specified SDK."""
return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-path'], timeout=300).decode('utf-8').strip()
@dataclass
class TargetSdk:
"""A target-platform SDK."""
name: str
platform_path: str
sdk_path: str
@dataclass
class SdkInfo:
"""The host toolchain and all requested SDK paths."""
toolchain_path: str
sdks: list
def get_sdk_info(sdks) -> SdkInfo:
"""Collects paths for host toolchain and all specified SDKs."""
sdk_info = SdkInfo(get_toolchain_path(), [])
for sdk in sdks:
platform_path = get_platform_path(sdk)
sdk_path = get_sdk_path(sdk)
sdk_info.sdks.append(TargetSdk(sdk, platform_path, sdk_path))
return sdk_info
def print_paths(sdk_info) -> None:
"""Prints all SDK paths in key=value from to stdout."""
print('toolchain_path="%s"' % sdk_info.toolchain_path)
for sdk in sdk_info.sdks:
print('%s_platform_path="%s"' % (sdk.name, sdk.platform_path))
print('%s_sdk_path="%s"' % (sdk.name, sdk.sdk_path))
def create_symlink(target_dir, orig_path) -> str:
"""Creates a symlink in target_dir that points to orig_path and has the same basename."""
target_path = os.path.join(target_dir, os.path.basename(orig_path))
symlink(orig_path, target_path)
return target_path
def create_symlinks(sdk_info, symlink_path, delete_existing_links) -> SdkInfo:
"""
Creates SDK symlinks under symlink_path.
Returns an SdkInfo with paths updated to use the symlinks instead of original paths.
"""
platforms_path = os.path.join(symlink_path, 'Platforms')
sdks_path = os.path.join(symlink_path, 'SDKs')
if delete_existing_links:
# Remove any old files created by this script under the prebuilts dir.
if os.path.isdir(platforms_path):
shutil.rmtree(platforms_path)
if os.path.isdir(sdks_path):
shutil.rmtree(sdks_path)
# Create toolchain symlink.
toolchain_path = create_symlink(sdks_path, sdk_info.toolchain_path)
symlink_sdk_info = SdkInfo(toolchain_path, [])
for sdk in sdk_info.sdks:
platform_path = create_symlink(platforms_path, sdk.platform_path)
sdk_path = create_symlink(sdks_path, sdk.sdk_path)
symlink_sdk_info.sdks.append(TargetSdk(sdk.name, platform_path, sdk_path))
return symlink_sdk_info
def main(argv):
args = parse_arguments()
# On CI, Xcode is not yet installed when gclient hooks are being run.
# This is because the version of Xcode that CI installs might depend on the
# contents of the repo, so the repo must be set up first, which includes
# running the gclient hooks. Instead, on CI, this script will be run during
# GN.
running_on_luci = os.environ.get('LUCI_CONTEXT') is not None
if running_on_luci and args.as_gclient_hook:
return 0
# Gather SDK paths.
sdks = [args.sdk] if args.sdk else SDKS
sdk_info = get_sdk_info(sdks)
# For non-LUCI runs, default symlink_dir to the prebuilts dir.
symlink_dir = args.symlink
if not running_on_luci and symlink_dir is None:
symlink_dir = PREBUILTS
# Create symlinks.
if symlink_dir:
sdk_info = create_symlinks(sdk_info, symlink_dir, args.as_gclient_hook)
# Print paths to stdout.
if args.print_paths:
print_paths(sdk_info)
return 0
if __name__ == '__main__':
if sys.platform != 'darwin':
raise Exception('This script only runs on Mac')
sys.exit(main(sys.argv))