gpt4 book ai didi

java - 从 Java 调用 Rust

转载 作者:IT老高 更新时间:2023-10-28 21:08:58 44 4
gpt4 key购买 nike

我正在使用 Rust 1.0 beta,并且能够创建一个小示例,用于从 Java 调用用 Rust 编写的函数。我只是使用 rustc 在 mylib.rs 中编译了以下 Rust 代码,它在 Windows 上生成了一个 mylib.dll:

#![crate_type = "dylib"]
use std::any::Any;

#[no_mangle]
pub extern fn Java_tests_Test_hello(env: *const Any, jclass: *const Any) {
println!("hello from rust");
}

#[no_mangle]
pub extern fn Java_tests_Test_sum(env: *const Any, jclass: *const Any, a: i32, b: i32) -> i32 {
return a + b;
}

然后我可以从 Java 类 tests.Test 中调用这些函数:

package tests;

import java.io.File;

public class Test {

public static native void hello();

public static native int sum(int a, int b);

public static void main(String[] args) {
File f = new File("mylib.dll");
System.load(f.getAbsolutePath());
Test.hello();
System.out.println(Test.sum(20, 22));
}
}

运行 Java 主程序会打印出预期的结果:

hello from rust
42

在 Rust 方法中,我将 env 声明为指向 Any 类型的指针,但实际上它是一个带有函数指针的 C 结构体,如 documentation (Code example 4-1) 中所述。这是与 Java 运行时交换数据所必需的。

从此answer我知道这种带有函数指针的结构应该在 Rust 代码中有一个对应物来调用这些函数。所以我尝试实现这样一个结构,将所有字段值设置为 *mut Any 除了 GetVersion 字段:

#[repr(C)]
pub struct JavaEnv {

reserved0: *mut Any,
reserved1: *mut Any,
reserved2: *mut Any,
reserved3: *mut Any,
GetVersion: extern "C" fn(env: *mut JavaEnv) -> i32,

DefineClass: *mut Any,
FindClass: *mut Any,

当我从 Java 调用以下应该调用 GetVersion 函数的函数时,JVM 崩溃:

#[no_mangle]
pub extern fn Java_tests_Test_helloJre(jre: *mut JavaEnv, class: *const Any) {
unsafe {
let v = ((*jre).GetVersion)(jre);
println!("version: {:?}", v);
}
}

我应该如何正确调用 GetVersion 函数?请注意,我对这类东西真的很陌生,所以如果需要,请随时编辑这个问题。

最佳答案

除了 *mut Any 的问题/*const Any是胖指针,还有一个事实是原生 JNI 函数在访问 JNINativeInterface 时使用 双重间接结构:

struct JNINativeInterface_;
typedef const struct JNINativeInterface_ *JNIEnv;
jint (JNICALL *GetVersion)(JNIEnv *env);

在这里,您可以看到 JNIEnv是指向 JNINativeInterface_ 的指针实际上包含您提供的字段的结构,以及 GetVersion接受指向 JNIEnv 的指针- 也就是说,它需要一个指向 JNINativeInterface_ 的指针。 .这个 Rust 程序可以在我的机器上运行(Rust nightly 被使用,但相同的代码可以在 beta 版中使用外部 libc crate):

#![crate_type="dylib"]
#![feature(libc)]
extern crate libc;

use libc::c_void;

#[repr(C)]
pub struct JNINativeInterface {
reserved0: *mut c_void,
reserved1: *mut c_void,
reserved2: *mut c_void,
reserved3: *mut c_void,

GetVersion: extern fn(env: *mut JNIEnv) -> i32,

_opaque_data: [u8; 1824]
}

pub type JNIEnv = *const JNINativeInterface;

#[no_mangle]
pub extern fn Java_tests_Test_helloJre(jre: *mut JNIEnv, class: *const c_void) {
println!("Invoked native method, jre: {:p}, class: {:p}", jre, class);
unsafe {
let v = ((**jre).GetVersion)(jre);
println!("version: {:?}", v);
}
}

Java 对应:

package tests;

import java.nio.file.Path;
import java.nio.file.Paths;

public class Test {
public static native void helloJre();

public static void main(String[] args) {
Path p = Paths.get("libtest.dylib");
System.load(p.toAbsolutePath().toString());
Test.helloJre();
}
}

调用:

% javac tests/Test.java
% java tests.Test
Invoked native method, jre: 0x7f81240011e0, class: 0x10d9808d8
version: 65544

65544 是 0x10008,实际上,我在 Oracle JVM 1.8 下运行它。

我想你可以省略 _opaque_data字段为 JNINativeInterface结构总是通过指针传递,所以如果你只需要结构中的几个 first 字段,你可以只声明它们而忽略其余的。

关于java - 从 Java 调用 Rust,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30258427/

44 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com