Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating SPM packages from swift-bridge crates is error-prone #315

Open
colinmarc opened this issue Feb 2, 2025 · 1 comment
Open

Creating SPM packages from swift-bridge crates is error-prone #315

colinmarc opened this issue Feb 2, 2025 · 1 comment

Comments

@colinmarc
Copy link

colinmarc commented Feb 2, 2025

Possible duplicate of #280.

Swift-bridge basically generates four files presently:

  • A "stdlib" C header (SwiftBridgeCore.h)
  • A crate-specific C header for the generated rust code (my-cool-crate.h)
  • A "stdlib" Swift file (SwiftBridgeCore.swift)
  • A carte-specific Swift file (my-cool-crate.swift).

With the following implicit dependencies between the files:

  • my-cool-crate.h uses names from SwiftBridgeCore.h
  • SwiftBridgeCore.swift uses names from SwiftBridgeCore.h
  • my-cool-crate.swift uses names from SwiftBridgeCore.swift, SwiftBridgeCore.h, and my-cool-crate.h.

In contrast to xcframeworks, which can mix C headers and Swift code, Swift Package Manager (SPM) requires you to separate them into different targets, with explicit imports. That means that the static lib + C headers generated by swift-bridge have to be a different target from the Swift code, and imports (using the target names from Package.swift) need to be added to the files to make it all work.

(Just to underline this last point: I need to name the Package.swift target wrapping the right code, and if I name it FooBar, then import FooBar needs to be added to the beginning of the generated code, which is a leaky abstraction. For an example of this working, see #307)

Additionally, SPM is pretty picky about which files go where. Source files (such as the generated C headers) have to be "below" Package.swift in the directory hierarchy. This means that the rust build.rs has to be told where to spit out the generated files, or they have to be copied into place as part of the swift build.

Finally, SPM needs extra instructions to the linker to be added to Package.swift telling it where to find the static lib file (libfoo_crate.a). This can escape the package root, but it's another path that needs to be correct.

All of these issues mean that there's lots to get wrong.

Suggestion: produce a complete, working SPM package with cargo build

How great would it be if we just dumped a full SPM package source tree into target or wherever the user specifies with cargo's upcoming --artifact-dir build flag?

Swift packages are very versatile - unlike XCFrameworks, they can be used in other SPM packages on all platforms (including by path), but they can also be added to an Xcode project without any hassle.

The idea would be to generate a Package.swift with a total of four targets for a crate my-cool-crate:

  • RustSwiftBridge, a binary target with the "stdlib" C header and rust
  • RustMyCoolCrate, a binary target with the generated C headers and generated rust
  • SwiftBridge, a library with the swift "stdlib" code, depending on RustSwiftBridge
  • MyCoolCrate, a library with the generated swift code, dependending on the three other targets

Because we control the generation of Package.swift, we can get all the fiddly paths correct in the generation phase, as well as add the necessary imports to each file.

A user could import this Package.swift from another Swift package:

dependencies: [
    .package(url: "../crates/my-cool-crate/target/debug/MyCoolCrate")
    // ... other dependencies
]

Or they could add it directly to Xcode, also by path.

@colinmarc
Copy link
Author

colinmarc commented Feb 2, 2025

It seems like there are bits and pieces that could be adapted for this already in the repo (some of which I didn't see before). For example, swift_bridge_build::create_package wraps an xcframework in an SPM package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant