#java #bindings-generator #bindgen

bin+lib uniffi-bindgen-java

uniffi rust 的 Java 绑定生成器

1 个不稳定版本

新功能 0.1.0 2024 年 8 月 15 日

#63FFI

Download history 157/week @ 2024-08-10

每月 157 次下载

MPL-2.0 许可证

170KB
3.5K SLoC

Java 2K SLoC // 0.1% comments Rust 1.5K SLoC // 0.1% comments

uniffi-bindgen-java

为 Java 生成 UniFFI 绑定。

已经存在官方 Kotlin 绑定,任何 JVM 语言(包括 Java)都可以使用。Java 特定的绑定尽可能使用 Java 原生类型以获得更直观的接口,例如,Java 绑定使用 CompletableFutures 而不是 kotlinx.coroutines

我们强烈建议您尽可能使用 UniFFI 的 proc-macro 定义 而不是 UDL。

需求

  • Java 20+:javacjar
  • 下载 Java Native Access JAR,并将其路径添加到您的 $CLASSPATH 环境变量中。

安装

MSRV 是 1.77.0

cargoinstall uniffi-bindgen-java --githttps://github.com/IronCoreLabs/uniffi-bindgen-java

用法

uniffi-bindgen-java --help
Java scaffolding and bindings generator for Rust

Usage:

Commands:
  generate     Generate Java bindings
  scaffolding  Generate Rust scaffolding code
  print-repr   Print a debug representation of the interface from a dynamic library

Options:
  -h, --help     Print help
  -V, --version  Print version

生成绑定

uniffi-bindgen-java generate --help
Generate Java bindings

Usage:

Arguments:
  <SOURCE>  Path to the UDL file, or cdylib if `library-mode` is specified

Options:
  -o, --out-dir <OUT_DIR>    Directory in which to write generated files. Default is same folder as .udl file
  -n, --no-format            Do not try to format the generated bindings
  -c, --config <CONFIG>      Path to optional uniffi config file. This config is merged with the `uniffi.toml` config present in each crate, with its values taking precedence
  --lib-file <LIB_FILE>      Extract proc-macro metadata from a native lib (cdylib or staticlib) for this crate
  --library                  Pass in a cdylib path rather than a UDL file
  --crate <CRATE_NAME>       When `--library` is passed, only generate bindings for one crate. When `--library` is not passed, use this as the crate name instead of attempting to locate and parse Cargo.toml

例如

> git clone https://github.com/mozilla/uniffi-rs.git
> cd uniffi-rs/examples/arithmetic-proc-macro
> cargo b --release
> uniffi-bindgen-java generate --out-dir ./generated-java --library ../../target/release/libarithmeticpm.so
> ll generated-java/uniffi/arithmeticpm/
total 216
-rw-r--r-- 1 user users  295 Jul 24 13:02 ArithmeticExceptionErrorHandler.java
-rw-r--r-- 1 user users  731 Jul 24 13:02 ArithmeticException.java
-rw-r--r-- 1 user users 3126 Jul 24 13:02 Arithmeticpm.java
-rw-r--r-- 1 user users  512 Jul 24 13:02 AutoCloseableHelper.java
-rw-r--r-- 1 user users  584 Jul 24 13:02 FfiConverterBoolean.java
...
> cat generated-java/uniffi/arithmeticpm/Arithmeticpm.java
package uniffi.arithmeticpm;


import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class Arithmeticpm {
  public static Long add(Long a, Long b) throws ArithmeticException {
            try {
...

生成框架

uniffi-bindgen-java scaffolding --help
Generate Rust scaffolding code

Usage:

Arguments:
  <UDL_FILE>  Path to the UDL file

Options:
  -o, --out-dir <OUT_DIR>  Directory in which to write generated files. Default is same folder as .udl file
  -n, --no-format          Do not try to format the generated bindings

打印调试表示

uniffi-bindgen-java print-repr --help
Print a debug representation of the interface from a dynamic library

Usage:

Arguments:
  <PATH>  Path to the library file (.so, .dll, .dylib, or .a)

集成绑定

生成后,您将得到一个包含 Java 文件的 --out-dir 目录。使用您选择的构建工具将这些文件打包成一个 .jar 文件,然后可以在任何具有可用 JNA 依赖项的 Java 项目中导入和使用结果。

Rust 库中的任何顶级函数都将作为以 crate 命名的一个类的静态方法。

配置

可以使用 uniffi.toml 配置文件配置生成的 Java。

配置名称 默认值 说明
package_name uniffi Java包名 - 即在生成文件顶部package语句中使用的值。
cdylib_name uniffi_{命名空间} 包含FFI实现的编译好的Rust库的名称(使用generate --library时不需要)
generate_immutable_records false 是否生成具有不可变字段的记录(使用record代替class)。
custom_types 一个映射,用于控制如何将自定义类型暴露给Java。请参阅UniFFI手册中自定义类型的部分
external_packages 一个映射,用于指定外部crates的包。键是Rust crate名称,值是用于引用该crate中类型的Java包。请参阅手册中外部类型的部分
android false 用于打开Android特定优化(警告:尚未经过良好测试)
android_cleaner android 使用android.system.SystemCleaner代替java.lang.ref.Cleaner。在两种情况下,回退都是JNA附带的内容。

示例

自定义类型

[bindings.java]
package_name = "customtypes"

[bindings.java.custom_types.Url]
# Name of the type in the Java code
type_name = "URL"
# Classes that need to be imported
imports = ["java.net.URI", "java.net.URL"]
# Functions to convert between strings and URLs
into_custom = "new URI({}).toURL()"
from_custom = "{}.toString()"

外部类型

[bindings.java.external_packages]
# This specifies that external types from the crate `rust-crate-name` will be referred by by the package `"java.package.name`.
rust-crate-name = "java.package.name"

注意

  • CompletableFutures中的失败将导致它们completeExceptionally。导致失败的错误可以通过e.getCause()进行检查。当在Java中实现异步Rust trait时,您需要使用completeExceptionally而不是抛出异常。请参阅TestFixtureFutures.java以查看具有错误示例的trait实现。
  • Java中默认所有原始类型都是有符号的。Rust可以在被告知时正确地将Java中的有符号原始值解释为无符号。调用Uniffi函数的调用者需要在进行比较(compareUnsigned)或打印实际无符号值时注意这一点,以避免在这方面的陷阱。

不支持的功能

  • Java不支持默认值,因此uniffi结构体、方法和函数默认值在Java代码中不存在。注意:可以通过生成构建器模式来支持结构体上的默认值,这是一个合理的案例。欢迎提交PR。
  • 输出格式化目前不受支持,因为没有找到独立的命令行Java格式化程序。欢迎提交PR以启用该功能,基础设施已就绪。

测试

我们直接从Uniffi拉取固定的示例并使用生成的绑定运行Java测试。运行cargo t以运行所有测试。

请注意,如果您需要为测试添加额外的toml条目,您可以将一个uniffi-extras.toml放在测试的兄弟节点中,它将被读取,作为示例的基uniffi.toml。请参阅CustomTypes以获取示例。在uniffi-extras.toml中的设置适用于所有命名空间。

版本控制

uniffi-bindgen-javauniffi-rs 的版本是分开管理的。我们遵循 Cargo SemVer 规则,因此当它们的最高非零主版本、次版本或补丁版本相同时,版本是兼容的。任何导致生成代码的消费者需要做出更改的生成器修改都被认为是破坏性的。

uniffi-bindgen-java 目前处于不稳定状态,由 IronCore Labs 开发,以支持 ironcore-alloy 所需的功能。当前主版本为 0,大多数更改可能会提升次版本号。

依赖项

~11MB
~190K SLoC