11 releases (6 major breaking)
128.0.1 | Jul 8, 2024 |
---|---|
127.0.1 | May 30, 2024 |
125.0.1 | Mar 28, 2024 |
123.0.1 | Feb 1, 2024 |
97.5.1 | Apr 17, 2023 |
#418 in Development tools
607 stars & 48 watchers
140KB
2K
SLoC
XCFramework build for distributing Rust code on iOS
This directory contains the logic for compiling all of our Rust code into a binary artifact that can be easily distributed to iOS consumers. If you run the following script:
$> ./build-xcframework.sh
Then it should produce a file named MozillaRustComponents.xcframework.zip
that
contains:
- The compiled Rust code for all the crates listed in
Cargo.toml
, as a static library, - along with their corresponding C header files and Swift module maps,
- built for all our target iOS platforms, as an "XCFramework" bundle.
The resulting .zip
is suitable for consumption as a Swift Package binary dependency.
To support focus-ios
which only needs a subset of the Rust code, we also support generating a smaller xcframework using:
$> ./build-xcframework.sh --focus
Then it should produce a file named FocusRustComponents.xcframework.zip
in the focus
directory that serves as the binary that focus-ios
eventually consumes.
What's here?
In this directory we have:
- A Rust crate that serves as the "megazord" for our iOS distributions; it basically depends on all the Rust Component crates and re-exports their public APIs.
- Some skeleton files for building an XCFramework:
module.modulemap
is a "module map", which tells the Swift compiler how to use C-level APIs.MozillaRustComponents.h
is an "umbrella header", used by the module map as a shortcut to specify all the available header files.Info.plist
specified metadata about the resulting XCFramework, such as the available architectures and their subdirectories.
- The
build-xcframework.sh
script which knows how to stitch things together into a full XCFramework bundle.- The XCFramework format is not well documented; briefly:
- It's a directory containing resources compiled for multiple target architectures,
typically distributed as
.zip
file. - The top-level directory contains a subdirectory per architecture, and an
Info.plist
file that says what things live in which directory. - Each subdirectory contains a
.framework
directory for that architecture. There are notes on the layout of an individual.framework
in the links below.
- It's a directory containing resources compiled for multiple target architectures,
typically distributed as
- The XCFramework format is not well documented; briefly:
- The
focus
directory, which is a megazord that gets built forfocus-ios
. The components in thefocus
megazord are a subset of the components in the overallios-rust
megazord and thus are only built on release.
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 detailts of XCFrameworks in future Xcode releases.
Adding crates
For details on adding new crates, checkout the documentation for adding new spm components
Testing local Rust changes
For testing changes against our project's test suite, you'll need to:
- Run
./build-xcframework.sh
to build the XCFramework bundle.
Note: You only need to do this if the underlying rust code changes, if you're just changing *.swift code. You don't need to rebuild!
- Test the changes either via Xcode or command line:
- Xcode:
open megazords/ios-rust/MozillaTestServices.xcodeproj
- Command line:
./automation/run_ios_tests.sh
- Xcode:
Testing local changes for consumers
See the following documents for testing local changes in consumers:
Testing from a pre-release commit
For release builds, we publish the resulting MozillaRustComponents.xcframework.zip
as a GitHub
release artifact, and then update https://github.com/mozilla/rust-components-swift to point to
it via URL and hash.
For testing from a PR or unreleased git commit, you can:
- Find the CircleCI job named
ios-test-and-artifacts
for the commit you want to test, click through to view it on CircleCI, and confirm that it completed successfully. - In the "artifacts" list, locate
MozillaRustComponents.xcframework.zip
and note its URL. - In the "steps" list, find the step named
XCFramework bundle checksum
, and note the checksum in its output. - Take a local checkout of https://github.com/mozilla/rust-components-swift,
and edit its
Swift.package
to use the above URL and checksum for theMozillaRustComponents
binary target. - Commit the result to your local checkout, and make a git tag in
MAJOR.MINOR.PATCH
format. - Add your local
rust-components-swift
repo as a Swift Package dependency in a consuming app. If testing in firefox-ios, you can run:
$ cd firefox-ios
$ ./rust_components_local.sh ../rust-components-swift
alternatively, you can specify file:///path/to/rust-components-swift
as the git repo.
* (You'll have to remove any existing depdency on https://github.com/mozilla/rust-components-swift first)
Note that your changes must be committed. You can import them either as a local git tag or by choosing the branch of rust-components-swift
.
Further Reading
- The Architecture Design Doc wherein we decided to distribute things this way:
- An introduction to the problem that XCFrameworks as designed to solve:
- A brief primer on the contents of a Framework, which is useful when you want to construct one by hand:
- The documentation on Module Maps, which is how C-level code gets exposed to Swift: