
如何在Java中调用Rust编写的库包?在这个例子中,我们将看到如何:
- 构建一个简单的 Rust 库,它公开一个 C API(巴拿马 FFI 可以链接到它)。
- 使用cbindgen来生成这个库中的C头文件。
- 用于jextract从头文件生成 java 绑定。
- 创建一个简单的 java 程序,通过绑定调用 rust 库。
步骤 1. 设置项目
$ mkdir rust-panama-helloworld
$ cd rust-panama-helloworld
$ cargo init --lib
步骤 2. 编写一个简单的 Rust 库
编辑src/lib.rs并将内容更改为:
#[no_mangle]
pub extern <font>"C"</font><font> fn hello_world() {
println!(</font><font>"Hello, world!"</font><font>);
}
</font>
#[no_mangle]需要该属性以确保函数在库中可见,并extern "C"用于确保函数具有正确的 ABI(特定平台的 C ABI)。
步骤 3. 添加所需的项目配置
进入Cargo.toml并添加以下内容:
[build-dependencies]
cbindgen = <font>"0.20.0"</font><font>
<p>[lib]
crate_type = [</font><font>"cdylib"</font><font>]
</font>
cbindgen 用于从 rust 源生成 C 头文件,该文件将被输入到巴拿马的jextract工具中以生成 java 绑定。
步骤 4. 创建一个调用 cbindgen 的构建脚本
build.rs在顶级目录中创建一个文件并添加以下内容:
extern crate cbindgen;
use std::env;
fn main() {
let crate_dir = env::<b>var</b>(<font>"CARGO_MANIFEST_DIR"</font><font>).unwrap();
cbindgen::Builder::<b>new</b>()
.with_crate(crate_dir)
.with_language(cbindgen::Language::C)
.generate()
.expect(</font><font>"Unable to generate bindings"</font><font>)
.write_to_file(</font><font>"lib.h"</font><font>);
}
</font>
这是一个简单的构建脚本,它调用 cbindgen 并将输出写入lib.h顶级目录中的文件。
步骤 5. 构建 Rust 库并生成 C 头文件
$ cargo build
这应该在target/debug的文件夹中创建该文件(lib)rust_panama_helloworld.(dll/so/dylib)。
构建还应调用cbindgen并生成lib.h顶级目录中的文件。该文件的内容应如下所示:
<a href="/query/searchAction.shtml?query=include"><b>include</b></a> <stdarg.h>
<a href="/query/searchAction.shtml?query=include"><b>include</b></a> <stdbool.h>
<a href="/query/searchAction.shtml?query=include"><b>include</b></a> <stdint.h>
<a href="/query/searchAction.shtml?query=include"><b>include</b></a> <stdlib.h>
<b>void</b> hello_world(<b>void</b>);
步骤 6. 确保panama jdk 在路径上
$ java --version
openjdk 17-panama 2021-09-14
OpenJDK Runtime Environment (build 17-panama+3-167)
OpenJDK 64-Bit Server VM (build 17-panama+3-167, mixed mode, sharing)
在撰写本文时,我正在使用http://jdk.java.net/panama/上提供的最新快照。
步骤 7. 使用 jextract 生成 java 绑定
$ jextract -d classes -t org.openjdk --include-function hello_world -l rust_panama_helloworld -- lib.h
在这个命令中:
- -d classes 指定生成的绑定的输出目录。
- -t org.openjdk 指定生成的类所在的 java 包。
- –include-function hello_world所以我们只包含hello_world我们在 rust 中定义的函数。
- -l rust_panama_helloworld使生成的绑定将rust_panama_helloworld自动加载库。
- – 是一个分隔符,用于指示要处理的头文件列表的开始。
- 最后lib.h是在步骤 5 中生成的头文件。
一个classes目录应创建包含由jextract产生了一些文件:
.
/classes
└───org
└───openjdk
constants$0.<b>class</b>
lib_h.<b>class</b>
RuntimeHelper$VarargsInvoker.<b>class</b>
RuntimeHelper.<b>class</b>
步骤 8. 创建一个调用我们的库的 java 程序
在顶级目录中创建一个Main.java文件并将以下内容放入其中:
<b>import</b> <b>static</b> org.openjdk.lib_h.*;
<b>public</b> <b>class</b> Main {
<b>public</b> <b>static</b> <b>void</b> main(String[] args) {
hello_world();
}
}
步骤 9. 运行 java 程序
$ java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED -Djava.library.path=./target/debug -cp classes Main.java
在这个命令中:
- –add-modules jdk.incubator.foreign将jdk.incubator.foreign模块添加到模块图中(默认情况下不解析孵化器模块)。
- –enable-native-access=ALL-UNNAMED 启用对未命名模块的本机访问,这是巴拿马 API 工作所必需的。
- -Djava.library.path=./target/debug将包含我们 rust 库的目录添加到库路径中,以便System.loadLibrary在运行时可以找到它。
- -cp classes 使用我们生成的 java 绑定类(jextract 的输出)指定类路径。
- Main.java 指定我们的主类,它将被动态编译,然后运行。
步骤 10. 观察输出
WARNING: Using incubator modules: jdk.incubator.foreign
warning: using incubating module(s): jdk.incubator.foreign
1 warning
Hello, world!

如果对软件测试、接口测试、自动化测试、持续集成、面试经验。感兴趣可以进到806549072,群内会有不定期的分享测试资料。还会有技术大牛,业内同行一起交流技术
版权声明:本文为m0_61655732原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。