【发布时间】:2015-05-15 11:31:07
【问题描述】:
我正在使用 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 函数?请注意,我对这类东西真的很陌生,所以如果需要,请随时编辑这个问题。
【问题讨论】:
-
我无法给出完整的答案,但您似乎假设
*const Any是一个常规指针:它不是。它是一个指向 trait 对象的指针,这意味着它是常规指针大小的两倍。您不应该使用*const Any来表示“任意指针”;为此,您应该使用*const ()或*const c_void(来自libc包)。顺便说一句:您可以使用::std::mem::size_of<T>()来获取给定类型的大小。 -
请注意
Any是一个特征,任何指向一个裸特征的指针都是一个特征对象,也就是说,它实际上是一个“胖”指针。例如,this 程序打印 16 而不是 8。因此它不适合用作类似void*的指针。你需要例如*mut ()为它。
标签: java java-native-interface rust