Skip to content
Closed
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
36 changes: 27 additions & 9 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ use_repo(
apple_cc_configure = use_extension("@apple_support//crosstool:setup.bzl", "apple_cc_configure_extension")
use_repo(apple_cc_configure, "local_config_apple_cc")

register_toolchains("//swift/toolchains:all")

system_sdk = use_extension("//swift:extensions.bzl", "system_sdk")
system_sdk.configure_sdks(
# NOTE: This doesn't apply to downstream repos
Expand Down Expand Up @@ -90,6 +88,9 @@ swift.wasm_sdk(
swift.android_sdk(
toolchain_name = "swift_toolchain",
)
swift.static_linux_sdk(
toolchain_name = "swift_toolchain",
)
use_repo(
swift,
"swift_toolchain",
Expand Down Expand Up @@ -117,19 +118,25 @@ register_toolchains(
)

register_toolchains(
# Swift SDK toolchains for cross-compiling to WebAssembly and Android;
# used by //examples/cross_compilation. As with the embedded toolchains
# above, we register only the host platforms used by CI rather than
# `@swift_toolchain//:all`, because rules_swift cannot yet auto-select a
# Linux distribution and `:all` would make the host/exec toolchain
# ambiguous across distros. A consumer that builds on a single host
# platform can simply register `@swift_toolchain//:all`.
# Swift SDK toolchains for cross-compiling to WebAssembly, Android, and
# Static Linux; used by //examples/cross_compilation. As with the embedded
# toolchains above, we register only the host platforms used by CI rather
# than `@swift_toolchain//:all`, because rules_swift cannot yet auto-select
# a Linux distribution and `:all` would make the host/exec toolchain
# ambiguous across distros. A consumer that builds on a single host platform
# can simply register `@swift_toolchain//:all`.
"@swift_toolchain//:cc_toolchain_android_aarch64_ubuntu22.04",
"@swift_toolchain//:cc_toolchain_android_aarch64_ubuntu22.04-aarch64",
"@swift_toolchain//:cc_toolchain_android_aarch64_xcode",
"@swift_toolchain//:cc_toolchain_android_x86_64_ubuntu22.04",
"@swift_toolchain//:cc_toolchain_android_x86_64_ubuntu22.04-aarch64",
"@swift_toolchain//:cc_toolchain_android_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_aarch64_ubuntu22.04",
"@swift_toolchain//:cc_toolchain_static_linux_aarch64_ubuntu22.04-aarch64",
"@swift_toolchain//:cc_toolchain_static_linux_aarch64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_ubuntu22.04",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_ubuntu22.04-aarch64",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_wasm32_ubuntu22.04",
"@swift_toolchain//:cc_toolchain_wasm32_ubuntu22.04-aarch64",
"@swift_toolchain//:cc_toolchain_wasm32_xcode",
Expand All @@ -139,12 +146,23 @@ register_toolchains(
"@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04",
"@swift_toolchain//:swift_toolchain_android_x86_64_ubuntu22.04-aarch64",
"@swift_toolchain//:swift_toolchain_android_x86_64_xcode",
"@swift_toolchain//:swift_toolchain_static_linux_aarch64_ubuntu22.04",
"@swift_toolchain//:swift_toolchain_static_linux_aarch64_ubuntu22.04-aarch64",
"@swift_toolchain//:swift_toolchain_static_linux_aarch64_xcode",
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_ubuntu22.04",
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_ubuntu22.04-aarch64",
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:swift_toolchain_wasm32_ubuntu22.04",
"@swift_toolchain//:swift_toolchain_wasm32_ubuntu22.04-aarch64",
"@swift_toolchain//:swift_toolchain_wasm32_xcode",
dev_dependency = True,
)

# Keep broad built-in Linux toolchains after Static Linux SDK toolchains:
# Static Linux platforms are also `@platforms//os:linux`, and Bazel chooses the
# first compatible toolchain.
register_toolchains("//swift/toolchains:all")

# Dev dependencies
bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True)
bazel_dep(name = "gazelle", version = "0.46.0", dev_dependency = True)
Expand Down
61 changes: 48 additions & 13 deletions doc/standalone_toolchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,15 @@ bazel run @rules_swift//tools/swift-releases -- list \
main-snapshot-2024-08-01 --platform xcode --platform ubuntu22.04
```

## Cross-compiling with Swift SDKs (WebAssembly and Android)
## Cross-compiling with Swift SDKs

swift.org publishes "Swift SDK" artifact bundles (the bundles consumed by
`swift sdk install`) that let the host compiler cross-compile for platforms
it cannot target by itself. The `swift` extension can download these and
define matching Swift and C/C++ toolchains, so that plain `swift_library`
and `swift_binary` targets build for those platforms under `--platforms`.

Add the `wasm_sdk` and/or `android_sdk` tags, referencing the `toolchain`
Add the SDK tags you need, referencing the `toolchain`
tag by name (the Swift module format is not stable across compiler
versions, so the SDK is always downloaded for exactly the toolchain's
version):
Expand All @@ -174,6 +174,10 @@ swift.android_sdk(
# api_level = 28, # the default
)

swift.static_linux_sdk(
toolchain_name = "swift_toolchain",
)

register_toolchains(
# WebAssembly (wasm32-unknown-wasip1), per host platform you build on.
"@swift_toolchain//:swift_toolchain_wasm32_xcode",
Expand All @@ -183,21 +187,38 @@ register_toolchains(
"@swift_toolchain//:cc_toolchain_android_aarch64_xcode",
"@swift_toolchain//:swift_toolchain_android_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_android_x86_64_xcode",
# Static Linux (musl), per architecture and host platform.
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:swift_toolchain_static_linux_aarch64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_aarch64_xcode",
)
```

If you build on a single host platform, you can register everything the
extension generates (standalone, embedded, and Swift-SDK toolchains) in one
line instead of listing the matrix:
The `_xcode` suffix in these labels is the existing standalone-toolchain
platform name for the Swift.org macOS `.pkg`; it does not mean the Xcode-bundled
Swift toolchain is used.

Register Static Linux SDK toolchains before any generic same-architecture Linux
Swift toolchains (for example `//swift/toolchains:all`). Static Linux platforms
still carry `@platforms//os:linux`, so a generic Linux toolchain can also match;
Bazel uses registration order to choose among compatible toolchains.

If you build on a single host platform and are not targeting Static Linux from
a same-architecture Linux host, you can register everything the extension
generates (standalone, embedded, and Swift-SDK toolchains) in one line instead
of listing the matrix:

```bzl
register_toolchains("@swift_toolchain//:all")
```

Avoid `:all` when you configure multiple Linux distributions, for the same
reason the standalone host toolchains are registered explicitly: rules_swift
cannot yet auto-select a distribution, so `:all` would make the host/exec
toolchain ambiguous across them.
For Static Linux on Linux hosts, prefer explicit registration so the Static
Linux SDK toolchain labels appear before any same-architecture generic Linux
toolchain labels. Also avoid `:all` when you configure multiple Linux
distributions, for the same reason the standalone host toolchains are registered
explicitly: rules_swift cannot yet auto-select a distribution, so `:all` would
make the host/exec toolchain ambiguous across them.

Then build with a platform carrying the matching constraints, for example:

Expand All @@ -217,6 +238,15 @@ platform(
"@platforms//os:android",
],
)

platform(
name = "static-linux-x86_64",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
"@rules_swift//swift/toolchains:static_linux",
],
)
```

```sh
Expand Down Expand Up @@ -253,21 +283,26 @@ Details worth knowing:

* The Swift standard library is linked statically from the SDK, matching
the behavior of `swiftc` with these SDKs. WebAssembly binaries are
self-contained `wasm32-wasip1` modules (runnable with `wasmtime` et al.).
self-contained `wasm32-wasip1` modules (runnable with `wasmtime` et al.);
Static Linux binaries are fully static `*-swift-linux-musl` executables.
* Android binaries link against the NDK's `libc++_shared.so`, which must be
packaged with the application. Reference it host-independently as
`@<toolchain_name>//:libcxx_shared_<arch>` (e.g.
`@swift_toolchain//:libcxx_shared_aarch64`); the alias selects the NDK for
the build host automatically.
* Static Linux toolchains require the
`@rules_swift//swift/toolchains:static_linux` constraint in the target
platform. This prevents the musl SDK toolchain from being selected for normal
Linux/glibc platforms.
* The `android_sdk` tag downloads the Android NDK (for its sysroot and
clang) in addition to the Swift SDK. The NDK is only fetched when an
Android target is actually built; WebAssembly-only builds do not download
it. The NDK version and checksums can be overridden with the
`ndk_version` and `ndk_sha256s` attributes.
* As with toolchains, checksums for the SDK bundles are bundled for a
curated list of releases (see
`swift/internal/extensions/swift_sdk_releases.bzl`); for other releases,
pass `sha256` explicitly.
curated list of Swift/SDK version pairs (see
`swift/internal/extensions/swift_sdk_releases.bzl`); when using an
unlisted SDK version, pass `sha256` explicitly.

### Coexistence with `rules_apple`

Expand Down
33 changes: 31 additions & 2 deletions examples/cross_compilation/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ load("//swift:swift.bzl", "swift_binary", "swift_library")
package(default_visibility = ["//visibility:public"])

# Platforms covered by the Swift SDK toolchains registered by this repository's
# dev `MODULE.bazel` (via the `swift` extension's `wasm_sdk`/`android_sdk`
# tags). Build the targets below with `--platforms` set to one of these.
# dev `MODULE.bazel` (via the `swift` extension's SDK tags). Build the targets
# below with `--platforms` set to one of these.
platform(
name = "wasm32-wasip1",
constraint_values = [
Expand All @@ -22,6 +22,15 @@ platform(
],
)

platform(
name = "static-linux-x86_64",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
"//swift/toolchains:static_linux",
],
)

# A plain library dependency, compiled for whichever platform depends on it.
# Both platform-specific entry points below call into it, demonstrating that a
# normal `swift_library` is reused unchanged across targets.
Expand Down Expand Up @@ -58,6 +67,7 @@ transition_binary(
name = "Reactor.wasm",
binary = ":Reactor",
platform = ":wasm32-wasip1",
tags = ["manual"],
)

# A static web app embedding the reactor: `index.html` + `Reactor.wasm` in one
Expand Down Expand Up @@ -99,4 +109,23 @@ transition_binary(
name = "libSwiftJNI.so",
binary = ":SwiftJNI",
platform = ":android-aarch64",
tags = ["manual"],
)

# ---------------------------------------------------------------------------
# Static Linux: a fully static musl executable, runnable on Linux systems.
# ---------------------------------------------------------------------------

swift_binary(
name = "HelloStaticLinux",
srcs = ["Sources/HelloStaticLinux/main.swift"],
tags = ["manual"],
deps = [":Greeter"],
)

transition_binary(
name = "hello_static_linux",
binary = ":HelloStaticLinux",
platform = ":static-linux-x86_64",
tags = ["manual"],
)
18 changes: 14 additions & 4 deletions examples/cross_compilation/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Cross-compilation example (WebAssembly + Android)
# Cross-compilation example (WebAssembly + Android + Static Linux)

Builds plain `swift_library` / `swift_binary` targets for non-host platforms
using the Swift SDK toolchains registered by this repository's `MODULE.bazel`
(via the `swift` extension's `wasm_sdk` and `android_sdk` tags). See
(via the `swift` extension's `wasm_sdk`, `android_sdk`, and
`static_linux_sdk` tags). See
`doc/standalone_toolchain.md` for the toolchain setup.

All targets are tagged `manual` because they download the Swift SDK bundles
Expand All @@ -16,6 +17,7 @@ All targets are tagged `manual` because they download the Swift SDK bundles
| `:Reactor.wasm` | `Reactor.wasm` | A WebAssembly **reactor** (`swift_binary(linkshared)`), no `main`, with exported functions |
| `:web_app` | `web_app/` | A static site embedding `Reactor.wasm`, driven from JS — see [`web/README.md`](web/README.md) |
| `:libSwiftJNI.so` | `libSwiftJNI.so` | An Android **JNI shared library** (`swift_binary(linkshared)`) that calls `:Greeter` |
| `:hello_static_linux` | `hello_static_linux` | A fully static Linux executable targeting `x86_64-swift-linux-musl` |

```sh
# WebAssembly reactor (runnable with wasmtime):
Expand All @@ -30,11 +32,19 @@ python3 -m http.server -d bazel-bin/examples/cross_compilation/web_app 8000

# Android JNI shared library:
bazel build //examples/cross_compilation:libSwiftJNI.so

# Static Linux executable:
bazel build //examples/cross_compilation:hello_static_linux
```

Each `transition_binary` target builds its `swift_binary` under the matching
platform (`:wasm32-wasip1` / `:android-aarch64`); you can equivalently pass
`--platforms=//examples/cross_compilation:wasm32-wasip1` on the command line.
platform (`:wasm32-wasip1` / `:android-aarch64` /
`:static-linux-x86_64`); you can equivalently pass a platform on the command
line, for example:

* `--platforms=//examples/cross_compilation:wasm32-wasip1`
* `--platforms=//examples/cross_compilation:android-aarch64`
* `--platforms=//examples/cross_compilation:static-linux-x86_64`

## Android app

Expand Down
6 changes: 3 additions & 3 deletions examples/cross_compilation/Sources/Greeter/Greeter.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// A plain `swift_library` used as a normal dependency of the
/// platform-specific entry points (the Android JNI shared library and the
/// WebAssembly reactor). Nothing in here is platform-specific; it is compiled
/// for whichever platform the depending target is built for.
/// platform-specific entry points (the WebAssembly reactor, Android JNI shared
/// library, and Static Linux executable). Nothing in here is platform-specific;
/// it is compiled for whichever platform the depending target is built for.
public struct Greeter {
private let subject: String

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Greeter

print(Greeter(subject: "Static Linux").greeting())
2 changes: 2 additions & 0 deletions swift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ bzl_library(
"//swift/internal:repositories",
"//swift/internal/extensions:standalone_toolchain",
"//swift/internal/extensions:swift_releases",
"//swift/internal/extensions:swift_sdk_releases",
"//swift/internal/extensions:swift_sdks",
"//swift/internal/extensions:toolchains",
"@bazel_features//:features",
],
Expand Down
Loading