Skip to content

[build][android] Use a CMake toolchain file to cross-compile Testing #83260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/SILOptimizer/concat_string_literals.32.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

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

// NOTE: 25185.byteSwapped = 0x62 'a', 0x61 'b'
// CHECK-LABEL: test_ascii_scalar_scalar2
Expand Down
1 change: 0 additions & 1 deletion test/SILOptimizer/dead_array_elim.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

// REQUIRES: swift_stdlib_no_asserts
// REQUIRES: swift_in_compiler
// XFAIL: OS=linux-androideabi

// These tests check whether DeadObjectElimination pass runs as a part of the
// optimization pipeline and eliminates dead array literals in Swift code.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,18 +409,33 @@ def generate_linux_toolchain_file(self, platform, arch, crosscompiling=True):
toolchain_args = {}

if crosscompiling:
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Linux'
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch
if platform == "linux":
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Linux'
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch
elif platform == "android":
toolchain_args['CMAKE_SYSTEM_NAME'] = 'Android'
toolchain_args['CMAKE_SYSTEM_VERSION'] = self.args.android_api_level
toolchain_args['CMAKE_SYSTEM_PROCESSOR'] = arch if not arch == 'armv7' \
else 'armv7-a'
toolchain_args['CMAKE_ANDROID_NDK'] = self.args.android_ndk
toolchain_args['CMAKE_FIND_ROOT_PATH'] = self.args.cross_compile_deps_path
# This is a workaround for a CMake 3.30+ bug,
# https://gitlab.kitware.com/cmake/cmake/-/issues/26154, and can
# be removed once that is fixed.
toolchain_args['CMAKE_SHARED_LINKER_FLAGS'] = '\"\"'

# We only set the actual sysroot if we are actually cross
# compiling. This is important since otherwise cmake seems to change the
# RUNPATH to be a relative rather than an absolute path, breaking
# certain cmark tests (and maybe others).
maybe_sysroot = self.get_linux_sysroot(platform, arch)
if maybe_sysroot is not None:
toolchain_args['CMAKE_SYSROOT'] = maybe_sysroot

target = self.get_linux_target(platform, arch)
if platform == "linux":
maybe_sysroot = self.get_linux_sysroot(platform, arch)
if maybe_sysroot is not None:
toolchain_args['CMAKE_SYSROOT'] = maybe_sysroot

target = self.get_linux_target(platform, arch)
elif platform == "android":
target = '%s-unknown-linux-android%s' % (arch, self.args.android_api_level)
if self.toolchain.cc.endswith('clang'):
toolchain_args['CMAKE_C_COMPILER_TARGET'] = target
if self.toolchain.cxx.endswith('clang++'):
Expand Down Expand Up @@ -466,10 +481,30 @@ def generate_toolchain_file_for_darwin_or_linux(
platform, arch,
macos_deployment_version=override_macos_deployment_version)
self.cmake_options.define('CMAKE_TOOLCHAIN_FILE:PATH', toolchain_file)
elif platform == "linux":
toolchain_file = self.generate_linux_toolchain_file(platform, arch)
elif platform == "linux" or platform == "android":
# Always cross-compile for linux, but not on Android, as a native
# compile on Android does not use the NDK and its CMake config.
cross_compile = platform == "linux" or \
self.is_cross_compile_target(host_target)
toolchain_file = self.generate_linux_toolchain_file(platform, arch,
cross_compile)
self.cmake_options.define('CMAKE_TOOLCHAIN_FILE:PATH', toolchain_file)

if cross_compile and platform == "android":
resource_dir = None
# build-script-impl products build before the install and use
# the Swift stdlib from the compiler build directory instead,
# while products built even before that currently do not support
# cross-compiling Swift.
if not self.is_before_build_script_impl_product() and \
not self.is_build_script_impl_product():
install_path = self.host_install_destdir(host_target) + \
self.args.install_prefix
resource_dir = '%s/lib/swift' % install_path
flags = targets.StdlibDeploymentTarget.get_target_for_name(
host_target).platform.swift_flags(self.args, resource_dir)
self.cmake_options.define('CMAKE_Swift_FLAGS', flags)

return toolchain_file

def get_openbsd_toolchain_file(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,11 @@ def install(self, host_target):
install_prefix = install_destdir + self.args.install_prefix

self.install_with_cmake(['install'], install_prefix)

@classmethod
def is_build_script_impl_product(cls):
return False

@classmethod
def is_before_build_script_impl_product(cls):
return False
11 changes: 7 additions & 4 deletions utils/swift_build_support/swift_build_support/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def contains(self, target_name):
return True
return False

def swift_flags(self, args):
def swift_flags(self, args, resource_path=None):
"""
Swift compiler flags for a platform, useful for cross-compiling
"""
Expand Down Expand Up @@ -154,12 +154,15 @@ def uses_host_tests(self):
"""
return True

def swift_flags(self, args):
def swift_flags(self, args, resource_path=None):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is currently used to generate Swift cross-compilation flags for build-script-impl products alone, but I was able to reuse it for Testing by passing in a separate resource_path. That resource_path calculation can only be done externally, where the particular build product is known.

flags = '-target %s-unknown-linux-android%s ' % (args.android_arch,
args.android_api_level)

flags += '-resource-dir %s/swift-%s-%s/lib/swift ' % (
args.build_root, self.name, args.android_arch)
if resource_path is not None:
flags += '-resource-dir %s ' % (resource_path)
else:
flags += '-resource-dir %s/swift-%s-%s/lib/swift ' % (
args.build_root, self.name, args.android_arch)

android_toolchain_path = self.ndk_toolchain_path(args)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# REQUIRES: standalone_build
# REQUIRES: OS=macosx

# RUN: %empty-directory(%t)
# RUN: mkdir -p %t
# RUN: SKIP_XCODE_VERSION_CHECK=1 SWIFT_BUILD_ROOT=%t %swift_src_root/utils/build-script --dry-run --install-all --cmake %cmake --skip-build-llvm --skip-build-swift 2>&1 | %FileCheck %s
# RUN: SKIP_XCODE_VERSION_CHECK=1 SWIFT_BUILD_ROOT=%t %swift_src_root/utils/build-script --dry-run --install-all --cmake %cmake --skip-build-llvm --skip-build-swift --cross-compile-hosts=android-aarch64 --skip-local-build --android --android-ndk %t/ndk/ 2>&1 | %FileCheck --check-prefix=ANDROID %s

# CHECK: DRY_RUN! Writing Toolchain file to path:{{.*}}BuildScriptToolchain.cmake
# CHECK: cmake {{.*}}-DCMAKE_TOOLCHAIN_FILE:PATH={{.*}}BuildScriptToolchain.cmake {{.*}}cmark

# ANDROID: DRY_RUN! Writing Toolchain file to path:{{.*}}cmark-android-aarch64/BuildScriptToolchain.cmake
# ANDROID: cmake {{.*}}-DCMAKE_TOOLCHAIN_FILE:PATH={{.*}}cmark-android-aarch64/BuildScriptToolchain.cmake
# ANDROID: -DCMAKE_Swift_FLAGS=-target aarch64-unknown-linux-android