一般查到的 JNI 文件似乎都是以 C 做為範例,但實際上 JNI 針對 C 與 C++ 似乎提供了不同介面?總之,用常見的那些 for C 的範例是行不通的。
剛剛重新試了一下,沒想到成功了!其實答案就在 g++ 給的 error message 中,上周大概是太累了,居然沒仔細看,白白花了那麼多冤枉工夫。
這邊簡單做個筆記。
Step 1:在 class 裡要先宣告 native method
此例為 HelloWorld 類別(HelloWorld.java)
class HelloWorld {
private native void print();
private native String getString(String filename);
public static void main(String[] args) {
System.out.println(new HelloWorld().getString(args[0]) );
}
static {
System.loadLibrary("HelloWorld");
}
}
在此處有 2 個 native method:print() 和 getString()。System.loadLibrary() 是為了載入 native method 所在的 library。
Step 2:編譯出 class 的 byte code
$ javac HelloWorld.java產生 HelloWorld.class。
Step 3:使用 javah 產生 JNI 相對應的 C header & source file ,並實做 .c 檔裡的方法
$ javah -jni HelloWorld產生 HelloWorld.h 與 HelloWorld.c(若用 C++ 則自行改副檔名為 .cpp)。
HelloWorld.h(不更動)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
/*
* Class: HelloWorld
* Method: getString
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloWorld_getString
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
HelloWorld.cpp(實作)
#include <jni.h>
#include <cstdio>
#include <string>
#include "HelloWorld.h"
using namespace std;
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
JNIEXPORT jstring JNICALL
Java_HelloWorld_getString(JNIEnv *env, jobject obj, jstring filename)
{
string s = "the filename is: ";
size_t strLength = 0;
const char *buf = 0;
strLength = (env)->GetStringLength(filename);
buf = (env)->GetStringUTFChars( filename, 0);
s += buf;
(env)->ReleaseStringUTFChars( filename, buf);
return (env)->NewStringUTF( s.c_str() );
}
print() 做的事很簡單,只是印個 "Hello World!"。getString() 則是接收傳入的 String (jstring),處理完後,再回傳。
值得注意的是這邊取得變數與回傳變數的方法是 C++ 適用的,C 的寫法不同,可參考 jni.h。
Step 4:編譯 library
g++ -shared -o libHelloWorld.so HelloWorld.cpp -I/usr/lib/jvm/java-6-openjdk/include此例會產生一個 static shared library,-I 參數的 include file path 請指定 JDK 位置。
Step 5:執行
$ LD_LIBRARY_PATH=`pwd` java HelloWorld a.jpg會顯示:the filename is a.jpg
設定 LD_LIBRARY_PATH 是為了讓 JVM 能在當前路徑(pwd)找到 libHelloWorld.so 並載入。
參考資料
C++和JNI的数据转换
沒有留言:
張貼留言