From c23d52003eabe306563dc84d00e6e62bcf18ec0c Mon Sep 17 00:00:00 2001 From: Ethan Kusters Date: Tue, 29 Nov 2022 14:54:43 -0800 Subject: [PATCH 1/3] Support cross compilation in macOS toolchain builds Updates the build script used in SwiftCI for building the `docc` executable as part of Swift.org toolchains to support cross compilation. Currently the `docc` executable included in the otherwise universal macOS toolchain only supports x86_64. This resolves the issue. --- build-script-helper.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/build-script-helper.py b/build-script-helper.py index 31a0a2df76..57eb261d7d 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -16,8 +16,10 @@ from __future__ import print_function import argparse +import json import sys import os, platform +import re import subprocess def printerr(message): @@ -43,6 +45,7 @@ def parse_args(args): parser.add_argument('--install-dir', default=None, help='The location to install the docc executable to.') parser.add_argument('--copy-doccrender-from', default=None, help='The location to copy an existing Swift-DocC-Render template from.') parser.add_argument('--copy-doccrender-to', default=None, help='The location to install an existing Swift-DocC-Render template to.') + parser.add_argument("--cross-compile-hosts", dest="cross_compile_hosts", help="List of cross compile hosts targets.", default=[]) parsed = parser.parse_args(args) @@ -167,6 +170,14 @@ def get_swiftpm_options(action, args): # Library rpath for swift, dispatch, Foundation, etc. when installing '-Xlinker', '-rpath', '-Xlinker', '$ORIGIN/../lib/swift/linux', ] + + build_target = get_build_target(args) + cross_compile_hosts = args.cross_compile_hosts + if cross_compile_hosts: + if re.search('-apple-macosx', build_target) and re.match('macosx-', cross_compile_hosts): + swiftpm_args += ["--arch", "x86_64", "--arch", "arm64"] + else: + printerr("cannot cross-compile for %s" % cross_compile_hosts) if action == 'install': # When tests are run on the host machine, `docc` is located in the build directory; to find @@ -245,6 +256,23 @@ def install(args, env): install_path=copy_render_to, verbose=verbose ) + +def get_build_target(args): + """Returns the target-triple of the current machine or for cross-compilation.""" + # Adapted from https://github.com/apple/swift-package-manager/blob/fde9916d/Utilities/bootstrap#L296 + try: + command = [args.swiftc_path, '-print-target-info'] + target_info_json = subprocess.check_output(command, stderr=subprocess.PIPE, universal_newlines=True).strip() + args.target_info = json.loads(target_info_json) + if platform.system() == 'Darwin': + return args.target_info["target"]["unversionedTriple"] + return args.target_info["target"]["triple"] + except Exception as e: + # Temporary fallback for Darwin. + if platform.system() == 'Darwin': + return 'x86_64-apple-macosx' + else: + fatal_error(str(e)) def docc_bin_path(swift_exec, args, env, verbose): cmd = [ From 12b6fc7d7757a62ba20a942340390ca1df65f5d8 Mon Sep 17 00:00:00 2001 From: Ethan Kusters Date: Tue, 29 Nov 2022 22:13:11 -0800 Subject: [PATCH 2/3] Provide correct args to SwiftPM when requesting bin path The bin path is different when building for multiple architectures so we need to pass the complete swiftpm args we use during a full build when requesting the bin path instead of a custom set. --- build-script-helper.py | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/build-script-helper.py b/build-script-helper.py index 57eb261d7d..e21ad70795 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -179,7 +179,7 @@ def get_swiftpm_options(action, args): else: printerr("cannot cross-compile for %s" % cross_compile_hosts) - if action == 'install': + if action == 'install' or action == 'show-bin-path': # When tests are run on the host machine, `docc` is located in the build directory; to find # its linked libraries (Swift runtime dependencies), `docc` needs to link against the host # machine's toolchain libraries. When installing docc on the target machine, the `docc` @@ -189,6 +189,9 @@ def get_swiftpm_options(action, args): if action == 'test': swiftpm_args += ['--parallel'] + if action == 'show-bin-path': + swiftpm_args += ['--show-bin-path'] + return swiftpm_args def invoke_swift(action, products, env, args, swiftpm_args): @@ -197,7 +200,7 @@ def invoke_swift(action, products, env, args, swiftpm_args): for product in products: invoke_swift_single_product(action, product, env, args, swiftpm_args) -def invoke_swift_single_product(action, product, env, args, swiftpm_args): +def get_call_to_invoke_swift_single_product(action, product, args, swiftpm_args): call = [args.swift_exec, action] + swiftpm_args if platform.system() != 'Darwin': @@ -208,6 +211,16 @@ def invoke_swift_single_product(action, product, env, args, swiftpm_args): call.extend(['--test-product', product]) else: call.extend(['--product', product]) + + return call + +def invoke_swift_single_product(action, product, env, args, swiftpm_args): + call = get_call_to_invoke_swift_single_product( + action=action, + product=product, + args=args, + swiftpm_args=swiftpm_args + ) # Tell Swift-DocC that we are building in a build-script environment so that # it does not need to be rebuilt if it has already been built before. @@ -228,7 +241,6 @@ def install(args, env): verbose=args.verbose # Find the docc executable location docc_path = docc_bin_path( - swift_exec=os.path.join(os.path.join(args.toolchain, 'bin'), 'swift'), args=args, env=env, verbose=verbose @@ -274,16 +286,17 @@ def get_build_target(args): else: fatal_error(str(e)) -def docc_bin_path(swift_exec, args, env, verbose): - cmd = [ - swift_exec, - 'build', - '--show-bin-path', - '--package-path', args.package_path, - '--scratch-path', args.build_dir, - '--configuration', args.configuration, - '--product', 'docc' - ] +def docc_bin_path(args, env, verbose): + cmd = get_call_to_invoke_swift_single_product( + action='build', + product='docc', + args=args, + swiftpm_args=get_swiftpm_options( + action='show-bin-path', + args=args + ) + ) + if verbose: print(' '.join([escape_cmd_arg(arg) for arg in cmd])) return os.path.join( From affdeef3141238e655e7d9ba31ca65dec8f07229 Mon Sep 17 00:00:00 2001 From: Ethan Kusters Date: Wed, 30 Nov 2022 15:17:22 -0800 Subject: [PATCH 3/3] Use correct swift executable path in get_build_target --- build-script-helper.py | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/build-script-helper.py b/build-script-helper.py index e21ad70795..f28acfc7e8 100755 --- a/build-script-helper.py +++ b/build-script-helper.py @@ -272,19 +272,13 @@ def install(args, env): def get_build_target(args): """Returns the target-triple of the current machine or for cross-compilation.""" # Adapted from https://github.com/apple/swift-package-manager/blob/fde9916d/Utilities/bootstrap#L296 - try: - command = [args.swiftc_path, '-print-target-info'] - target_info_json = subprocess.check_output(command, stderr=subprocess.PIPE, universal_newlines=True).strip() - args.target_info = json.loads(target_info_json) - if platform.system() == 'Darwin': - return args.target_info["target"]["unversionedTriple"] - return args.target_info["target"]["triple"] - except Exception as e: - # Temporary fallback for Darwin. - if platform.system() == 'Darwin': - return 'x86_64-apple-macosx' - else: - fatal_error(str(e)) + command = [args.swift_exec, '-print-target-info'] + target_info_json = subprocess.check_output(command, stderr=subprocess.PIPE, universal_newlines=True).strip() + args.target_info = json.loads(target_info_json) + if platform.system() == 'Darwin': + return args.target_info["target"]["unversionedTriple"] + + return args.target_info["target"]["triple"] def docc_bin_path(args, env, verbose): cmd = get_call_to_invoke_swift_single_product(