构建跨平台的JNI实现(下)
昨天我们讲了要开发JNI的几个工具的安装和下载,今天我们讲它们的基本使用.为了验证我们昨天的PATH确实设好了.我们可以进入CMD下面,输入如下语句:gcc --version
如果输出类似如下的话,就说明安装正确了:
gcc (GCC) 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
既然我们这个已经装好了,现在就打开Netbeans6.0吧.Netbeans6.0现在提供的下载分几个版本,我们下载的是完全版,就是什么功能都有的,完全版最大,如果下载别的版本的话,就不能用它来做C/C++的程序了.启动速度当然就最慢了.启动的时候,耐心的等待一下,反正启动界面挺好看的.
好了,Netbeans启动了,我们先建一个JAVA工程,名字就叫TestNative吧.如何使用Netbeans就不是本文的目的了:).大家可以去参考别的资料。然后在TestNative里面建一个类,就叫testnative1.Main吧。然后在里面写上如下的内容:.
/*
* Main.java
*
* Created on 2007-10-19, 17:23:02
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package testnative1;
/**
*
* @author hadeslee
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Main m = new Main();
System.loadLibrary( " cygHello " );
m.sayHello( " hadeslee " );
}
public native void sayHello(String who);
}
* Main.java
*
* Created on 2007-10-19, 17:23:02
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package testnative1;
/**
*
* @author hadeslee
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Main m = new Main();
System.loadLibrary( " cygHello " );
m.sayHello( " hadeslee " );
}
public native void sayHello(String who);
}
在这里我们可以看到,我们定义了一个native的方法,叫sayHello,它接受一个String做为参数,我们编译一下这个文件,然后转到此工程的build/classes文件夹下面,执行如下命令:
javah testnative1.Main
如果正常的话,就会在你运行命令的目录下产生一个testnative1_Main.h的文件。至此,我们JAVA部份的工作就告一段落了。
然后我们新建一个C/C++的工程,选择C/C++ Dynamic Library。意思是动态链接库。工程名就叫Hello吧。
打开这个工程,在Header Files节点下,建一个C++的头文件,就叫HelloH.h吧。进入这个文件以后,我们把刚刚生成的testnative1_Main.h内容复制到它里面去。 这样头文件就建好了。然后再在Source Files节点下,建一个Empty C++ File。把如下的内容复制过去:
#include
<
jni.h
>
#include < stdio.h >
#include " HelloH.h "
JNIEXPORT void JNICALL Java_testnative1_Main_sayHello
(JNIEnv * env, jobject obj, jstring s){
const char * who;
who = env -> GetStringUTFChars(s, 0 );
printf( " 你好:%s " , who);
env -> ReleaseStringUTFChars(s,who);
}
#include < stdio.h >
#include " HelloH.h "
JNIEXPORT void JNICALL Java_testnative1_Main_sayHello
(JNIEnv * env, jobject obj, jstring s){
const char * who;
who = env -> GetStringUTFChars(s, 0 );
printf( " 你好:%s " , who);
env -> ReleaseStringUTFChars(s,who);
}
这个时候,你会发现很多错误提示,别急,我们一个一个来解决,首先对着你的Hello工程点右键,然后再点Properties。找到如图所示的地方,添加我们的引用的头文件,这个引用是SUN公司给我们定义好的头文件,就是供我们开发JNI的时候用的。
这里有一点要注意的就是,不要直接引用到JDK里面的头文件,最好是把它里面的include文件夹拷出来,因为我们默认安装的java是装在C:\program files下面的,因为有空格,所以cygwin将不能识别,在我这里我是把它拷出来放在D盘的根目录下。然后再找到Command Line这个地方,加上如下的几个命令:
-mno-cygwin -Wl,--add-stdcall-alias -shared -m32
至此,我们的事情就完成了大部份了,然后我们编译生成整个Hello工程就可以了,如果不出意外的话,就可以在dist目录下面找到一个叫cygHello.dll的文件,我们把这个文件拷到我们的TestNative工程的根目录下,执行一下我们的Main类,发现了没有,我们的native方法 有输出了。我们现在只是生成了一个在windows下面使用的动态链接库,如果我们要生成能在linux,Mac ,Solaries平台下的呢。别急,有cygwin,一切都可以搞定了。我们要生成别的平台的库文件,只要在General里面选中相应的平台就可以了。不过最好的办法还是去相应的平台下载cygwin,然后再重新用我们这个工程,经过少量的改动,重新生成一下,只需要改动的地方有,include要改一下,因为在windows下面我们include的目录和linux当然不一样。还有就是在linux下面编译的时候,不再需要-mno-cygwin -Wl,--add-stdcall-alias -shared -m32这个命令了。直接生成就可以了,在linux下面会生成一个叫libHello.so的文件,我们JAVA代码只要导入Hello就可以了,lib的前缀不需要再导入了,因为linux下面库文件都是带lib前缀的。
我这里用的linux环境是ubuntu,一切都正常,在ubuntu下可以看到正常的输出。只是你一样要把它放到java.library.path里面去,这样JVM才能找得到它。构建跨平台的jni并不是一件非常容易的事情,但是从一个小小的例子可以看出JNI方面的一些东西。祝大家玩得愉快。
尽管千里冰封
依然拥有晴空
你我共同品味JAVA的浓香.