1、Rust FFI
Rust语言本身提供C语言接口,以ffi的形式可以直接调用C库中的函数。语法是这样的:
#[link(so/filename)]
extern "C" {
fn foo() -> return_type;
}
#[repr(return_type)]
return type definition
而JNI正是JDK提供的用于Java和C/C++之间相互调用的,函数都定义在libjvm.so中,如果是Linux系统,执行
locate libjvm.so
即可找到该库。
2、Java Native Interface
JNI全称Java Native Interface,它实现了Java和C/C++之间通信的机制,可从Java访问C/C++,也可从C/C++访问Java。
- Java访问C/C++
在Java中通过native关键字声明方法,但是通过外部C/C++文件实现。jvm会加载外部库找到相应的方法。在Java声明完成后,通过javac生成头文件,如果是JDK 10以前的版本,则通过javah生成头文件,
javac foo.java -h <header_dir>
相关feature更新记录在http://openjdk.java.net/projects/jdk/10/中,其中313条Remove the Native-Header Generation Tool (javah)
Hello World Example
Java代码
class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.loadLibrary("hello");
}
}
C语言代码
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World\n");
}
Makefile
.PHONY: all clean tar
INC_DIR =
INC_DIR += -I/usr/lib/jvm/java-10-oracle/include/
INC_DIR += -I/usr/lib/jvm/java-10-oracle/include/linux
all: libhello.so
libhello.so: HelloWorld.o
gcc -shared -o $@ $<
%.o : %.c
gcc $(INC_DIR) -c -fPIC $<
clean:
@rm -rf libhello.so *.o
tar:
- C/C++访问Java
从上面的example可以发现,有两个参数:JNIEnv指针和jobject。这个JNIEnv和jobject正是包含了对应Java定义的方法和成员的所有信息。libjvm.so中提供了JNI_CreateJavaVM函数用来初始化JNIEnv,原型JNI_CreateJavaVM(JNIInvokeInterface **, JNINativeInterface **, JavaVMInitArgs *)
正是通过JNIEnv,我们可以访问到Java中方法和成员。
三、Rust JNI仓库
git clone https://github.com/benanders/rjni.git
cd rjni; cargo build
添加example到Cargo.toml文件中。
[[example]]
name = "instance"
path = "examples/instance.rs"
[[example]]
name = "field"
path = "examples/field.rs"
[[example]]
name = "static"
path = "examples/static.rs"
[[example]]
name = "static_field"
path = "examples/static_field.rs"
then use examples to test Rust JNI Crate
export LIBRARY_PATH=/usr/lib/jvm/java-8-oracle/jre/lib/amd64/server/; cargo run --example instance