在Java中使用panama FFI呼叫Rust庫
如何在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 "C" fn hello_world() { println!("Hello, world!"); } |
#[no_mangle]需要該屬性以確保函式在庫中可見,並extern "C"用於確保函式具有正確的 ABI(特定平臺的 C ABI)。
步驟 3. 新增所需的專案配置
進入Cargo.toml並新增以下內容:
[build-dependencies] cbindgen = "0.20.0" <p class="indent">[lib] crate_type = ["cdylib"] |
cbindgen用於從 rust 源生成 C 標頭檔案,該檔案將被輸入到巴拿馬的jextract工具中以生成 java 繫結。
步驟 4. 建立一個呼叫 cbindgen 的構建指令碼
build.rs在頂級目錄中建立一個檔案並新增以下內容:
extern crate cbindgen; use std::env; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); cbindgen::Builder::new() .with_crate(crate_dir) .with_language(cbindgen::Language::C) .generate() .expect("Unable to generate bindings") .write_to_file("lib.h"); } |
這是一個簡單的構建指令碼,它呼叫 cbindgen 並將輸出寫入lib.h頂級目錄中的檔案。
步驟 5. 構建 Rust 庫並生成 C 標頭檔案
$ cargo build
這應該在target/debug的資料夾中建立該檔案(lib)rust_panama_helloworld.(dll/so/dylib)。
構建還應呼叫cbindgen並生成lib.h頂級目錄中的檔案。該檔案的內容應如下所示:
include <stdarg.h> include <stdbool.h> include <stdint.h> include <stdlib.h> void hello_world(void); |
步驟 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.class lib_h.class RuntimeHelper$VarargsInvoker.class RuntimeHelper.class |
步驟 8. 建立一個呼叫我們的庫的 java 程式
在頂級目錄中建立一個Main.java檔案並將以下內容放入其中:
import static org.openjdk.lib_h.*; public class Main { public static void 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! |
相關文章
- Java的Panama專案與JNI以及外部函式介面FFIJava函式
- 騰訊 IVWEB 團隊:通過 ffi 在 Node.js 中呼叫動態連結庫 (.so/.dll 檔案)WebNode.js
- PHP通過FFI呼叫CJieba分詞PHPJieba分詞
- PHP透過FFI呼叫CJieba分詞PHPJieba分詞
- lua的FFI庫--alien
- PHP FFI呼叫go,居然比go還快PHPGo
- 在Java中呼叫Groovy方法的又一種方法:使用介面Java
- 在python程式中呼叫java程式碼PythonJava
- Windows 下 c++ 呼叫 Rust 庫的例子WindowsC++Rust
- node-ffi使用指南
- 在Java中實現遠端方法呼叫(轉)Java
- PHP中呼叫JAVA,PHPJava
- 在 Java 中如何使用 transientJava
- REST 在 Java 中的使用RESTJava
- 在iOS中呼叫HTMLiOSHTML
- 使用call在sqlplus中呼叫procedure和funtion!SQL
- java中呼叫npm模組JavaNPM
- 如何在 Deno 應用程式中呼叫 Rust 函式Rust函式
- 在java中使用mysql資料庫JavaMySql資料庫
- Disruptor-rs:Rust中Disruptor庫Rust
- java呼叫c++動態庫之jni呼叫JavaC++
- 翻譯|在Rust中怎樣panicRust
- java動態呼叫c++庫JavaC++
- validator庫在gin中的使用
- java 中對物件的呼叫Java物件
- java中呼叫groovy指令碼Java指令碼
- 在Java中this關鍵字的使用Java
- 使用PyO3從Python呼叫 Rust:加速PythonPythonRust
- 使用 Java實現mTLS呼叫JavaTLS
- Android 使用js呼叫JavaAndroidJSJava
- 在DWR中呼叫Http Servlet 物件HTTPServlet物件
- 在處理鏈中呼叫APD
- 在Watir中呼叫JavaScript指令碼JavaScript指令碼
- 在c#中呼叫confirmC#
- CXX庫提供Rust和C+ 之間的安全相互呼叫Rust
- PHP 7.4 前瞻:FFIPHP
- Lua FFI 實戰
- 【譯】Arc 在 Rust 中是如何工作的Rust