Swift Package for Mozilla's Rust Components
This 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 mozilla/application-services.
For more information, please consult:
- application-services ADR-0003, which describes the overall plan for distributing Rust-based components as Swift packages.
- The Swift Package Manager docs and GitHub repo, which explain the details of how Swift Packages work (and hence why this repo is set up the way it is).
- The
ios-rust
crate which is currently responsible for publishing the pre-builtMozillaRustComponents.xcframework.zip
bundle on which this repository depends.
Overview
Here's a diagram of how this repository relates to the application-services repository and its release artifacts:
Key points:
- The
application-services
repo publishes a binary artifactMozillaRustComponents.xcframework.zip
containing the Rust code and FFI definitions for all components, compiled together into a single library. - The
Package.swift
file referencesMozillaRustComponents.xcframework.zip
as a Swift binary target. - The
Package.swift
file defines an individual module for the Swift wrapper code of each component.- Each module references its Swift source code directly as files in the repo.
- Each module depends on
MozillaRustComponentsWrapper
which wrapsMozillaRustComponents
to provide the pre-compiled Rust code.
Cutting a new release
Whenever a new release of the underlying components is availble, we need to tag a new release in this repo to make them available to Swift components. To do so:
- Edit
Package.swift
to update the URL and checksum ofMozillaRustComponents.xcframework.zip
. - Run
./make_tag.sh --as-version {APP_SERVICES_VERSION} X.Y.Z
to create the new tag. - Run
git push origin X.Y.Z
to publish it to GitHub.
Adding a new component
To add a new component to be distributed via this repo, you'll need to:
- Add its Rust code and
.h
files to the build for theMozillaRustComponents.xcframework.zip
bundle, following the docs for theios-rust
crate. - If the component needs to dynamically generate any Swift code (e.g. for UniFFI bindings, or Glean metrics), add logic for doing so to the
./generate.sh
script in this repository.- Swift packages can't dynamically generate code at build time, so we use the
./generate.sh
script to do it ahead-of-time when publishing a release.
- Swift packages can't dynamically generate code at build time, so we use the
- Edit
./Package.swift
to add the new component.- Add a new library product for the component under "products".
- Add a corresponding target for the component under "targets".
- Make sure it depends on "MozillaRustComponentsWrapper" to pull in the pre-compiled Rust code, as well as on any third-party Swift packages that it may require.
- Follow the instructions below to test it out locally.
That's it! The component will be included in the next release of this package.
Testing locally
Swift Packages can only be installed from a git repository, but luckily it is possible to use a local checkout for a git repository for local testing.
You may also need to follow the instructions for locally testing the ios-rust
crate if you need to test changes in the underlying Rust code.
To test out some local changes to this repo:
- Make your changes in a local checkout and commit them.
- Make a new tag via
./make_tag.sh -f 0.0.1
.- (You won't push this tag anywhere, but using a very low version number helps guard against any adverse consequences if it does accidentally escape your local machine).
- In a consuming application, delete the Swift Package dependency on
https://github.com/mozilla/rust-components-swift
and replace it with a dependency onfile:///path/to/your/local/checkout/rust-components-swift
at the0.0.
release.
Testing against a local application-services checkout
To run against a local application services checkout, the make_tag.sh
script supports setting a local path using a -l
flag, for example:
./make_tag -l ../application-services 0.0.1
That's it! The consuming application should be able to import the package from your local checkout.