Necessary Disclaimer
Some may consider this pitch as premature, as the upstream Swift toolchain doesn't have full support for WebAssembly yet. The problem is that SwiftWasm team doesn't have enough capacity to submit all of the changes to the compiler by the time the next version of Swift is branched off.
At the same time, we already have a few packages that we're actively using with the SwiftWasm toolchain and allow other people to depend on. Additionally, the SwiftWasm build of SwiftPM has very little (and soon hopefully none at all) differences from upstream SwiftPM. We'd like changes that enable Swift support for WebAssembly to land in SwiftPM first. This will allow us to support more WebAssembly features in the near future without fragmenting the whole Swift ecosystem.
wasm
as a Supported Platform in Package Manifests
As a quick introduction, I need to mention that WebAssembly is a collection of multiple proposals that are at different implementation stages in WebAssembly hosts. The bare minimum is called WebAssembly MVP and is available in all major browsers. Other features such as atomics, SIMD, reference types and many more are not as widely available (with Safari lagging behind in most of these).
The SwiftWasm team would be happy to start experimenting with atomics, SIMD, and reference types when that is possible. Atomics is a big one, as it unblocks multi-threading support with big parts of core libraries that are currently unavailable in SwiftWasm. We could then make Dispatch and major parts of Foundation available in browsers.
I don't think we'll be able to do that transparently to our users. I'm convinced that use of atomics should be opt-in, at least per package. This would allow package authors to preserve compatibility with older browsers. It's obviously applicable to the rest of WebAssembly features, so we need a way to specify this in package manifests.
My pitch here is to introduce a new SupportedPlatform.WasmFeatures
struct conforming to OptionSet
in the PackageDescription
module.
extension SupportedPlatform {
/// The supported WebAssembly features.
public struct WasmFeatures: Encodable, OptionSet {
public init(rawValue: Int64) {
self.rawValue = rawValue
}
/// The underlying features representation.
public let rawValue: Int64
/// Minimum available feature set.
static let mvp = WasmFeatures([])
/// WebAssembly System Interface is available.
static let wasi = WasmFeatures(rawValue: 1 << 0)
/// Shared linear memory and atomic memory access are available.
static let atomics = WasmFeatures(rawValue: 1 << 1)
/// Fixed-width SIMD is available.
static let simd = WasmFeatures(rawValue: 1 << 2)
}
}
Not all Wasm features are specified here as some of them are too low-level. I've only picked a few that could be useful in the near future, but the list can be easily expanded (as long as we don't have more than 64 features and run out of bits in the rawValue
property).
This way our users would be able to specify features they require in Package.swift
:
// swift-tools-version:5.4
// the Swift toolchain version that supports this is assumed to be 5.4,
// but is not guaranteed
import PackageDescription
let package = Package(
name: "SwiftWasmApp",
platforms: [.wasm([.atomics, .simd])]
// other package settings omitted here for brevity
)
Alternatives considered
Keeping the status quo
We could keep the situation as is, but I'm convinced this would be detrimental to the user experience. We could also wait until WebAssembly support is fully available in the upstream Swift toolchain, but that could put barriers to development and adoption of the SwiftWasm ecosystem. If we discuss this pitch as early as possible and it is accepted, we hope for the implementation to land in the current merge window. If it is rejected, we'll get the necessary feedback and start working on alternatives early enough for this to be resolved soon.
Specifying versions of Wasm hosts and browsers
We could allow specifying browsers and their versions directly as supported platforms:
// swift-tools-version:5.4
// the Swift toolchain version that supports this is assumed to be 5.4,
// but is not guaranteed
import PackageDescription
let package = Package(
name: "SwiftWasmApp",
platforms: [.chrome(68), .safari(15), .firefox(79)]
// other package settings omitted here for brevity
)
In this case I guess some part of the toolchain (or just carton
itself in the short term) would have to maintain a database of what features are available in what browser versions. But in the end that would require more infrastructure changes to work. Additionally, specifying Wasm features and browser versions is not mutually exclusive in principle. .wasm(.simd)
could be useful for non-browser WebAssembly hosts, while .firefox(79)
would imply a JavaScript environment and DOM availability, which is also useful to encode in platform requirements.
If the community considers specifying browser versions in the list of support platforms useful, I would prefer this to be discussed as a separate pitch.
Source-level checks
The are different levels of feature checks to discuss. We could also add support for @available
attributes and if #available
runtime checks at the source code level. As we see, Apple platforms support all of these, and what would be the reason to not support them for other platforms? Package-level checks in SwiftPM are easy to implement though (I have a PR for it in the SwiftWasm fork), while the source-level checks should be discussed separately. It still would be interesting to gauge the interest in the community for any of these.
This change is additive, so I don't think it could harm other platforms that Swift supports in some way.
Thanks for reading, and I look forward to your feedback!