High level design for shipping Rust Components as Swift Packages
This is a high level description of the decision highlighted in the ADR that introduced Swift Packages as a strategy to ship our Rust components. That document includes that tradeoffs and why we chose this approach.
The strategy includes two main parts:
- The xcframework that is built from a megazord. The xcframework contains the following, built for all our target iOS platforms.
- The compiled Rust code for all the crates listed in
Cargo.toml
as a static library - The C header files and Swift module maps for the components
- The compiled Rust code for all the crates listed in
- The
rust-components-swift
repository which has aPackage.swift
that includes thexcframework
and acts as the swift package the consumers import
The xcframework and application-services
In application-services
, in the megazords/ios-rust
directory, we have the following:
- A Rust crate that serves as the megazord for our iOS distributions. The megazord depends on all the Rust Component crates and re-exports their public APIs.
- Some skeleton files for building an xcframework:
1.
module.modulemap
: The module map tells the Swift compiler how to use C APIs. 1.MozillaRustComponents.h
: The header is used by the module map as a shortcut to specify all the available header files 1.Info.plist
: Theplist
file specifies metadata about the resulting xcframework. For example, architectures and subdirectories. - The
build-xcframework.sh
script that stitches things together into a full xcframework bundle:- The
xcframework
format is not well documented; briefly:- The xcframework is a directory containing the resources compiled for multiple target architectures. The xcframework is distributed as a
.zip
file. - The top-level directory contains a subdirectory per architecture and an
Info.plist
. TheInfo.plist
describes what lives in which directory. - Each subdirectory represents an architecture. And contains a
.framework
directory for that architecture.
- The xcframework is a directory containing the resources compiled for multiple target architectures. The xcframework is distributed as a
- The
It's a little unusual that we're building the xcframework by hand, rather than defining it as the build output of an Xcode project. It turns out to be simpler for our purposes, but does risk diverging from the expected format if Apple changes the details of xcframeworks in future Xcode releases.
The rust-components-swift
repository
The repository is a Swift Package for distributing releases of Mozilla's various Rust-based application components. It provides the Swift source code packaged in a format understood by the Swift package manager, and depends on a pre-compiled binary release of the underlying Rust code published from application-services
The rust-components-swift
repo mainly includes the following:
Package.swift
: Defines all thetargets
andproducts
the package exposes.Package.swift
also includes where the package gets thexcframework
thatapplication-services
builds
make_tag.sh
: A script that does the following:- Generates any dynamically generated Swift code, mainly:
- The uniffi generated Swift bindings
- The Glean metrics
- Creates and commits a git tag that can be pushed to cut a release
- Generates any dynamically generated Swift code, mainly:
Consumers would then import the
rust-components-swift
swift package, by indicating the url of the package on github (i.e https://github.com/mozilla/rust-components-swift) and selecting a version using the git tag.