Skip to content

Enable building swift-testing for wasm32-unknown-wasip1-threads #607

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion schemes/main/build/build-target-toolchain.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ build_target_toolchain() {
env DESTDIR="$TRIPLE_DESTDIR" \
cmake --install "$TARGET_BUILD_ROOT/$STDLIB_PRODUCT-$HOST_SUFFIX" --prefix /usr

local swift_testing_build_dir="$TARGET_BUILD_ROOT/swift-testing-$SHORT_TRIPLE"
local swift_testing_build_dir="$TARGET_BUILD_ROOT/wasmswiftsdk-$HOST_SUFFIX/swift-testing/$TRIPLE"
# TODO: Remove this check once we build swift-testing for +threads target
if [[ -d "$swift_testing_build_dir" ]]; then
env DESTDIR="$TRIPLE_DESTDIR" \
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
From e46480e98c8eb6eb08b8ec0bb0de58fbd9831ff3 Mon Sep 17 00:00:00 2001
From: Yuta Saito <[email protected]>
Date: Mon, 9 Jun 2025 21:39:17 +0000
Subject: [PATCH] [wasm] Emit libTesting.a objects with single-threaded LLVM
codegen unit

Since 5f2b0022d14d6eaddd48d4f36034c31218965ead, swift-testing is being
compiled with WMO, which removes some of inter-object references in
object files by DCE. The inter-object reference removal revealed a
long-standing issue that the runtime metadata sections of objects in an
archive are not always included in the final binary if symbols from
those objects are not referenced anywhere. To force including all
metadata sections in the final binary, we have to emit everything in a
single object file when building the archive.
This issue happens only for Wasm SDK, which ships swift-testing as a
static archive.
---
.../swift_build_support/products/wasmswiftsdk.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py b/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
index e5769ca9622..ad4f197a174 100644
--- a/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
+++ b/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
@@ -69,9 +69,12 @@ class WasmSwiftSDK(product.Product):
'CMAKE_Swift_COMPILER_TARGET', swift_host_triple)
swift_testing.cmake_options.define('CMAKE_SYSROOT', wasi_sysroot)
swift_resource_dir = os.path.join(dest_dir, 'usr', 'lib', 'swift_static')
+ # For statically linked objects in an archive, we have to use singlethreaded
+ # LLVM codegen unit to prevent runtime metadata sections from being stripped
+ # at link-time.
swift_testing.cmake_options.define(
'CMAKE_Swift_FLAGS',
- f'-sdk {wasi_sysroot} -resource-dir {swift_resource_dir}')
+ f'-sdk {wasi_sysroot} -resource-dir {swift_resource_dir} -Xfrontend -enable-single-module-llvm-emission')
clang_resource_dir = os.path.join(dest_dir, 'usr', 'lib', 'clang')
swift_testing.cmake_options.define(
'CMAKE_CXX_FLAGS', f'-resource-dir {clang_resource_dir}')
--
2.39.5 (Apple Git-154)

Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
From b702fbfc0d98516fae058c7b43908d55e1f8e67e Mon Sep 17 00:00:00 2001
From: Yuta Saito <[email protected]>
Date: Wed, 11 Jun 2025 16:05:40 +0900
Subject: [PATCH] [wasm] Enable building swift-testing for
wasm32-unknown-wasip1-threads

---
.../products/wasmswiftsdk.py | 102 ++++++++++--------
1 file changed, 58 insertions(+), 44 deletions(-)

diff --git a/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py b/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
index ad4f197a174..987722f901b 100644
--- a/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
+++ b/utils/swift_build_support/swift_build_support/products/wasmswiftsdk.py
@@ -16,6 +16,7 @@ from . import product
from . import wasisysroot
from .swift_testing import SwiftTestingCMakeShim
from .wasmstdlib import WasmStdlib, WasmThreadsStdlib
+from .cmake_product import CMakeProduct
from .. import shell


@@ -41,52 +42,66 @@ class WasmSwiftSDK(product.Product):
def _target_package_path(self, swift_host_triple):
return os.path.join(self.build_dir, 'Toolchains', swift_host_triple)

- def _build_swift_testing(self, swift_host_triple, short_triple, wasi_sysroot):
- # TODO: We currently build swift-testing outside of SwiftTesting
- # build-script product because we build Wasm stdlib outside of
- # the main Swift build unit and we can't use build-script's cross
- # compilation infrastructure.
- # Once stdlib build is decoupled from compiler's CMake build unit
- # and we can use different CMake options for different targets
- # for stdlib build, we can fully unify library builds with the
- # regular path.
- dest_dir = self._target_package_path(swift_host_triple)
+ def _append_platform_cmake_options(self, cmake_options, swift_host_triple, has_pthread, wasi_sysroot, extra_swift_flags):
+ cmake_options.define('CMAKE_SYSTEM_NAME:STRING', 'WASI')
+ cmake_options.define('CMAKE_SYSTEM_PROCESSOR:STRING', 'wasm32')
+ cmake_options.define('CMAKE_C_COMPILER_TARGET', swift_host_triple)
+ cmake_options.define('CMAKE_CXX_COMPILER_TARGET', swift_host_triple)
+ cmake_options.define(
+ 'CMAKE_Swift_COMPILER_TARGET', swift_host_triple)
+ cmake_options.define('CMAKE_SYSROOT', wasi_sysroot)

- swift_testing = SwiftTestingCMakeShim(
+ dest_dir = self._target_package_path(swift_host_triple)
+ swift_resource_dir = os.path.join(dest_dir, 'usr', 'lib', 'swift_static')
+ clang_resource_dir = os.path.join(swift_resource_dir, 'clang')
+
+ swift_flags = ['-sdk', wasi_sysroot, '-resource-dir', swift_resource_dir] + extra_swift_flags
+ c_flags = ['-resource-dir', clang_resource_dir]
+ cxx_flags = c_flags + ['-fno-exceptions']
+ if has_pthread:
+ clang_flags = ['-mthread-model', 'posix', '-pthread']
+ c_flags.extend(clang_flags)
+ cxx_flags.extend(clang_flags)
+ swift_flags.extend(['-Xcc', '-matomics', '-Xcc', '-mbulk-memory', '-Xcc', '-mthread-model', '-Xcc', 'posix', '-Xcc', '-pthread'])
+
+ cmake_options.define('CMAKE_Swift_FLAGS', ' '.join(swift_flags))
+ cmake_options.define('CMAKE_C_FLAGS', ' '.join(c_flags))
+ cmake_options.define('CMAKE_CXX_FLAGS', ' '.join(cxx_flags))
+ cmake_options.define('CMAKE_Swift_COMPILER_FORCED', 'TRUE')
+ cmake_options.define('CMAKE_CXX_COMPILER_FORCED', 'TRUE')
+ cmake_options.define('CMAKE_BUILD_TYPE', self.args.build_variant)
+
+ # Explicitly choose ar and ranlib from just-built LLVM tools since tools in the host system
+ # unlikely support Wasm object format.
+ native_toolchain_path = self.native_toolchain_path(self.args.host_target)
+ cmake_options.define('CMAKE_AR', os.path.join(native_toolchain_path, 'bin', 'llvm-ar'))
+ cmake_options.define('CMAKE_RANLIB', os.path.join(native_toolchain_path, 'bin', 'llvm-ranlib'))
+
+ def _build_swift_testing(self, swift_host_triple, has_pthread, wasi_sysroot):
+ swift_testing = CMakeProduct(
args=self.args,
toolchain=self.toolchain,
source_dir=os.path.join(
os.path.dirname(self.source_dir), 'swift-testing'),
- build_dir=os.path.join(
- os.path.dirname(self.build_dir),
- 'swift-testing-%s' % short_triple))
-
- swift_testing.cmake_options.define('CMAKE_SYSTEM_NAME:STRING', 'WASI')
- swift_testing.cmake_options.define('CMAKE_SYSTEM_PROCESSOR:STRING', 'wasm32')
- swift_testing.cmake_options.define(
- 'CMAKE_CXX_COMPILER_TARGET', swift_host_triple)
- swift_testing.cmake_options.define(
- 'CMAKE_Swift_COMPILER_TARGET', swift_host_triple)
- swift_testing.cmake_options.define('CMAKE_SYSROOT', wasi_sysroot)
- swift_resource_dir = os.path.join(dest_dir, 'usr', 'lib', 'swift_static')
+ build_dir=os.path.join(self.build_dir, 'swift-testing', swift_host_triple))
# For statically linked objects in an archive, we have to use singlethreaded
# LLVM codegen unit to prevent runtime metadata sections from being stripped
# at link-time.
- swift_testing.cmake_options.define(
- 'CMAKE_Swift_FLAGS',
- f'-sdk {wasi_sysroot} -resource-dir {swift_resource_dir} -Xfrontend -enable-single-module-llvm-emission')
- clang_resource_dir = os.path.join(dest_dir, 'usr', 'lib', 'clang')
- swift_testing.cmake_options.define(
- 'CMAKE_CXX_FLAGS', f'-resource-dir {clang_resource_dir}')
- swift_testing.cmake_options.define('CMAKE_Swift_COMPILER_FORCED', 'TRUE')
- swift_testing.cmake_options.define('CMAKE_CXX_COMPILER_FORCED', 'TRUE')
-
- swift_testing.build('wasi-wasm32')
+ self._append_platform_cmake_options(
+ swift_testing.cmake_options, swift_host_triple, has_pthread, wasi_sysroot,
+ extra_swift_flags=['-Xfrontend', '-enable-single-module-llvm-emission'])
+ swift_testing.cmake_options.define('BUILD_SHARED_LIBS', 'FALSE')
+ swift_testing.cmake_options.define('CMAKE_Swift_COMPILATION_MODE', 'wholemodule')
+ swift_testing.cmake_options.define('SwiftTesting_MACRO', 'NO')
+
+ swift_testing.build_with_cmake([], self.args.build_variant, [],
+ prefer_native_toolchain=True)
+ dest_dir = self._target_package_path(swift_host_triple)
with shell.pushd(swift_testing.build_dir):
shell.call([self.toolchain.cmake, '--install', '.', '--prefix', '/usr'],
env={'DESTDIR': dest_dir})

- def _build_target_package(self, swift_host_triple, short_triple,
+ def _build_target_package(self, swift_host_triple, has_pthread,
stdlib_build_path, llvm_runtime_libs_build_path,
wasi_sysroot):

@@ -107,7 +122,7 @@ class WasmSwiftSDK(product.Product):
'--component', 'clang_rt.builtins-wasm32'],
env={'DESTDIR': clang_dir})
# Build swift-testing
- self._build_swift_testing(swift_host_triple, short_triple, wasi_sysroot)
+ self._build_swift_testing(swift_host_triple, has_pthread, wasi_sysroot)

return dest_dir

@@ -115,17 +130,15 @@ class WasmSwiftSDK(product.Product):
build_root = os.path.dirname(self.build_dir)

target_packages = []
- # NOTE: We have three types of target triples:
+ # NOTE: We have two types of target triples:
# 1. swift_host_triple: The triple used by the Swift compiler's '-target' option
# 2. clang_multiarch_triple: The triple used by Clang to find library
# and header paths from the sysroot
# https://github.com/llvm/llvm-project/blob/73ef397fcba35b7b4239c00bf3e0b4e689ca0add/clang/lib/Driver/ToolChains/WebAssembly.cpp#L29-L36
- # 3. short_triple: The triple used by build-script to name the build directory
- for swift_host_triple, clang_multiarch_triple, short_triple, build_basename in [
- ('wasm32-unknown-wasi', 'wasm32-wasi', 'wasi-wasm32', 'wasmstdlib'),
- # TODO: Enable threads stdlib once sdk-generator supports multi-target SDK
- # ('wasm32-unknown-wasip1-threads', 'wasm32-wasip1-threads',
- # 'wasip1-threads-wasm32', 'wasmthreadsstdlib'),
+ for swift_host_triple, clang_multiarch_triple, build_basename, build_sdk, has_pthread in [
+ ('wasm32-unknown-wasi', 'wasm32-wasi', 'wasmstdlib', True, False),
+ # TODO: Include p1-threads in the Swift SDK once sdk-generator supports multi-target SDK
+ ('wasm32-unknown-wasip1-threads', 'wasm32-wasip1-threads', 'wasmthreadsstdlib', False, True),
]:
stdlib_build_path = os.path.join(
build_root, '%s-%s' % (build_basename, host_target))
@@ -135,9 +148,10 @@ class WasmSwiftSDK(product.Product):
build_root, '%s-%s' % ('wasmllvmruntimelibs', host_target),
clang_multiarch_triple)
package_path = self._build_target_package(
- swift_host_triple, short_triple, stdlib_build_path,
+ swift_host_triple, has_pthread, stdlib_build_path,
llvm_runtime_libs_build_path, wasi_sysroot)
- target_packages.append((swift_host_triple, wasi_sysroot, package_path))
+ if build_sdk:
+ target_packages.append((swift_host_triple, wasi_sysroot, package_path))

swiftc_path = os.path.abspath(self.toolchain.swiftc)
toolchain_path = os.path.dirname(os.path.dirname(swiftc_path))
--
2.39.5 (Apple Git-154)