Skip to content
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
8 changes: 6 additions & 2 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,6 @@ http_archive(
urls = ["https://github.com/MobileNativeFoundation/index-import/releases/download/6.1.0.1/index-import.tar.gz"],
)

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 @@ -219,6 +217,12 @@ register_toolchains(

include("//examples/cross_compilation/android_app:android.MODULE.bazel")
include("//examples/cross_compilation/wasm:wasm.MODULE.bazel")
include("//examples/cross_compilation/static_linux:static_linux.MODULE.bazel")

# 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")
Comment thread
adincebic marked this conversation as resolved.

# Dev dependencies
bazel_dep(name = "bazel_skylib_gazelle_plugin", version = "1.5.0", dev_dependency = True)
Expand Down
30 changes: 30 additions & 0 deletions doc/standalone_toolchain.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,36 @@ linked statically from the SDK, so the reactor is a self-contained

See `examples/cross_compilation/wasm` for an end to end example.

## Building for Static Linux

The `swift` module extension can also download the Static Linux Swift SDK,
which defines matching Swift and C/C++ toolchains targeting
`x86_64-swift-linux-musl` and `aarch64-swift-linux-musl`.

Add the `static_linux_sdk` tag, 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):

```bzl
swift.static_linux_sdk(toolchain_name = "swift_toolchain")

register_toolchains(
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_xcode",
)
```

Then build with a platform that has `@platforms//os:linux`,
`@platforms//cpu:x86_64` or `@platforms//cpu:aarch64`, and
`@rules_swift//swift/toolchains:static_linux` constraints.

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.

See `examples/cross_compilation/static_linux` for an end to end example.

## Using the extension from a non-root module

The extension is intended for the root module — it fails if a non-root
Expand Down
32 changes: 32 additions & 0 deletions examples/cross_compilation/static_linux/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("//examples/embedded:transition.bzl", "transition_binary")
load("//swift:swift.bzl", "swift_binary", "swift_library")

platform(
name = "static-linux-x86_64",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
"//swift/toolchains:static_linux",
],
)
Comment on lines +4 to +11

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if this is something we end up requiring, we should move this somewhere that users can reference it too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Probably at the root?


swift_library(
name = "Greeter",
srcs = ["Sources/Greeter/Greeter.swift"],
module_name = "Greeter",
)

# This only builds for the Static Linux SDK platform configured by the
# transition below, so the //examples/... wildcard skips it on a host platform.
swift_binary(
name = "HelloStaticLinux",
srcs = ["Sources/HelloStaticLinux/main.swift"],
target_compatible_with = ["//swift/toolchains:static_linux"],
deps = [":Greeter"],
)

transition_binary(
name = "hello_static_linux",
binary = ":HelloStaticLinux",
platform = ":static-linux-x86_64",
)
11 changes: 11 additions & 0 deletions examples/cross_compilation/static_linux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Building Swift for Static Linux

A simple executable that cross-compiles Swift to a fully static musl binary with
the Static Linux Swift SDK. See `doc/standalone_toolchain.md` for the toolchain
setup.

## Build

```sh
bazel build //examples/cross_compilation/static_linux:hello_static_linux
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// A plain `swift_library` used as a normal dependency of the 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

public init(subject: String) {
self.subject = subject
}

public func greeting() -> String {
return "Hello, \(subject)!"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Greeter

print(Greeter(subject: "Static Linux").greeting())
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
swift = use_extension("//swift:extensions.bzl", "swift", dev_dependency = True)
swift.static_linux_sdk(toolchain_name = "swift_toolchain")

register_toolchains(
# Register Static Linux before the broad built-in Linux toolchains in the
# root MODULE.bazel; Static Linux platforms are also @platforms//os:linux.
"@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//: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",
dev_dependency = True,
)
2 changes: 2 additions & 0 deletions swift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ bzl_library(
deps = [
"//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",
],
)
Expand Down
143 changes: 131 additions & 12 deletions swift/extensions.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ load("//swift/internal/extensions:swift_releases.bzl", "SWIFT_RELEASES")
load(
"//swift/internal/extensions:swift_sdk_releases.bzl",
"SWIFT_SDK_RELEASES",
"static_linux_sdk_download_url",
"swift_sdk_download_url",
)
load(
"//swift/internal/extensions:swift_sdks.bzl",
"ANDROID_ARCHS",
"STATIC_LINUX_ARCHS",
"swift_android_sdk_repository",
"swift_static_linux_sdk_repository",
"swift_wasm_sdk_repository",
)
load(
"//swift/internal/extensions:toolchains.bzl",
"android_sdk_toolchains_for_platform",
"static_linux_sdk_toolchains_for_platform",
"toolchains_for_platform",
"toolchains_repository",
"wasm_sdk_toolchains_for_platform",
Expand Down Expand Up @@ -116,6 +120,62 @@ def _setup_wasm_sdk(*, tag, toolchain_name, swift_version, platforms):
)
return build_file_content

def _setup_static_linux_sdk(*, tag, toolchain_name, swift_version, platforms):
"""Creates the repositories for a `swift.static_linux_sdk` tag.

Args:
tag: The `static_linux_sdk` tag.
toolchain_name: The name of the `swift.toolchain` tag the SDK extends.
swift_version: The Swift release version of that toolchain.
platforms: The host platforms the toolchain was created for.

Returns:
BUILD file content with the `toolchain` declarations to add to the
toolchains hub repository.
"""
release = None
if swift_version in SWIFT_SDK_RELEASES:
release = SWIFT_SDK_RELEASES[swift_version].get("static_linux")

sdk_version = tag.sdk_version
if not sdk_version:
if not release:
fail("No known Static Linux Swift SDK version for Swift `{}`. Please provide sdk_version.".format(
swift_version,
))
sdk_version = release["version"]

sha256 = tag.sha256
if not sha256:
if not release:
fail("No known Static Linux Swift SDK for version `{}`. Please choose one of {}, or provide the SDK's sha256 and sdk_version.".format(
swift_version,
SWIFT_SDK_RELEASES.keys(),
))
if sdk_version != release["version"]:
fail("No known checksum for Static Linux Swift SDK version `{}` for Swift `{}`. Please provide sha256 when overriding sdk_version.".format(
sdk_version,
swift_version,
))
sha256 = release["sha256"]

build_file_content = ""
for platform in platforms:
repository_name = "{}_static_linux_sdk_{}".format(toolchain_name, platform)
swift_static_linux_sdk_repository(
name = repository_name,
sha256 = sha256,
swift_version = swift_version,
toolchain_repo = "{}_{}".format(toolchain_name, platform),
url = static_linux_sdk_download_url(swift_version, sdk_version),
)
build_file_content += static_linux_sdk_toolchains_for_platform(
platform = platform,
sdk_repository = repository_name,
archs = STATIC_LINUX_ARCHS,
)
return build_file_content

def _sdk_tags_by_toolchain_name(tags, kind):
"""Groups SDK tags by the toolchain they extend, rejecting duplicates."""
tags_by_name = {}
Expand Down Expand Up @@ -146,23 +206,27 @@ def _standalone_toolchain_impl(module_ctx):
root_module.tags.wasm_sdk,
"wasm_sdk",
)
static_linux_sdk_tags = _sdk_tags_by_toolchain_name(
root_module.tags.static_linux_sdk,
"static_linux_sdk",
)

toolchain_names = [
toolchain.name
for toolchain in root_module.tags.toolchain
]
for toolchain_name in android_sdk_tags:
if toolchain_name not in toolchain_names:
fail("The `android_sdk` tag references unknown toolchain `{}`. Please use the name of a `toolchain` tag: {}".format(
toolchain_name,
toolchain_names,
))
for toolchain_name in wasm_sdk_tags:
if toolchain_name not in toolchain_names:
fail("The `wasm_sdk` tag references unknown toolchain `{}`. Please use the name of a `toolchain` tag: {}".format(
toolchain_name,
toolchain_names,
))
for kind, tags in (
("android_sdk", android_sdk_tags),
("wasm_sdk", wasm_sdk_tags),
("static_linux_sdk", static_linux_sdk_tags),
):
for toolchain_name in tags:
if toolchain_name not in toolchain_names:
fail("The `{}` tag references unknown toolchain `{}`. Please use the name of a `toolchain` tag: {}".format(
kind,
toolchain_name,
toolchain_names,
))

toolchains_build_file_content = ""
for toolchain in root_module.tags.toolchain:
Expand Down Expand Up @@ -211,6 +275,13 @@ def _standalone_toolchain_impl(module_ctx):
swift_version = swift_version,
platforms = platforms,
)
if toolchain.name in static_linux_sdk_tags:
toolchains_build_file_content += _setup_static_linux_sdk(
tag = static_linux_sdk_tags[toolchain.name],
toolchain_name = toolchain.name,
swift_version = swift_version,
platforms = platforms,
)

toolchains_repository(
name = toolchain.name,
Expand Down Expand Up @@ -257,6 +328,53 @@ and defines Swift and C++ toolchains targeting `wasm32-unknown-wasip1`.
""",
)

_static_linux_sdk = tag_class(
attrs = {
"sdk_version": attr.string(
doc = """\
The Static Linux SDK version in the artifact bundle filename. May be omitted
for Swift/SDK version pairs known to this version of rules_swift. If this
overrides the known SDK version, `sha256` must also be provided. Custom SDK
versions must preserve the standard Static Linux SDK artifact-bundle layout,
including the `swift-sdk.json` metadata; linker args are read from the SDK's
`linux-static/static-executable-args.lnk`.
""",
),
"sha256": attr.string(
doc = """\
The expected SHA-256 of the SDK artifact bundle. May be omitted only for
Swift/SDK version pairs known to this version of rules_swift.
""",
),
"toolchain_name": attr.string(
doc = "The name of the `toolchain` tag to add this Swift SDK to.",
mandatory = True,
),
},
doc = """\
Downloads the Static Linux Swift SDK matching a `toolchain` tag's Swift version
and defines Swift and C++ toolchains targeting `x86_64-swift-linux-musl` and
`aarch64-swift-linux-musl`.

Register the generated toolchains for the host platforms you build on, e.g.:

```starlark
register_toolchains(
"@swift_toolchain//:swift_toolchain_static_linux_x86_64_xcode",
"@swift_toolchain//:cc_toolchain_static_linux_x86_64_xcode",
)
```

and build with a platform that has `@platforms//os:linux`,
`@platforms//cpu:x86_64` (or `aarch64`), and
`@rules_swift//swift/toolchains:static_linux` constraints.

On Linux hosts, register the Static Linux SDK toolchains before generic
same-architecture Linux Swift toolchains, since both can match a Static Linux
platform and Bazel chooses by registration order.
""",
)

_toolchain = tag_class(attrs = {
"name": attr.string(
doc = "Repository name of the generated toolchain",
Expand All @@ -278,6 +396,7 @@ swift = module_extension(
implementation = _standalone_toolchain_impl,
tag_classes = {
"android_sdk": _android_sdk,
"static_linux_sdk": _static_linux_sdk,
"toolchain": _toolchain,
"wasm_sdk": _wasm_sdk,
},
Expand Down
26 changes: 26 additions & 0 deletions swift/internal/extensions/swift_sdk_releases.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ https://www.swift.org/api/v1/install/releases.json.
SWIFT_SDK_RELEASES = {
"6.3.2": {
"android": "939e933549d12d28f2e0bf71019d734d309859e9773c572657ce565a81f85d68",
"static_linux": {
"sha256": "3fd798bef6f4408f1ea5a6f94ce4d4052830c4326ab85ebc04f983f01b3da407",
"version": "0.1.0",
},
"wasm": "a61f0584c93283589f8b2f42db05c1f9a182b506c2957271402992655591dd7c",
},
}
Expand All @@ -39,3 +43,25 @@ def swift_sdk_download_url(swift_version, sdk):
sdk = sdk,
version = swift_version,
)

def static_linux_sdk_download_url(swift_version, sdk_version):
"""Returns the download URL for a Static Linux Swift SDK artifact bundle.

Args:
swift_version: The Swift release version (e.g. "6.3.2").
sdk_version: The Static Linux SDK version (e.g. "0.1.0").

Returns:
The URL of the `.artifactbundle.tar.gz` for the given release.
"""
if "-snapshot-" in swift_version:
fail("Swift SDKs are only supported for release versions, got `{}`".format(
swift_version,
))
return (
"https://download.swift.org/swift-{version}-release/static-sdk/" +
"swift-{version}-RELEASE/swift-{version}-RELEASE_static-linux-{sdk_version}.artifactbundle.tar.gz"
).format(
sdk_version = sdk_version,
version = swift_version,
)
Loading
Loading