Jni Native를 통한 Rust 함수 호출

회사 허락을 맡아 홀로 프로젝트를 하나 시작했다. 큰 그림은 일부 컴포넌트를 Rust로 구현하고 컴포넌트간 연결은 rpc로 하는 것인데 아직 Rust 로 rpc 구현을 하기에 시간이 더 필요하다. 임시적인 수단으로 JNI를 통해 기존 컴포넌트에 연결을 하려고 한다.

그 외 프로젝트에 자세한 이야기는 나중에 설명하고 위 목적으로 Stackoverflow 에서 참고하고 https://github.com/Monnoroch/RustJni 를 참고해서 JNI를 테스트를 해봤다.

C 바인딩이 쉬운것은 Rust의 장점 중 하나인데 JNI 바인딩 역시 순조로웠다. 방법은 우선 아래와 같이 native 함수 인터페이스를 작성하고


public class NativeInvoke {
public static native void procedure();
public static native void stringArg(String str);
public static native String returnString();
}

아래와 같이 Rust 코드를 작성하면 된다.


#![crate_type="dylib"]
#![feature(libc)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate libc;
extern crate jni;
use libc::c_void;
use std::ptr;
use jni::native::*;
use jni::helper::*;
#[no_mangle]
pub extern fn Java_org_github_hyunsik_NativeInvoke_procedure(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);
}
}
#[no_mangle]
pub extern fn Java_org_github_hyunsik_NativeInvoke_stringArg(jre: *mut JNIEnv,
class: *const c_void, name: jstring) {
unsafe {
let string = ((**jre).GetStringUTFChars)(jre, name, ptr::null_mut());
println!("{}", chars_to_str(string));
((**jre).ReleaseStringUTFChars)(jre, name, string);
}
}
#[no_mangle]
pub extern fn Java_org_github_hyunsik_NativeInvoke_returnString(jre: *mut JNIEnv,
class: *const c_void) -> jstring {
unsafe {
return str_to_jstring(jre, "jni native");
}
}

view raw

lib.rs

hosted with ❤ by GitHub

이게 전부다. 위에서 사용된 chars_to_str와 str_to_jstring 는 아래 github repository에 있다.

https://github.com/hyunsik/jni-rs/blob/master/src/helper.rs

위 repository 는 https://github.com/Monnoroch/RustJni를 fork 해서 JNI 뿐 아니라 JNI 프로그램 작성 중에 반복되는 코드들에 대한 유틸리티 함수들을 추가할 계획이다.

그리고 아래는 JNI Native + Rust 를 위한 템플릿 프로젝트이다.

https://github.com/hyunsik/rust-jni-template