上帝在造人之初已经通过语言的不同将人类分割成各个部落,如今又多了“计算机语言”这么一个洪水猛兽,导致本已分裂的人类群体要被再次划分并打上相应的标记,不同“学者”之间好像完全两个世界的人,这个世界还能更友爱一点吗!
闲话少叙,还是看看Native库的编写和使用方法吧,俗话说没吃过猪肉,还没见过猪跑啊,虽然不做java开发,但是小小的测试还是难不倒我们的,可为什么总是有人问我Native库要怎么编译?哎,源码都已经提供了,您说该怎么编译呢...
1.为了测试,在我们的Native库里面引用另外一个dll,就用MT/MD中的示例,名称为lib.dll。为啥?其实不为啥,好玩
2.Native库生成参考孙鑫教程里的指导,java编写如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com; class HelloJni{ public static native int helloworld(); public static void main(String[] args) { helloworld(); } static{ try{ System.loadLibrary("hellojni"); //System.load("C:\\JavaLoadlibrary\\hellojni.dll""); } catch(Exception e) { e.printStackTrace(); } } } |
内容很简单,就调用一个native的接口。此处插一段,就是load和loadlibrary是有区别的,前者要指定dll文件的绝对路径,后者只需要给出dll文件的名称。从使用上来说没有太多的技术含量,除非提供整套软硬件系统的供应商,否则鲜有人会使用load。我自己测试也没有发现什么值得注意的地方,也可能是新手不容易发现问题。
3.编译java源码文件,生成class
javac -d . HelloJni.java
4.生成Native库的.h文件
javah com.HelloJni
会在当前目录下产生一个名为com_HelloJni.h的头文件
5.编写Native代码
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include "com_HelloJni.h" #include "lib.h" #include "jni.h" #include <stdio.h> JNIEXPORT jint JNICALL Java_com_HelloJni_helloworld(JNIEnv *env, jobject obj) { hello(); return 0; } |
内容也非常简单,Native库里面调用外部lib.dll里面的hello()函数而已,如果不想调用第三方的接口,就替换成自己的内容,然后编译/链接生成库
set JDK=C:\Program Files (x86)\Java\jdk1.7.0_51
cl.exe /LD -I"%JDK%\include" -I"%JDK%\include\win32" -Fehellojni.dll lib.lib hellojni.c
JDK变量设置为本地JDK安装目录,链接后生成hellojni.dll文件。
6.运行java程序
java com.HelloJni
理论上程序可以正常执行,因为Native库hellojni.dll和引用的第三方库lib.dll都在当前目录下,所以不存在找不到的情况。
如果使用 - System.load("C:\\JavaLoadlibrary\\hellojni.dll"),用绝对路径会怎么样,运行看一下,也是没有问题的,因为所有的dll文件都在当前目录下。再接着将lib.dll移到另外一个目录目录下,例如.\depend_dll中呢,运行则提示找不到依赖的库文件!
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\JavaLoadlibrary\de
pend_dll\hellojni.dll: Can't find dependent libraries
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1965)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1890)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1851)
at java.lang.Runtime.load0(Runtime.java:795)
at java.lang.System.load(System.java:1062)
at com.HelloJni.<clinit>(HelloJni.java:14)
使用 -Djava.library.path=C:\JavaLoadlibrary\depend_dll 呢,网上很多人介绍这种用法,但实际效果并不理想,因为此处的设置会导致启动java时候只理会设置的路径,而原始的java.library.path里面的内容没有了,可以用System.getProperty("java.library.path")打印结果来验证这一点。所以可用的方式应该向下面这样,直接将依赖的dll目录添加到Path变量:
set Path=Path=C:\JavaLoadlibrary\depend_dll;%Path%
然后执行 java com.HelloJni,就能正常运行了,理论上应该有合理设置java.library.path 来运行程序的方法,但是如果能将两个库合并到一起,不就完美的解决这个问题了吗?如果您使用的Native代码中必需用到第三方的内容,而这个第三方又提供了static library,那还会有什么问题吗?NO