Rust JNI原理

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 
#include 
#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

你可能感兴趣的:(Rust JNI原理)