Comments (18)
Awesome. I'll be looking through the code of this package to get a better understanding of how this all works. After that I can have another attempt at converting to a Swift package.
from swift-bridge.
Hey!
If I'm understanding, you're saying that you'd like to be able to have the Rust side of things get packaged up into a Swift package that you can then import from your Swift project? Or are you saying something else?
I'll read up on Swift packages since I don't know much about them at the moment.
Would using Swift packages be strictly better to what we're currently doing, or are there any downsides?
Also, if you could explain your Swift+Rust use case that would be great - just so that I can better understand when and how Swift packages are typically used (I'm new to Swift).
Thanks for opening this issue!
from swift-bridge.
I do think that compiling to a Swift package could be a huge plus. Right now we can compile Swift code using swiftc
and linking the rust library. This is great for cli's. However, if we could either compile the Rust code to a Swift library, or compile the Swift project that includes the Rust code to a Swift library, I think this could be a huge benefit.
If our Swift code is in package form, we can import it in every Swift project (as long as we have compiled our rust code to the right targets, of course).
Swift packages are similar to Rust crates, you can create one with mkdir myPackage && cd $_ && swift package init --type library
(Swift Package Manager docs).
Other projects or packages can then depend on the package by specifying the package in the Package.swift
file (see above for example of importing a package named HelloSwift
in the package named swift
).
I guess this would be similar to any other Swift package that wraps a C api (Can't remember a good, simple example, but here is one for LLVM: https://github.com/llvm-swift/llvmswift).
Really love this project, if you need any help, I would love to contribute where I can.
EDIT: I'll also do some research myself and will let you know if I get some working prototype
from swift-bridge.
Nice! Just let me know whenever you have any questions and I'll try to add answers to the currently empty internal design chapter.
from swift-bridge.
Aha! Seems like all I was missing was a modulemap file. I'll clean up what I have now and try it from scratch again.
I'll update you soon
from swift-bridge.
Ok, here's what I have. Source code on this branch.
1. Rust
I have a Rust project with these functions:
fn print_hello_rust() {
println!("Hello from Rust!");
}
fn is_from_rust() -> bool {
true
}
fn get_hello_rust() -> String {
String::from("Hello Rust!")
}
Build the project like you would do usually with the build.rs file specified in the book.
2. XCFramework
The next step is to make the XCFramework.
Framework
├── include
│ ├── SwiftBridgeCore.h
│ ├── module.modulemap
│ └── rust.h
├── ios
│ └── librust.a
├── macos
│ └── librust.a
└── simulator
└── librust.a
We have a folder for each target we build for our rust project and copied both header files as well.
We can then build the XCFramework
xcodebuild -create-xcframework \
-library simulator/librust.a \
-headers include \
-library ios/librust.a \
-headers include \
-library macos/librust.a \
-headers include \
-output rust.xcframework
The order of the targets is important
Note: we could also build the framework without this command I think, as it is just a folder containing the different targets and a .plist
file
3. Swift package
Now, we build the swift package that incorporates the XCFramework.
We copy the .xcframework
file from the previous step to the root of this folder and add it as a binaryTarget
to our Package.swift
as well as include it as a dependency.
let package = Package(
name: "package",
products: [
.library(
name: "package",
targets: ["package"]),
],
dependencies: [
],
targets: [
.binaryTarget(
name: "Rust",
path: "rust.xcframework"
),
.target(
name: "package",
dependencies: ["Rust"]),
]
)
Then, we copy the generated swift files to the Sources/{package_name}
folder. In the swift file containing the functions, we make the functions public
and add import {XCFramework name}
(in this case import Rust
).
Now, we should also make the methods in SwiftBridgeCore.swift
public so we can call get_hello_rust().toString()
in this example to convert a RustString
to a String
in swift, for example.
4. Testing
After the previous steps, we now have a Swift package that can be used in any project targeting MacOs or iOS (we can of course target other Apple devices as well if we build those targets).
- We can add our package to an executable package as a dependency (here our package is just called "package"), then import it in our swift files and call our functions.
- And we can add it to an iOS app. And use it in the same way.
- To add a package in iOS in Xcode, click on the app name. General > Framework, Libraries and Embedded Content
Tested on an executable on MacOS and on the simulator for iOS, and a physical device.
Next steps
I can add a chapter to the book explaining the whole process in detail (basically the above, but a little more "cleaned up"). Let me know if you have any comments on the above.
Next would be generating a Swift package with the build file? I think you know best on how we should implement this into swift-bridge-build.
from swift-bridge.
Hey! just want to say thankyou so much for putting this together. Packaging my code as a swift package is way cleaner for my use case, and I appreciate the effort making it easy! Lots of gratitude for swift-bridge and this PR!
from swift-bridge.
Alright I read up on Swift packages on modules and have a basic understanding.
It seems like if I had to find the closest Rust ecosystem version of them..:
Swift Package == Cargo crate
Swift Module == Rust module
I know they aren't the same.. I'm just going for a rough understanding of what these Swift code organization tools are.
Ok so I'd sum up my current thoughts as:
- I don't yet understand what your end goal is and would love an explanation / some context around how you're using Swift+Rust so that I can better understand why you want to be able to generate a Swift package.
from swift-bridge.
So far I've had no luck, my knowledge of C and headers is quite limited, though.
So far I have found the following:
- LNPopupController: This package exposes a c api as a package called
LNPopupController-ObjC
and then uses that package in another package to "refine" it to Swift (LNPopupController
, defined in the folderLNPopupControllerRefinements
) - MyDependencySample: Here, the static library is distributed as an xcframework (difference between Swift package and xcframework)
from swift-bridge.
Thanks the gist and for all of the links. I've read through them and they were helpful as I start to get familiar with Swift packages / modules / etc.
Awesome work and research so far..
Really love this project, if you need any help, I would love to contribute where I can.
I'd love for you to contribute! Awesome, going forwards I'll start creating more issues and you can get involved wherever you like. Figuring out this Swift Package stuff might be a great place to start.
Alright.. I did some more reading and thinking and here's where I'm at.
-
We want people to be able to expose their
Swift+Rust
libraries as Swift Packages, Cocoapods, Carthage "packages" (not sure what they're really called), or any format that they want. -
A good starting point would be to add documentation on how to take the current output of
swift-bridge-build
and turn it into a package yourself.- This will teach us about how to create packages and how they should be shaped. For example, right now we emit everything into the global module so everything has access to the
SwiftBridgeCore.swift
file that we generate. So we'd need to figure out how leveragingSwiftBridgeCore
looks in a package world.. Or if it even still makes sense in a package world.
- This will teach us about how to create packages and how they should be shaped. For example, right now we emit everything into the global module so everything has access to the
-
Then in the future we might decide to have
swift-bridge-build
know about some of these target formats so that it can emit a package for you based on some configuration values. Or we might decide that that is out of scope for the library. Who knows.. needs more thinking..
So, here's a potential path forwards (which I think you've already made progress on in your gist.)
-
Write a book chapter on how to take the Swift and C headers that
swift-bridge-build
currently outputs and bundle them up into a Swift package. -
Open a pull request with wherever you get stuck (i.e. I think you were stuck on linking in the Rust library).
-
I'm comfortable with linking, so I can try to add a commit to the PR that adds linking related stuff to the chapter to finish up that piece (unless you end up figuring it out beforehand of course).
-
We clean up the PR and merge it. Now people have instructions on how to manually create their own Swift package. Then.. in the future.. we can think through whether or not we want
swift-bridge-build
to be able to automatically output a package (perhaps as a flag.. or at the default behavior.. who knows).
On the flip side.. we'll also want to eventually explore how to expose Swift + Rust
code as a Cargo crate.. (first as documentation.. then later explore having swift-bridge-build
emit a crate.. But that isn't important for this issue. Just jotting it down so we remember for the future.
from swift-bridge.
Ok, I have started looking at the internals of the project. I just wanted to finish a few of my own projects first before I tackled this.
So if I understand correctly, the swift-bridge-build
crate generates the .h
and .swift
files found in the generated
folder.
With swiftc
we link those files and the .a
file generated by cargo to the compiled swift program. So, if I figure out how to link all of those to an XCFramework, we have a standalone Swift package. I've been doing some research on XCFrameworks and will continue doing that now.
from swift-bridge.
Awesome!!
I'm not familiar with XCFramework but in general that all sounds about right.
from swift-bridge.
So far, I have packaged a system library and a c source file into a Swift package. I've had no luck with including a static library, though.
If you have any ideas on including the rust library, let me know, because so far I've had no luck.
from swift-bridge.
I think this might walk you through the entire process of going from Rust code to Swift package -> https://betterprogramming.pub/from-rust-to-swift-df9bde59b7cd
Let me know if that helps?
from swift-bridge.
A quote from Apple's documentation https://developer.apple.com/documentation/swift_packages/distributing_binary_frameworks_as_swift_packages :
In addition, binary dependencies are only available for Apple platforms, which limits the audience for your Swift package.
At the very least I think we'll want our own documentation to make it very clear to people that if they're creating a Swift package it can only be used on Apple hardware.
Which I'd imagine that the vast majority of users will be just fine with.
And we'll still support other output formats for people that aren't targeting Apple hardware (such as what we have right now with just spitting out files).
Not important right now.. Just dropping it here for us to keep in mind as we think through this stuff.
from swift-bridge.
I think this might walk you through the entire process of going from Rust code to Swift package -> https://betterprogramming.pub/from-rust-to-swift-df9bde59b7cd
Judging by the linked repo, I’m almost there with linking an XCFramework to Swift.
A quote from Apple's documentation
I’ve come across that as well, so unfortunately this approach will indeed not work for non-Apple devices. I haven’t come across any other solutions to this. I guess we will have to wait until some cross-platform solution comes around.
from swift-bridge.
Awesome work!
Adding a chapter to the book sounds great. My main feedback would be to call the crate something other than rust
(such as my-rust-lib
and call the package something other than package
(such as my-rust-package
) so that people can more easily keep track of what these artifacts are.
In terms of generating a package from programatically.. let's create a new issue for that. But yeah I'm happy to help figure out a good starting point for that. Thanks for making so much progress already!
from swift-bridge.
Closed by #30
from swift-bridge.
Related Issues (20)
- #[swift_bridge::bridge] macro forces module to be private HOT 3
- warning: `extern` block uses type `RustString`, which is not FFI-safe HOT 4
- Book update: Xcode 15 (at least) requires a bridge in order to import into swift
- Can't seem to return refs of custom types HOT 11
- Cannot use two `#[swift_bridge(..)]` attributes on the same function
- Already_declared causes swift generation to never declare Class HOT 1
- Result returns translating incorrectly? HOT 3
- Is &Vec<T> supported? HOT 2
- Cannot for the life of me get Xcode + Cargo to work HOT 2
- Unable to bridge function that receives &str and returns result HOT 1
- Support bridging `Option<SwiftClass>` in `extern "Rust"` function
- Support `#[swift_bridge(Sendable)]` to implement `Rust Send+Sync` for `Swift Sendable` types HOT 1
- ffi struct produces warnings on Rust 1.79.0 or +nightly HOT 5
- not sure my use case would work HOT 4
- Compile swift-library for iOS HOT 3
- Multi-platform compilation example HOT 1
- SPM setup for rust library
- [feature request] export default trait functions in a swift_bridge module? HOT 2
- #[swift_bridge(already_declared)] fails when wrapping an enum in Optional HOT 1
- Suggestions for handling Arc<String> associated with enum HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swift-bridge.