Skip to content

Add support for cross-compiling Swift stdlib with an external sysroot #79090

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7af4661
Set system processor in Libdispatch.cmake for LINUX sdks
xtremekforever Jan 29, 2025
f7f3004
Add ability to compile Swift stdlib with external sysroot
xtremekforever Jan 30, 2025
f6f70e1
Add cross-compile-sysroot option to build scripts
xtremekforever Jan 30, 2025
15826c4
Only include CROSS_COMPILE_SYSROOT if cross-compiling
xtremekforever Jan 31, 2025
47403ae
Use lld in product.py if cross_compile_sysroot is used
xtremekforever Jan 31, 2025
726cb18
Use cross_compile_sysroot in get_linux_sysroot if set
xtremekforever Jan 31, 2025
a31141d
Fix linting issues
xtremekforever Jan 31, 2025
07f3af1
Merge pull request #78909 from xtremekforever/#75341-fix-swift-build-…
MaxDesiatov Jan 27, 2025
d7ee7c8
Find gcc-install-dir in CROSS_COMPILE_SYSROOT for better locating of …
xtremekforever Feb 1, 2025
b7d4eef
Open up cross-compilation to all linux- hosts
xtremekforever Feb 1, 2025
c045204
Fix tests for llvm_linux_cross_compile support, add more tests
xtremekforever Feb 2, 2025
a7d188e
Merge branch 'main' into #78960-swift-stdlib-cross-compile
xtremekforever Feb 2, 2025
47c0498
Find --gcc-install-dir in usr directory of sysroot
xtremekforever Feb 2, 2025
91cad22
Rename cross-compile-sysroot -> cross-compile-sysroots and update wor…
xtremekforever Feb 4, 2025
5bbda49
Remove redundant case for linux-static-*, remove extra whitespace
xtremekforever Feb 4, 2025
3fc1838
Remove --gcc-install-dir and --gcc-toolchain code when using external…
xtremekforever Feb 5, 2025
e205a48
Restore original code for setting SWIFT_SDK_LINUX_ARCH_${arch}_TRIPLE…
xtremekforever Feb 5, 2025
f046aad
Add SWIFT_ prefix to CROSS_COMPILE_SYSROOTS when passed to Swift cmak…
xtremekforever Feb 6, 2025
6448729
Implement new SWIFT_LIBDISPATCH_C_FLAGS and SWIFT_LIBDISPATCH_CXX_FLA…
xtremekforever Feb 6, 2025
c1fb6cb
Update wording for cross-compile-sysroots option
xtremekforever Feb 7, 2025
724757d
Merge branch 'main' into #78960-swift-stdlib-cross-compile
xtremekforever Feb 15, 2025
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
16 changes: 12 additions & 4 deletions cmake/modules/Libdispatch.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,17 @@ foreach(sdk ${DISPATCH_SDKS})

foreach(arch ${ARCHS})
set(LIBDISPATCH_VARIANT_NAME "libdispatch-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}")
set(SWIFT_LIBDISPATCH_C_FLAGS ${CMAKE_C_FLAGS})
set(SWIFT_LIBDISPATCH_CXX_FLAGS ${CMAKE_CXX_FLAGS})

if(sdk MATCHES WINDOWS)
set(SWIFT_LIBDISPATCH_COMPILER_TRIPLE_CMAKE_ARGS -DCMAKE_C_COMPILER_TARGET=${SWIFT_SDK_WINDOWS_ARCH_${arch}_TRIPLE};-DCMAKE_CXX_COMPILER_TARGET=${SWIFT_SDK_WINDOWS_ARCH_${arch}_TRIPLE})
elseif(sdk MATCHES LINUX)
set(SWIFT_LIBDISPATCH_COMPILER_CMAKE_ARGS ${SWIFT_LIBDISPATCH_COMPILER_CMAKE_ARGS};-DCMAKE_SYSROOT=${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH})
set(SWIFT_LIBDISPATCH_COMPILER_TRIPLE_CMAKE_ARGS -DCMAKE_C_COMPILER_TARGET=${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE};-DCMAKE_CXX_COMPILER_TARGET=${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE})
# Use linker used to build Swift
set(SWIFT_LIBDISPATCH_C_FLAGS "${SWIFT_LIBDISPATCH_C_FLAGS} -w -fuse-ld=${SWIFT_USE_LINKER}")
set(SWIFT_LIBDISPATCH_CXX_FLAGS "${SWIFT_LIBDISPATCH_CXX_FLAGS} -w -fuse-ld=${SWIFT_USE_LINKER}")
endif()

if("${sdk}" STREQUAL "ANDROID")
Expand All @@ -93,8 +101,8 @@ foreach(sdk ${DISPATCH_SDKS})
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
${SWIFT_LIBDISPATCH_COMPILER_CMAKE_ARGS}
${SWIFT_LIBDISPATCH_COMPILER_TRIPLE_CMAKE_ARGS}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS=${SWIFT_LIBDISPATCH_C_FLAGS}
-DCMAKE_CXX_FLAGS=${SWIFT_LIBDISPATCH_CXX_FLAGS}
-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
Expand Down Expand Up @@ -193,8 +201,8 @@ foreach(sdk ${DISPATCH_SDKS})
-DCMAKE_AR=${CMAKE_AR}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
${SWIFT_LIBDISPATCH_COMPILER_CMAKE_ARGS}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS=${SWIFT_LIBDISPATCH_C_FLAGS}
-DCMAKE_CXX_FLAGS=${SWIFT_LIBDISPATCH_CXX_FLAGS}
-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}
-DCMAKE_INSTALL_LIBDIR=lib
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
Expand Down
8 changes: 8 additions & 0 deletions cmake/modules/SwiftConfigureSDK.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,14 @@ macro(configure_sdk_unix name architectures)
else()
message(FATAL_ERROR "unknown arch for ${prefix}: ${arch}")
endif()

# If we are using an external sysroot, update path and CXX compile flags to point to it
if(SWIFT_CROSS_COMPILE_SYSROOTS)
set(SWIFT_SDK_${prefix}_ARCH_${arch}_PATH ${SWIFT_CROSS_COMPILE_SYSROOTS})

# Clear hardcoded --gcc-toolchain to let the external sysroot be used to find libstdc++
set(SWIFT_SDK_${prefix}_CXX_OVERLAY_SWIFT_COMPILE_FLAGS "")
endif()
elseif("${prefix}" STREQUAL "FREEBSD")
if(NOT arch MATCHES "(arm64|x86_64)")
message(FATAL_ERROR "unsupported arch for FreeBSD: ${arch}")
Expand Down
13 changes: 12 additions & 1 deletion utils/build-script-impl
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ KNOWN_SETTINGS=(
cross-compile-with-host-tools "" "set to use the clang we build for the host to then build the cross-compile hosts"
cross-compile-install-prefixes "" "semicolon-separated list of install prefixes to use for the cross-compiled hosts. The list expands, so if there are more cross-compile hosts than prefixes, unmatched hosts use the last prefix in the list"
cross-compile-deps-path "" "path for CMake to look for cross-compiled library dependencies, such as libXML2"
cross-compile-sysroots "" "path(s) for CMake to look for cross-compilation sysroots for different platforms or architectures"
cross-compile-append-host-target-to-destdir "1" "turns on appending the host target name of each cross-compiled toolchain to its install-destdir, to keep them separate from the natively-built toolchain"
skip-merge-lipo-cross-compile-tools "" "set to skip running merge-lipo after installing cross-compiled host Swift tools"
coverage-db "" "If set, coverage database to use when prioritizing testing"
Expand Down Expand Up @@ -1103,7 +1104,7 @@ function false_true() {
CROSS_COMPILE_HOSTS=($CROSS_COMPILE_HOSTS)
for t in "${CROSS_COMPILE_HOSTS[@]}"; do
case ${t} in
macosx* | iphone* | appletv* | watch* | linux-armv5 | linux-armv6 | linux-armv7 | android-* | openbsd-* | linux-static-* )
macosx* | iphone* | appletv* | watch* | linux-* | android-* | openbsd-* )
;;
*)
echo "Unknown host to cross-compile for: ${t}"
Expand Down Expand Up @@ -1704,6 +1705,16 @@ for host in "${ALL_HOSTS[@]}"; do
-DLLVM_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/llvm-tblgen
-DSWIFT_INCLUDE_TEST_BINARIES:BOOL=FALSE
)

# This allows passing a sysroot other than "/" to compile Swift and libraries
# It also assumes the sysroot contains arch libraries matching --stdlib-deployment-targets
if [ ! -z "${CROSS_COMPILE_SYSROOTS}" ]; then
cmake_options=(
"${cmake_options[@]}"
-DSWIFT_CROSS_COMPILE_SYSROOTS:STRING="${CROSS_COMPILE_SYSROOTS}"
-DSWIFT_USE_LINKER:STRING="lld"
)
fi
fi

# Command-line parameters override any autodetection that we
Expand Down
6 changes: 6 additions & 0 deletions utils/build_swift/build_swift/driver_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,12 @@ def create_argument_parser():
'library dependencies of the corelibs and other Swift repos, '
'such as the libcurl dependency of FoundationNetworking')

option('--cross-compile-sysroots', store_path,
help='Path(s) to one or more directories that contain C/C++ sysroots for '
'different platforms and/or architectures for cross-compiling Swift. '
'The sysroots must contain C/C++ libraries that match the '
'architectures that are being built for.')

option('--cross-compile-append-host-target-to-destdir', toggle_true,
default=True,
help="Append each cross-compilation host target's name as a subdirectory "
Expand Down
2 changes: 2 additions & 0 deletions utils/build_swift/tests/expected_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
'coverage_db': None,
'cross_compile_append_host_target_to_destdir': True,
'cross_compile_deps_path': None,
'cross_compile_sysroots': None,
'cross_compile_hosts': [],
'infer_cross_compile_hosts_on_darwin': False,
'darwin_deployment_version_ios':
Expand Down Expand Up @@ -816,6 +817,7 @@ class BuildScriptImplOption(_BaseOption):
PathOption('--cmake'),
PathOption('--coverage-db'),
PathOption('--cross-compile-deps-path'),
PathOption('--cross-compile-sysroots'),
PathOption('--host-cc'),
PathOption('--host-cxx'),
PathOption('--host-libtool'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ def convert_to_impl_arguments(self):
impl_args += [
"--cross-compile-deps-path=%s" % args.cross_compile_deps_path
]
if args.cross_compile_sysroots is not None:
impl_args += [
"--cross-compile-sysroots=%s" % args.cross_compile_sysroots
]

if args.test_paths:
impl_args += ["--test-paths", " ".join(args.test_paths)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,8 @@ def get_linux_target_components(self, arch):
def get_linux_sysroot(self, platform, arch):
if not self.is_cross_compile_target('{}-{}'.format(platform, arch)):
return None
if self.args.cross_compile_sysroots:
return self.args.cross_compile_sysroots
sysroot_arch, _, abi = self.get_linux_target_components(arch)
# $ARCH-$PLATFORM-$ABI
# E.x.: aarch64-linux-gnu
Expand Down Expand Up @@ -479,6 +481,11 @@ def common_cross_c_flags(self, platform, arch, include_arch=False):
if self.is_release():
cross_flags.append('-fno-stack-protector')

# Use lld if external sysroot is provided
if (self.is_cross_compile_target('{}-{}'.format(platform, arch))
and self.args.cross_compile_sysroots):
cross_flags.append('-w -fuse-ld=lld')

return self.common_c_flags + cross_flags


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,60 @@ def tearDown(self):
self.toolchain = None
self.args = None

def test_llvm_get_linux_sysroot(self):
def test_llvm_get_linux_sysroot_default(self):
args = argparse.Namespace(
llvm_targets_to_build='X86;ARM;AArch64',
llvm_assertions='true',
compiler_vendor='none',
clang_compiler_version=None,
clang_user_visible_version=None,
cross_compile_hosts='linux-aarch64',
cross_compile_sysroots=None
)

llvm = LLVM(
args=self.args,
args=args,
toolchain=self.toolchain,
source_dir='/path/to/src',
build_dir='/path/to/build')
expected_arg = '/usr/aarch64-linux-gnu'
self.assertIn(expected_arg, llvm.get_linux_sysroot("linux", "aarch64"))

def test_llvm_get_linux_sysroot_external(self):
args = argparse.Namespace(
llvm_targets_to_build='X86;ARM;AArch64',
llvm_assertions='true',
compiler_vendor='none',
clang_compiler_version=None,
clang_user_visible_version=None,
cross_compile_hosts='linux-armv7',
cross_compile_sysroots='sysroot'
)

llvm = LLVM(
args=args,
toolchain=self.toolchain,
source_dir='/path/to/src',
build_dir='/path/to/build')
expected_arg = 'sysroot'
self.assertIn(expected_arg, llvm.get_linux_sysroot("linux", "armv7"))

def test_llvm_common_cross_c_flags_external_sysroot(self):
args = argparse.Namespace(
llvm_targets_to_build='X86;ARM;AArch64',
llvm_assertions='true',
compiler_vendor='none',
clang_compiler_version=None,
build_variant='Debug',
clang_user_visible_version=None,
cross_compile_hosts='linux-armv7',
cross_compile_sysroots='sysroot'
)

llvm = LLVM(
args=args,
toolchain=self.toolchain,
source_dir='/path/to/src',
build_dir='/path/to/build')
expected_arg = '-w -fuse-ld=lld'
self.assertIn(expected_arg, llvm.common_cross_c_flags("linux", "armv7"))