mozilla / uniffi-rs

a multi-language bindings generator for rust
https://mozilla.github.io/uniffi-rs/
Mozilla Public License 2.0
2.87k stars 232 forks source link

Combine generated .swift and headers file? #2257

Open praveenperera opened 1 month ago

praveenperera commented 1 month ago

I have a project called cove that is using uniffi, I had it set up as a single crate and the build script calling cargo run --bin uniffi-bindgen generate --library ./target/debug/libcove.dylib --language swift --out-dir ./bindings

This outputs Cove.swift, modulemap and headers file, which I then use to make a xcframework.

I wanted to see if I could make new functionality in a crate, so I made one called cove_nfc all using proc macros and then in cove/src/lib.rs I have

uniffi::setup_scaffolding!();
cove_nfc::uniffi_reexport_scaffolding!();

That all seems to work fine, but when I run the uniffi-bindgen it now makes separate swift files, headers and module maps for cove and cove_nfc.

Is it possible to just combine them?

mhammond commented 1 month ago

The usual way to do this is to have both your crates in the same library - we don't support any multi-lib scenarios.

praveenperera commented 1 month ago

Cove is my main library and I was hoping to split off other functionality into other crates, that Cove could then depend one. Is that not possible to do that and still only have one set of outputs (shared dylib, .swift and headers)?

Would it make more sense to still add the proc macros in a crate for the structs and enums, but do all the [#uniffi::exports] in my main crate?

Would that accomplish what I want?

I tried to do that but got this error:

unknown throw type: Some(External { module_path: "cove_nfc", name: "NfcReaderError", namespace: "cove_nfc", kind: DataClass, tagged: false })
mhammond commented 1 month ago

Cove is my main library and I was hoping to split off other functionality into other crates, that Cove could then depend one.

That's possible, but it happens at build-time. Each of these other crates would end up building its own dylib which includes Cove. You don't need multiple dylibs for uniffi projects because Rust doesn't support them.

praveenperera commented 1 month ago

That's possible, but it happens at build-time. Each of these other crates would end up building its own dylib which includes Cove. You don't need multiple dylibs for uniffi projects because Rust doesn't support them.

I see thank you, I think I'll close this issue then, because when I try to do that I'm getting this issue now:

unknown throw type: Some(External { module_path: "cove_nfc", name: "NfcReaderError", namespace: "cove_nfc", kind: DataClass, tagged: false })

Same as #2225

I'll try to explore a bit more about why that is an maybe make a new issue. I'm wondering if its because of the weird way I have the crates set up now for ease of use.

My folder structure is

rust
  cove (non workspace crate)
    src/lib/
    Cargo.toml
    Cargo.lock
  cove_crates (different workspace crate)
    cove_nfc/ (crate i'm trying to import)
      src/lib/
    Cargo.toml
    Cargo.lock

It's non standard, and probably messing with how uniffi searches for deps.

Alphapage commented 1 month ago

As far as I tried, it seems to only happen when using

#[derive(uniffi::Error, Debug)]
pub enum MyError {}

So you can use multiple libraries, but all errors must be in the main lib. Is it a limitation ? Or a bug ?

praveenperera commented 1 month ago

@Alphapage i haven’t had a chance to try it with a more normal setup but if it only happens with errors it sounds like it could be a bug?

Do you have a repo that you tested this on?

Alphapage commented 1 month ago

Sorry, but I don't have a repo to share. The only thing I can tell is as soon as I removed all #[derive(uniffi::Error, Debug)] from my dependent library and put it back to main library, then it started working like a charm. So, it seems uniffi::Error or more globally enums aren't supported in a child library :-(

praveenperera commented 1 month ago

When one of us gets a chance, lets make a minimal repo and make a new issue, cc: @mhammond ^

mhammond commented 1 month ago

Probably #2265 - we don't yet support errors defined in another crate.

praveenperera commented 1 month ago

@mhammond I'm going to re-open this because I tried doing this with a more traditional crate structure but I'm still not sure the best way to use other crates in my main crate.

My main crate / library is cove: https://github.com/bitcoinppl/cove

And I am trying to use this crate in it, that crate has uniffi under a feature.

When I compile the rust and run uniffi-bindgen it all works fine. But the iOS app won't compile. That's because the glue code for pubport is in its own files pubport.swift, pubporFFI.h and pubportFFI.modulemap

I'm not sure what the best way to combine these with my existing cove.swift header and module map files is.