antoniusnaumann / cargo-swift

A cargo plugin to easily build Swift packages from Rust code
https://crates.io/crates/cargo-swift
Apache License 2.0
172 stars 22 forks source link

Add support for proc-macro #26

Closed martinmose closed 10 months ago

martinmose commented 11 months ago

Hello,

Firstly, a heartfelt thank you for the incredible work you've done!

I'd like to express my interest in proc-macro support, eliminating the need for a .udl file. I believe this enhancement could significantly simplify the initial learning curve for those venturing into a shared codebase in Rust.

I recognize that this is a substantial request, and a "spoiled" one, but I hope you bear with me.

antoniusnaumann commented 11 months ago

The underlying library (UniFFI by Mozilla, which does the heavy lifting here) has proc-macros as described in the UniFFI docs: https://mozilla.github.io/uniffi-rs/proc_macro/index.html

It should work if you have a lib.udl file with an empty namespace.

Alternatively, as per the UniFFI docs, putting uniffi::setup_scaffolding!(); instead of uniffi::include_scaffolding!("lib"); at the beginning of your lib.rs file allows you to delete the lib.udl file altogether (and I think you can delete the generated build.rs file in this case as well)

I am currently on vacation, but I'll check soon what should be modified in cargo swift to make this work more elegantly. (Probably just adding a template for macro-only mode). Keeping this issue open until I checked the rough edges when using UniFFI proc-macros with cargo swift

antoniusnaumann commented 11 months ago

@martinmose I added support for using UniFFI proc macros in v0.5.0-alpha01.

If you want to test it, you can do the following:

Install the current alpha:

cargo install cargo-swift --force --version 0.5.0-alpha01

Init a new project with cargo swift init --plain and write code with proc macros as described in the UniFFI docs. (you should keep the .udl file and the empty namespace it contains as well as the uniffi::include_scaffolding!("lib"); call in lib.rs)

Calling cargo swift package will now work with proc macros.

Let me know if you encounter any bugs Happy building :)

martinmose commented 11 months ago

@antoniusnaumann Awesome! Thanks a lot. I will give it a go tonight 💪.

Regarding the uniffi::include_scaffolding!("lib");

I have this in my lib.rs: uniffi::setup_scaffolding!();

And this in the bin:

fn main() {
    uniffi::uniffi_bindgen_main()
}

It could be cool if I could test it out with my existing project where Im using procs marcros ⭐.

antoniusnaumann commented 11 months ago

@antoniusnaumann Awesome! Thanks a lot. I will give it a go tonight 💪.

Regarding the uniffi::include_scaffolding!("lib");

I have this in my lib.rs: uniffi::setup_scaffolding!();

And this in the bin:

fn main() {
    uniffi::uniffi_bindgen_main()
}

It could be cool if I could test it out with my existing project where Im using procs marcros ⭐.

For cargo swift, you don't need the bin as cargo swift already handles this. (If you still need this for generating bindings to other languages using the UniFFI CLI, you can keep it of course)

Currently, cargo swift assumes that there is a lib.udl file in the src/ directory and will fail if it is not present. I will lift this requirement in future versions. Otherwise, cargo swift should work fine in your existing project.

martinmose commented 11 months ago

I require the bin for Android 😅.

However, fantastic work! You're doing great, and it works flawlessly! I can finally eliminate all the convoluted code I had to write to generate the Swift Package manually. Thanks a million! 🤩

antoniusnaumann commented 11 months ago

The 0.5.0-alpha02 release should support deleting the .udl file completely when setup_scaffolding!() is used as soon as a new UniFFI update will be released (uniffi_bindgen, which cargo swift depends on, currently (v0.24.3) expects exactly one udl file - this requirement is already lifted on UniFFI's main branch)

To test this out, you can install the latest cargo swift version from git, this one depends on the UniFFI git repository instead of the latest published versions:

cargo install -f --git https://github.com/antoniusnaumann/cargo-swift.git --rev 00e24b0142afaebbad17b9cabeacf7614defaf4f

(this might contain bugs of course, as it depends on the UniFFI main branch)

antoniusnaumann commented 11 months ago

Keeping this issue open - blocked until UniFFI update is released by Mozilla

antoniusnaumann commented 10 months ago

Projects that only use UniFFI proc macros can now be packaged without a UDL file.

@martinmose Could you try this out in the 0.5.0-beta01 version?

cargo install cargo-swift --force --version 0.5.0-beta01

(make sure that your project depends on uniffi 0.25.0)

martinmose commented 10 months ago

Hi,

First and foremost, great job – it's working now! 🤩

However, I have a few observations:

I noticed the header file (.h) is now named using snake_case. Wasn't it supposed to be named based on the --name option? I see the same naming pattern with the .swift file.

I observed that the static lib-type is now the default. I found I can specify the desired library type using --lib-type dynamic if I want to generate a .dylib.

I encountered a few "errors" initially.

I'm pretty sure it is unrelated and I believe this might be because I restructured my project. My root Cargo.toml file now contains this at the top of the file:

[workspace]
members = [
    "core",
    "service",
    "playground"
]

When I used the --name parameter, I got this "error":

Failed due to the following error:
Package name can only be specified when building a single crate!

But if I just removed the --name parameter I could just specify the name when promoted.

However, after that I ran into another "error":

Failed due to the following error:
No supported library type was specified in Cargo.toml!

 Supported types are:
    - staticlib
    - cdylibNo supported library type was specified in Cargo.toml!

 Supported types are:
    - staticlib
    - cdylibNo library tag defined in Cargo.toml!%   

The only "project" I want to uniffi to export is my root project. The other crates are just some dependencies to my root project. If that make sense?

antoniusnaumann commented 10 months ago

I'm pretty sure it is unrelated and I believe this might be because I restructured my project. My root Cargo.toml file now contains this at the top of the file:

[workspace]
members = [
    "core",
    "service",
    "playground"
]

When I used the --name parameter, I got this "error":

Failed due to the following error:
Package name can only be specified when building a single crate!

But if I just removed the --name parameter I could just specify the name when promoted.

Yeah, when invoked in a workspace, the default behavior is now as of #7. This builds all crates that depend on UniFFI as package. Consequently, the --name parameter is not allowed when invoking in a workspace. However, I see that this behavior is not desirable (especially in your case where you only want to build the root package), I will open an issue about that and fix it (= revert the behavior to just building the crate in the current directory).

antoniusnaumann commented 10 months ago

I changed the behavior of cargo swift to only run for the package that is in the current working directory. This should fix the issue you encountered. @martinmose thanks for pointing this out!

cargo install cargo-swift --force --version 0.5.0-beta02
martinmose commented 10 months ago

@antoniusnaumann Thanks a lot! It now just works 🥳