2013年1月3日 星期四

Java call C 語言 JNI 的簡易範例

想要從 Java 程式去呼叫 C 語言程式, 網路上有非常多的範例程式, 但是網路上的 JNI 範例程式大多無法順利執行, 否則就是命名方式很容易混淆, 造成初學者看的霧茫茫, 所以我故意寫個誇張的命名方式, 讓自己將來看了能很快的回想這個程式的目的, 並能很快的依照此步驟就能順利執行, 做為改寫成複雜程式的樣本參考.

 共需寫兩個檔案, HelloWorld.java 及 cjnitest.c


HelloWorld.java 如下:

class HelloWorld
{
    public native void csayhello();
    static {
        System.loadLibrary("cjnitest"); //call libcjnitest.so
    }

    public static void main(String[] args)
    {
        System.out.println("Java say Hello World 1");
        new HelloWorld().csayhello();
        System.out.println("Java say Hello world 2");
    }
}



cjnitest.c 如下:

#include <jni.h>
#include "HelloWorld.h"
#include <stdio.h>

JNIEXPORT void JNICALL
Java_HelloWorld_csayhello(JNIEnv *env, jobject obj)
{
    printf("Hello world from C Language cjnitest.c csayhello!\n");
    return;
}


編譯及執行過程:

root@ubuntu:~/workspace/testjni2# javac HelloWorld.java
這行命令產生 HelloWorld.class

root@ubuntu:~/workspace/testjni2# javah -jni HelloWorld
這行命令產生 HelloWorld.h, 這個檔案是為了提供給 cjnitest.c 使用

root@ubuntu:~/workspace/testjni2# gcc -shared -I/usr/local/jdk1.6.0_/usr/lib/jvm/java-7-openjdk-i386/include -I/usr/lib/jvm/java-7-openjdk-i386/include cjnitest.c -o libcjnitest.so
這行命令產生 libcjnitest.so, 這個檔案是為了提供給執行 HelloWorld.class 過程中使用
以下是執行命令及結果
root@ubuntu:~/workspace/testjni2# LD_LIBRARY_PATH=`pwd` java HelloWorld
Java say Hello World 1
Hello world from C Language cjnitest.c csayhello!
Java say Hello world 2

root@ubuntu:~/workspace/testjni2#


注意隱藏在文字中的細節, 可以發現

1. 我用 Ubuntu 來撰寫測試程式

   原因是在 Windows 上撰寫測試程式會牽涉較多的  UI 操作, 讓原本僅是為了了解 JNI 介面的小程式, 失焦成 UI 操作細節, 搞了半天反而還是不清楚 JNI 到底怎麼用.

2. Ubuntu 用 root 登入

   Ubuntu , LinuxMint 等 Linux 現在都禁止使用 root 登入, 但是為了安裝 Eclipse  Linux 版, 如果不用 root 登入來安裝 eclipse, 一直都會出現一些奇奇怪怪的問題, 並不是使用 $ sudo eclipse 來執行就可以解決, 最後不得已只好採用 root 登入來安裝,  不想浪費時間去解一般user 權限的問題

3. csayhello 為什麼不取成 c_say_hello

    如果取成 c_say_hello 在 compile 階段沒問題, 但是 runtime 會錯誤, 猜測是 JNI 的寫法, 底線已經被他們拿來使用, 所以我們在命名不能使用底線.
          

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。