linux下 java JNI调用C语言动态链接库(非常使用!!非常经典!!)

9 篇文章 0 订阅
6 篇文章 0 订阅

comes from: http://watershitter.iteye.com/blog/477615


1 java 中 c语言函数的声明 

    public native static void greeting(); //就像是接口声明一样,不过有native! 

2 编译 javac HelloNative.java ,然后使用 javah 

      javah HelloNative会自动产生c的头文件HelloNative.h

3 生成的头文件 的 第一句子为 

  #include <jni.h> 
  但是gcc里面默认环境可不知道jni.h是什么东西,jni.h在jdk的$JAVA_HOME/include或者$JAVA_HOME/include/linux下面,可进去查看一下~ 

4 接下来就是根据HelloNative.h中声明的方法写C语言的实现,注意,自动生成的那个函数名字很长,并且 开头的  Java是大写的,大小写很致命,(最后我的程序在动态库已经加载好的情况下报错:java.lang.UnsatisfiedLinkError: HelloNative.greeting()V,就是因为c语言中的函数名字大小写写错,奇怪!编译不报错.....) 

<<<评论:这个作者有点2,直接复制就好了>>>


5 linux下编译生成动态库,注意不同环境的不一样~ 

  gcc -fPIC -I jdk/include -I jdk/include/linux -shared -o libHelloNative.so HelloNative.c 

<<<我当时的编译命令是:

gcc -fPIC -shared -D_REENTRANT -I $JAVA_HOME/include -I $JAVA_HOME/include/linux Hello.c -o libTestHello.so

我认为作者的命令是出问题的,除非作者真有jdk这个文件夹而且真在他的父母录。。。我这条前提也是配置了java环境,不过这不是废话么。。>>>

  在这里,我犯的错:

a,不理解 -I jdk -I 是include,显示指定库的库的地址,自然后面的jdk是要用你的设计地址替换的,

b, 着急的去网上搜索问题,没有注意的在linux下,动态链接库的名字 必须是 lib****.so,必须以lib开头! 

<<<我也被b这条搞了很长时间,而且我就只是在这里出了问题。。真感谢作者>>>


6 编译生成了 libHelloNative.h之后,接下写一个test类,如 HelloNativeTest, 
当然要调用System.loadLibrary("HelloNative");注意此时不要lib,也不要.so!; 
调用执行 HelloNative.greeting();这个时候错误又来了: 
java.lang.UnsatisfiedLinkError: no HelloNative in java.library.path。这个错误很经典,原因:是java找不到库路径~: 
显然: libHelloNative.so放在当前路径 ".",但linux执行的时候却不知道在当前路径找。 linux很“傻”很“复杂”~ 
a. linux下面java.library.path 和环境变脸 jdk/bin的那个个PATH不是一回事情,有另外一个默认变量 LD_LIBRARY_PATH来保存他的信息。而windows下,首先java会找当前目录,其次,它会去环境变量的地址找! 
b。 由于linux的路径特殊,所以,解决方法 1-可以调用sysout(System.getProperty("java.library.path"));来查看! 然后把 libXXXX.so拷贝到那里面的目录下去 
2 设置环境变量 export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ,但是设置到哪里呢? /etc/profile ? or /root/.bashrc 不知道...忘记了linux的加载顺序了~ 
3 可以单次执行时候指定library位置: 
  java -Djava.library.path=. HelloNativeTest 

总结犯错:

1.不知道gcc编译时候指定库 

2.不了解java.libray.path的特点,特别是在linux下 

3.c语言实现函数的时候拼写错误 

4.排除问题不够理性,系统化,出现了烦躁情绪,导致效率低。 时刻明白,机器只是做你指定的事情,总是你自己出错了~~~ 


附:gcc 参数解释(转载): 
   最主要的是GCC命令行的一个选项: 
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件 

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。 

-L.:表示要连接的库在当前目录中 

-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称 

LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。 

当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。 


4、注意 

调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。 


<<<虽然自己当初用过jni(不过貌似是一年前了),如今用起来居然还花了我两个小时去写一个helloworld!!可想我当时的基础多么不扎实,我却一直跟别人说我的基础非常厉害,非常牢固。。真无地自容了>>>

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
准备工作: 1.编译JnativeCpp 2.将编译出来的libJNativeCpp.so,拷贝到/usr/lib/,同时执行chmod 555 libJNativeCpp.so 测试过程简介 1.c测试库libtest.so 环境:ubuntu10.4下 语言:c 编译库名称为:libtest.so 涉及文件:so_test.h test_a.c test_b.c test_c.c 终端执行命令:$ gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so 将编译得到到libtest.so拷贝到/usr/lib/,同时执行chmod 555 libtest.so 2.qt测试库libmylib.so 环境:ubuntu10.4下 语言:c 编译工具:qt Creator 编译库名称为:libmylib.so 将编译得到到libmylib.so拷贝到/usr/lib/,同时执行chmod 555 libmylib.so 3.编译环境安装 a.安装jdk 1.6 b.安装netBeans 6.8 c.创建javaApp工程 d.将JNative.jar添加到工程 e.参考如下代码,编写后编译执行,并运行 import org.xvolks.jnative.JNative; import org.xvolks.jnative.Type; import org.xvolks.jnative.exceptions.NativeException; public class Main { public static void main(String[] args) throws NativeException, IllegalAccessException{ //纯c写到动态库 JNative clib = new JNative("libtest.so", "test_a"); //调用libtest.so下到test_a函数 clib.setRetVal(Type.STRING); //设置此函数的返回值 clib.invoke(); //函数执行 System.out.println(clib.getRetVal());//输出函数返回结果 //qt写到动态库 //以下部分使用qt编译到so,注意在函数声明前加 extern "C" //如extern "C" const char* getLocalHost(); JNative getstring = new JNative("libmylib.so", "getstring"); getstring.setRetVal(Type.STRING); getstring.invoke(); System.out.println(getstring.getRetVal()); } } 4.输出结果 this is in test_a... getstring hello .....

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值