cargo-swift

repository·main·Indexed 43 days ago

https://github.com/antoniusnaumann/cargo-swift

A Cargo plugin for building Swift Packages from Rust code using Mozilla's UniFFI. It automates the bridging process, XCFramework creation, and Swift Package Manager structure for iOS and macOS applications. Requires macOS and specific version matching between cargo-swift and uniffi-rs (e.g., cargo-swift 0.11.1 for UniFFI 0.31.1).

Tokens
4.7K
Snippets
19
Records
30
Agent score
51%

What's inside cargo-swift

  1. Understand cargo-swift configuration precedence

    main

    When providing configuration values, cargo-swift resolves conflicts using the following order of precedence (highest to lowest):

    1. Command-line arguments (e.g., --platforms macos ios)
    2. Crate-level metadata in [package.metadata.swiftpackage] within Cargo.toml
    3. Workspace-level metadata in [workspace.metadata.swiftpackage] within the workspace Cargo.toml
    4. Interactive prompts (values provided during runtime if not found in the methods above)
  2. Bundle a Rust library as a Swift Package with cargo swift package

    main

    To package an existing Rust library as a Swift Package (compatible with Swift Package Manager for iOS and macOS apps), run cargo swift package.

    This command is interactive and will prompt you for:

    1. The Swift package name.
    2. The target platforms.

    If required toolchains for your selected target platforms are missing, cargo-swift will offer to install them automatically.

    cargo swift package
  3. Install cargo-swift

    main

    Install the cargo-swift plugin using cargo install.

    Important Requirements:

    • This plugin can only be used on macOS because it requires proprietary Apple toolchains.
    • You must ensure the version of cargo-swift you install matches the version of uniffi-rs used in your Rust project.
    cargo install cargo-swift
  4. Initialize a new Rust library for Swift with cargo-swift init

    main
    To create a new Rust library crate pre-configured with boilerplate code and examples for UniFFI, run cargo swift init. This sets up the foundation for a library that can be bridged to Swift.
    cargo swift init
  5. Save configuration values to Cargo.toml

    main

    To avoid manual editing, you can use the --save option with the cargo swift package command. This will automatically write the provided configuration values into your crate's Cargo.toml under the [package.metadata.swiftpackage] section.

    cargo swift package --save --platforms macos ios
  6. Match cargo-swift version with UniFFI version

    main

    Since cargo-swift does not automatically detect your project's UniFFI version, you must manually install the version of cargo-swift that corresponds to your uniffi-rs version. Use the following mapping:

    UniFFIcargo swift
    0.250.5
    0.260.6
    0.270.7
    0.280.8
    0.290.9
    0.300.10
    0.310.11
    0.31.10.11.1

    To install a specific version, use the @ syntax with the -f flag:

    cargo install cargo-swift@0.X -f
    # Replace 0.X with the desired cargo swift version
  7. Patching headers in static XCFrameworks

    main

    When creating an XCFramework from static libraries, xcodebuild often produces a lowercase headers directory. To comply with Apple conventions, cargo-swift performs a patching step:

    1. Removes the existing headers directory.
    2. Creates a new Headers directory.
    3. Creates a sub-directory named after the ffi_module_name inside Headers/.
    4. Copies the generated header files into this new structure.

    This is handled automatically by create_xcframework when LibType::Static is used.

  8. Determine the bundle layout for an Apple platform

    main

    Apple platforms use different framework bundle structures. You can check if a platform requires a versioned layout (e.g., Versions/A/... with symlinks) or a flat (shallow) layout using uses_versioned_bundle().

    • Versioned Layout: MacOS, MacCatalyst
    • Flat Layout: All other platforms (iOS, tvOS, visionOS, watchOS, and their simulators).
  9. Identify Apple platform-specific Info.plist requirements

    main

    When building frameworks for Apple platforms, cargo-swift uses ApplePlatform::info_plist() to retrieve the necessary PlatformInfoPlist fragments. These fragments ensure that the generated Info.plist contains the correct keys (like MinimumOSVersion or LSMinimumSystemVersion) and deployment target environment variables required for App Store validation.

    Supported platforms include:

    • IOS, IOSSimulator
    • MacOS, MacCatalyst
    • TvOS, TvOSSimulator
    • WatchOS, WatchOSSimulator
    • VisionOS, VisionOSSimulator
  10. How framework bundle layouts differ by platform

    main

    When generating dynamic libraries, cargo-swift creates .framework bundles using different directory structures based on the target ApplePlatform:

    iOS, tvOS, watchOS, and visionOS (Shallow Layout)

    Uses a flat structure where the binary and headers reside at the root:

    {framework_name}.framework/
    ├── Info.plist
    ├── {framework_name}     (the dylib)
    ├── Headers/
    └── Modules/

    macOS and Mac Catalyst (Versioned Layout)

    Requires a versioned structure where the actual content is stored in Versions/A/ and the root contains symlinks:

    {framework_name}.framework/
    ├── {framework_name}     -> Versions/Current/{framework_name}
    ├── Headers              -> Versions/Current/Headers
    ├── Modules              -> Versions/Current/Modules
    ├── Resources            -> Versions/Current/Resources
    └── Versions/
        ├── A/
        │   ├── {framework_name}
        │   ├── Headers/
        │   ├── Modules/
        │   └── Resources/Info.plist
        └── Current          -> A
  11. Understand how ToolchainTargets manages Rust targets

    main

    The ToolchainTargets struct manages the availability and installation status of Rust targets across both stable and nightly toolchains. It is used to determine if a build requires the nightly toolchain or the -Z build-std flag (used when a target is available in Rust but not installed on either stable or nightly).

    Key behaviors:

    • Nightly Fallback: If any requested architecture is not available on the stable toolchain, cargo-swift will use the nightly toolchain for the entire build to ensure compiler version consistency.
    • Build-Std Requirement: If a target is not available on either stable or nightly, it is flagged as needing -Z build-std.
  12. Configure cargo-swift

    main
    Currently, configuration for cargo-swift is only supported via command line arguments. Most default settings are sufficient for standard use cases. Persistent configuration via a config file is a planned feature (see CONFIG-DRAFT.md in the repository for details).