Skip to content

Commit cd62ce0

Browse files
authored
Merge pull request #83503 from finagolfin/droid
[6.2][build] Make it possible to build a cross-compilation toolchain for Android, including Testing Add a linker flag for the upcoming 16 KB page support in Android, generate an Android CMake toolchain file that can be used to cross-compile repos like cmark and Testing, and add a build flag that makes it easy to build cross-compilation toolchains, by disabling the cross-compilation of all host tools and macros for listed --cross-compile-hosts, leaving only the Swift runtime libraries in a cross-compilation SDK.
2 parents 9453946 + 5068951 commit cd62ce0

File tree

14 files changed

+126
-34
lines changed

14 files changed

+126
-34
lines changed

stdlib/cmake/modules/AddSwiftStdlib.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2504,6 +2504,8 @@ function(add_swift_target_library name)
25042504
list(APPEND swiftlib_link_flags_all "-shared")
25052505
# TODO: Instead of `lib${name}.so` find variable or target property which already have this value.
25062506
list(APPEND swiftlib_link_flags_all "-Wl,-soname,lib${name}.so")
2507+
# Ensure compatibility with Android 15+ devices using 16KB memory pages.
2508+
list(APPEND swiftlib_link_flags_all "-Wl,-z,max-page-size=16384")
25072509
endif()
25082510

25092511
if (SWIFTLIB_BACK_DEPLOYMENT_LIBRARY)

test/SILOptimizer/concat_string_literals.32.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
// We have a separate test for 64-bit architectures.
66
// REQUIRES: PTRSIZE=32
7+
// XFAIL: OS=linux-androideabi
78

89
// NOTE: 25185.byteSwapped = 0x62 'a', 0x61 'b'
910
// CHECK-LABEL: test_ascii_scalar_scalar2

utils/build-script-impl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2351,7 +2351,7 @@ for host in "${ALL_HOSTS[@]}"; do
23512351
continue
23522352
fi
23532353

2354-
if [[ "${CROSS_COMPILE_BUILD_SWIFT_TOOLS}" == "0" ]]; then
2354+
if [[ "$(true_false ${CROSS_COMPILE_BUILD_SWIFT_TOOLS})" == "FALSE" ]]; then
23552355
echo "Skipping building Foundation Macros for ${host}, because the host tools are not being built"
23562356
continue
23572357
fi
@@ -2940,7 +2940,7 @@ for host in "${ALL_HOSTS[@]}"; do
29402940
continue
29412941
fi
29422942

2943-
if [[ "${CROSS_COMPILE_BUILD_SWIFT_TOOLS}" == "0" && "${product}" == "foundation_macros" ]]; then
2943+
if [[ "$(true_false ${CROSS_COMPILE_BUILD_SWIFT_TOOLS})" == "FALSE" && "${product}" == "foundation_macros" ]]; then
29442944
echo "Skipping installing Foundation Macros for ${host}, because the host tools are not being built"
29452945
continue
29462946
fi

utils/build_swift/build_swift/driver_arguments.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,12 @@ def create_argument_parser():
677677
"for each cross-compiled toolchain's destdir, useful when building "
678678
"multiple toolchains and can be disabled if only cross-compiling one.")
679679

680+
option('--cross-compile-build-swift-tools', toggle_true,
681+
default=True,
682+
help="Cross-compile the Swift compiler, other host tools from the "
683+
"compiler repository, and various macros for each listed "
684+
"--cross-compile-hosts platform.")
685+
680686
option('--stdlib-deployment-targets', store,
681687
type=argparse.ShellSplitType(),
682688
default=None,

utils/build_swift/tests/expected_options.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
'compiler_vendor': defaults.COMPILER_VENDOR,
156156
'coverage_db': None,
157157
'cross_compile_append_host_target_to_destdir': True,
158+
'cross_compile_build_swift_tools': True,
158159
'cross_compile_deps_path': None,
159160
'cross_compile_hosts': [],
160161
'infer_cross_compile_hosts_on_darwin': False,
@@ -622,6 +623,7 @@ class BuildScriptImplOption(_BaseOption):
622623
EnableOption('--build-swift-clang-overlays'),
623624
EnableOption('--build-swift-remote-mirror'),
624625
EnableOption('--cross-compile-append-host-target-to-destdir'),
626+
EnableOption('--cross-compile-build-swift-tools'),
625627
EnableOption('--color-in-tests'),
626628
EnableOption('--distcc'),
627629
EnableOption('--sccache'),

utils/swift_build_support/swift_build_support/build_script_invocation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ def convert_to_impl_arguments(self):
119119
"--cmake-generator", args.cmake_generator,
120120
"--cross-compile-append-host-target-to-destdir", str(
121121
args.cross_compile_append_host_target_to_destdir).lower(),
122+
"--cross-compile-build-swift-tools", str(
123+
args.cross_compile_build_swift_tools).lower(),
122124
"--build-jobs", str(args.build_jobs),
123125
"--lit-jobs", str(args.lit_jobs),
124126
"--common-cmake-options=%s" % ' '.join(

utils/swift_build_support/swift_build_support/products/cmake_product.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def is_verbose(self):
2424
return self.args.verbose_build
2525

2626
def build_with_cmake(self, build_targets, build_type, build_args,
27-
prefer_native_toolchain=False):
27+
prefer_native_toolchain=False, build_llvm=True):
2828
assert self.toolchain.cmake is not None
2929
cmake_build = []
3030
_cmake = cmake.CMake(self.args, self.toolchain,
@@ -71,9 +71,7 @@ def build_with_cmake(self, build_targets, build_type, build_args,
7171
env=env)
7272

7373
is_llvm = self.product_name() == "llvm"
74-
if (not is_llvm and not self.args.skip_build) or (
75-
is_llvm and self.args._build_llvm
76-
):
74+
if (not is_llvm and not self.args.skip_build) or (is_llvm and build_llvm):
7775
cmake_opts = [self.build_dir, "--config", build_type]
7876

7977
shell.call(

utils/swift_build_support/swift_build_support/products/llvm.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,13 @@ def build(self, host_target):
249249
# space/time efficient than -g on that platform.
250250
llvm_cmake_options.define('LLVM_USE_SPLIT_DWARF:BOOL', 'YES')
251251

252-
if not self.args._build_llvm:
252+
build = True
253+
if not self.args._build_llvm or (not self.args.cross_compile_build_swift_tools
254+
and self.is_cross_compile_target(host_target)):
253255
# Indicating we don't want to build LLVM at all should
254256
# override everything.
255257
build_targets = []
258+
build = False
256259
elif self.args.skip_build or not self.args.build_llvm:
257260
# We can't skip the build completely because the standalone
258261
# build of Swift depends on these.
@@ -399,7 +402,8 @@ def build(self, host_target):
399402

400403
self._handle_cxx_headers(host_target, platform)
401404

402-
self.build_with_cmake(build_targets, self.args.llvm_build_variant, [])
405+
self.build_with_cmake(build_targets, self.args.llvm_build_variant, [],
406+
build_llvm=build)
403407

404408
# copy over the compiler-rt builtins for iOS/tvOS/watchOS to ensure
405409
# that Swift's stdlib can use compiler-rt builtins when targeting
@@ -484,7 +488,9 @@ def should_install(self, host_target):
484488
Whether or not this product should be installed with the given
485489
arguments.
486490
"""
487-
return self.args.install_llvm
491+
return self.args.install_llvm and (
492+
self.args.cross_compile_build_swift_tools or
493+
not self.is_cross_compile_target(host_target))
488494

489495
def install(self, host_target):
490496
"""

utils/swift_build_support/swift_build_support/products/product.py

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def get_linux_target(self, platform, arch):
389389
sysroot_arch, vendor, abi = self.get_linux_target_components(arch)
390390
return '{}-{}-linux-{}'.format(sysroot_arch, vendor, abi)
391391

392-
def generate_linux_toolchain_file(self, platform, arch):
392+
def generate_linux_toolchain_file(self, platform, arch, crosscompiling=True):
393393
"""
394394
Generates a new CMake tolchain file that specifies Linux as a target
395395
platform.
@@ -402,18 +402,34 @@ def generate_linux_toolchain_file(self, platform, arch):
402402

403403
toolchain_args = {}
404404

405-
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Linux'
406-
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch
405+
if crosscompiling:
406+
if platform == "linux":
407+
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Linux'
408+
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch
409+
elif platform == "android":
410+
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Android'
411+
toolchain_args['CMAKE_SYSTEM_VERSION'] = self.args.android_api_level
412+
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch if not arch == 'armv7' \
413+
else 'armv7-a'
414+
toolchain_args['CMAKE_ANDROID_NDK'] = self.args.android_ndk
415+
toolchain_args['CMAKE_FIND_ROOT_PATH'] = self.args.cross_compile_deps_path
416+
# This is a workaround for a CMake 3.30+ bug,
417+
# https://gitlab.kitware.com/cmake/cmake/-/issues/26154, and can
418+
# be removed once that is fixed.
419+
toolchain_args['CMAKE_SHARED_LINKER_FLAGS'] = '\"\"'
407420

408421
# We only set the actual sysroot if we are actually cross
409422
# compiling. This is important since otherwise cmake seems to change the
410423
# RUNPATH to be a relative rather than an absolute path, breaking
411424
# certain cmark tests (and maybe others).
412-
maybe_sysroot = self.get_linux_sysroot(platform, arch)
413-
if maybe_sysroot is not None:
414-
toolchain_args['CMAKE_SYSROOT'] = maybe_sysroot
415-
416-
target = self.get_linux_target(platform, arch)
425+
if platform == "linux":
426+
maybe_sysroot = self.get_linux_sysroot(platform, arch)
427+
if maybe_sysroot is not None:
428+
toolchain_args['CMAKE_SYSROOT'] = maybe_sysroot
429+
430+
target = self.get_linux_target(platform, arch)
431+
elif platform == "android":
432+
target = '%s-unknown-linux-android%s' % (arch, self.args.android_api_level)
417433
if self.toolchain.cc.endswith('clang'):
418434
toolchain_args['CMAKE_C_COMPILER_TARGET'] = target
419435
if self.toolchain.cxx.endswith('clang++'):
@@ -459,10 +475,30 @@ def generate_toolchain_file_for_darwin_or_linux(
459475
platform, arch,
460476
macos_deployment_version=override_macos_deployment_version)
461477
self.cmake_options.define('CMAKE_TOOLCHAIN_FILE:PATH', toolchain_file)
462-
elif platform == "linux":
463-
toolchain_file = self.generate_linux_toolchain_file(platform, arch)
478+
elif platform == "linux" or platform == "android":
479+
# Always cross-compile for linux, but not on Android, as a native
480+
# compile on Android does not use the NDK and its CMake config.
481+
cross_compile = platform == "linux" or \
482+
self.is_cross_compile_target(host_target)
483+
toolchain_file = self.generate_linux_toolchain_file(platform, arch,
484+
cross_compile)
464485
self.cmake_options.define('CMAKE_TOOLCHAIN_FILE:PATH', toolchain_file)
465486

487+
if cross_compile and platform == "android":
488+
resource_dir = None
489+
# build-script-impl products build before the install and use
490+
# the Swift stdlib from the compiler build directory instead,
491+
# while products built even before that currently do not support
492+
# cross-compiling Swift.
493+
if not self.is_before_build_script_impl_product() and \
494+
not self.is_build_script_impl_product():
495+
install_path = self.host_install_destdir(host_target) + \
496+
self.args.install_prefix
497+
resource_dir = '%s/lib/swift' % install_path
498+
flags = targets.StdlibDeploymentTarget.get_target_for_name(
499+
host_target).platform.swift_flags(self.args, resource_dir)
500+
self.cmake_options.define('CMAKE_Swift_FLAGS', flags)
501+
466502
return toolchain_file
467503

468504
def get_openbsd_toolchain_file(self):

utils/swift_build_support/swift_build_support/products/swift_testing.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,11 @@ def install(self, host_target):
127127
install_prefix = install_destdir + self.args.install_prefix
128128

129129
self.install_with_cmake(['install'], install_prefix)
130+
131+
@classmethod
132+
def is_build_script_impl_product(cls):
133+
return False
134+
135+
@classmethod
136+
def is_before_build_script_impl_product(cls):
137+
return False

0 commit comments

Comments
 (0)