JNI各种环境下编译方法及初期出错分析
转自 https://www.cnblogs.com/xyang0917/p/4172490.html
第五步、将C/C++代码编译成本地动态库文件
动态库文件名命名规则:lib+动态库文件名+后缀(操作系统不一样,后缀名也不一样)如:
Mac OS X : libHelloWorld.jnilib
Windows :HelloWorld.dll(不需要lib前缀)
Linux/Unix:libHelloWorld.so
1> Mac OS X
- gcc -dynamiclib -o /Users/yangxin/Library/Java/Extensions/libHelloWorld.jnilib jni/HelloWorld.c -framework JavaVM -I/$JAVA_HOME/include -I/$JAVA_HOME/include/darwin
我的$JAVA_HOME目录在:/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home
参数选项说明:
-dynamiclib:表示编译成动态链接库
-o:指定动态链接库编译后生成的路径及文件名
-framework JavaVM -I:编译JNI需要用到JVM的头文件(jni.h),第一个目录是平台无关的,第二个目录是与操作系统平台相关的头文件
2> Windows(以Windows7下VS2012为例)
开始菜单-->所有程序-->Microsoft Visual Studio 2012-->打开VS2012 X64本机工具命令提示,用cl命令编译成dll动态库:
- cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
参数选项说明:
-I : 和mac os x一样,包含编译JNI必要的头文件
-LD:标识将指定的文件编译成动态链接库
-Fe:指定编译后生成的动态链接库的路径及文件名
3> Linux/Unix
- gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared HelloWorld.c -o libHelloWorld.so
参数说明:
-I: 包含编译JNI必要的头文件
-fPIC: 编译成与位置无关的独立代码
-shared:编译成动态库
-o: 指定编译后动态库生成的路径和文件名
第六步、运行Java程序
Java在调用native(本地)方法之前,需要先加载动态库。如果在未加载动态之前就调用native方法,会抛出找不到动态链接库文件的异常。如下所示:
- Exception in thread "main" java.lang.UnsatisfiedLinkError: com.study.jnilearn.HelloWorld.sayHello(Ljava/lang/String;)Ljava/lang/String;
- at com.study.jnilearn.HelloWorld.sayHello(Native Method)
- at com.study.jnilearn.HelloWorld.main(HelloWorld.java:9)
一般在类的静态(static)代码块中加载动态库最合适,因为在创建类的实例时,类会被ClassLoader先加载到虚拟机,随后立马调用类的static静态代码块。这时再去调用native方法就万无一失了。加载动态库的两种方式:
- System.loadLibrary("HelloWorld");
- System.load("/Users/yangxin/Desktop/libHelloWorld.jnilib");
方式1:只需要指定动态库的名字即可,不需要加lib前缀,也不要加.so、.dll和.jnilib后缀
方式2:指定动态库的绝对路径名,需要加上前缀和后缀
如果使用方式1,java会去java.library.path系统属性指定的目录下查找动态库文件,如果没有找到会抛出java.lang.UnsatisfiedLinkError异常。
- Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorld2 in java.library.path
- at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
- at java.lang.Runtime.loadLibrary0(Runtime.java:845)
- at java.lang.System.loadLibrary(System.java:1084)
- at com.study.jnilearn.HelloWorld.<clinit>(HelloWorld.java:13)
大家从异常中可以看出来,他是在java.library.path中查找该名称对应的动态库,如果在mac下找libHelloWorld.jnilib文件,linux下找libHelloWorld.so文件,windows下找libHelloWorld.dll文件,可以通过调用System.getProperties("java.library.path")方法获取查找的目录列表,下面是我本机mac os x 系统下的查找目录:
- String libraryDirs = System.getProperties("java.library.path");
- System.out.println(libraryDirs);
- // 输出结果如下:
- /Users/yangxin/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
有两种方式可以让java从java.library.path找到动态链接库文件,聪明的你应该已经想到了。
方式1:将动态链接库拷贝到java.library.path目录下
方式2:给jvm添加“-Djava.library.path=动态链接库搜索目录”参数,指定系统属性java.library.path的值
java -Djava.library.path=/Users/yangxin/Desktop
Linux/Unix环境下可以通过设置LD_LIBRARY_PATH环境变量,指定库的搜索目录。
费了那么大劲,终于可以运行写好的Java程序了,结果如下:
- yangxin-MacBook-Pro:JNILearn yangxin$ java -classpath ./bin com.study.jnilearn.HelloWorld
- Java Str:yangxin
- hello yangxin
如果没有将动态库拷贝到本地库搜索目录下,执行java命令,可通过添加系统属性java.library.path来指定动态库的目录,如下所示:
- yangxin-MacBook-Pro:JNILearn yangxin$ java -Djava.library.path=/Users/yangxin/Desktop -classpath ./bin com.study.jnilearn.HelloWorld
- Java Str:yangxin
- hello yangxin
JNI各种环境下编译方法及初期出错分析的更多相关文章
- 在SoCEDS环境下编译和更新preloader和uboot程序的方法
在SoCEDS环境下编译和更新preloader和uboot程序的方法 前面有介绍preloader在HPS boot过程中的的作用,接下来讲述下用户在SoCEDS环境下改如何编译preloade ...
- Redhat环境下编译安装Google Bazel
Redhat环境下编译安装bazel 作者:Jack47 目前Google Bazel没有提供各个操作系统下的二进制安装包,只提供源代码,需要我们自己编译安装,详情可以见我翻译的中文版Google B ...
- Android 环境下编译FFmpeg
Android 环境下编译FFmpeg 开发环境:Ubuntu 12.04.2 LTS , android-sdk-linux, android-ndk-r8e 一 .X264 编译 1. X2 ...
- centos7.6环境下编译安装tengine-2.2.2的编译安装
centos7.6环境下编译安装tengine-2.2.2的编译安装 .获取tengine2..2的源码包 http://tengine.taobao.org/download/tengine-2.2 ...
- Boost学习总结(一)VS2010环境下编译STLport和Boost
Boost学习总结(一)VS2010环境下编译STLport和Boost Boost简介 Boost库是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库.1998年,Beman G.Da ...
- Suse环境下编译linux-2.6.24内核
Suse环境下编译linux-2.6.24内核 1.下载linux-2.6.24内核源码: https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/ ...
- libCURL开源库在VS2010环境下编译安装,配置详解
libCURL开源库在VS2010环境下编译安装,配置详解 转自:http://my.oschina.net/u/1420791/blog/198247 http://blog.csdn.net/su ...
- 在Tex live和Beamer环境下编译中文
在Tex live和Beamer环境下编译中文时,容易出现缺少$的提示错误.它有可能是由于特殊字符所致,如下划线: 也有可能是插图有误所致.
- 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...
随机推荐
- Objective-C(十九、通知-消息发送模式之中的一个)——iOS开发基础
结合之前的学习笔记以及參考<Objective-C编程全解(第三版)>,对Objective-C知识点进行梳理总结. 知识点一直在变.仅仅是作为參考.以苹果官方文档为准~ 十九.通知-消息 ...
- 读MBA经历回想(下)做法决定结果——北漂18年(49)
上期聊了目的决定了手段,这次说说详细做法决定了最后的结果. 差额面试被淘汰的高分学员 2005年,是北京邮电大学工商管理学入学考试第一个差额淘汰的年份.意思是过分数线(165分)的人数超过了录取人数, ...
- Linux下使用fstatfs/statfs查询系统相关信息
Linux下使用fstatfs/statfs查询系统相关信息 1. 功能 #include < sys/statfs.h > int statfs(const char *path, ...
- Dynamics CRM 2015/2016 Web API:Unbound Custom Action 和 Bound Custom Action
今天我们再来看看Bound/Unbound Custom Action吧,什么是Custom Action?不知道的小伙伴们就out了,Dynamics CRM 2013就有了这个功能啦.和WhoAm ...
- 操作系统 linux 内核的三种进程调度方法
1.SCHED_OTHER 分时调度策略: 2.SCHED_FIFO 实时调度策略.先到先服务: 3,SCHED_RR 实时调度策略,时间片轮转 . 实时进程将得到优先调用,实时进程依据实时优先级决定 ...
- vim插件之ack
这个插件其实是实现vim内部搜索功能的今天在学习vim搜索的时候,遇到了一个ack.vim的插件,这个插件给我们提供了一个并行于系统命令grep的搜索命令Ack 它的下载地址是 https://git ...
- VisualRoute for Mac OS 体验
VisualRoute 网络路径结点回溯分析工具,以在世界地图上显示连结的路径的方式,让你知道当无法连上某些IP时的真正问题所在.VisualRoute将traceroute.ping以及Whois等 ...
- IOS打包发布APP的所有详细流程
其他一些不错的参考:点击打开链接 一.申请苹果开发者账号 首先需要申请苹果开发者账号才能在APP store 里发布应用. 开发者账号分为:(1)个人开发者账号 (2)企业开发者账号 主要的区 ...
- pidof---查找指定名称的进程的进程号id号。
pidof命令用于查找指定名称的进程的进程号id号. 语法 pidof(选项)(参数) 选项 -s:仅返回一个进程号: -c:仅显示具有相同“root”目录的进程: -x:显示由脚本开启的进程: -o ...
- [ES6] Extends class in ES6 vs ES5 subclass
ES6 class with extends and super: class Tree { constructor(size = ', leaves = {spring: 'green', summ ...