转自 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

  1. 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动态库:

  1. 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

  1. 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方法,会抛出找不到动态链接库文件的异常。如下所示:

  1. Exception in thread "main" java.lang.UnsatisfiedLinkError: com.study.jnilearn.HelloWorld.sayHello(Ljava/lang/String;)Ljava/lang/String;
  2. at com.study.jnilearn.HelloWorld.sayHello(Native Method)
  3. at com.study.jnilearn.HelloWorld.main(HelloWorld.java:9)

一般在类的静态(static)代码块中加载动态库最合适,因为在创建类的实例时,类会被ClassLoader先加载到虚拟机,随后立马调用类的static静态代码块。这时再去调用native方法就万无一失了。加载动态库的两种方式:

  1. System.loadLibrary("HelloWorld");
  2. System.load("/Users/yangxin/Desktop/libHelloWorld.jnilib");

方式1:只需要指定动态库的名字即可,不需要加lib前缀,也不要加.so、.dll和.jnilib后缀

方式2:指定动态库的绝对路径名,需要加上前缀和后缀

如果使用方式1,java会去java.library.path系统属性指定的目录下查找动态库文件,如果没有找到会抛出java.lang.UnsatisfiedLinkError异常。

  1. Exception in thread "main" java.lang.UnsatisfiedLinkError: no HelloWorld2 in java.library.path
  2. at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
  3. at java.lang.Runtime.loadLibrary0(Runtime.java:845)
  4. at java.lang.System.loadLibrary(System.java:1084)
  5. 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 系统下的查找目录:

  1. String libraryDirs = System.getProperties("java.library.path");
  2. System.out.println(libraryDirs);
  3. // 输出结果如下:
  4. /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程序了,结果如下:

  1. yangxin-MacBook-Pro:JNILearn yangxin$ java -classpath ./bin com.study.jnilearn.HelloWorld
  2. Java Str:yangxin
  3. hello yangxin

如果没有将动态库拷贝到本地库搜索目录下,执行java命令,可通过添加系统属性java.library.path来指定动态库的目录,如下所示:

  1. yangxin-MacBook-Pro:JNILearn yangxin$ java -Djava.library.path=/Users/yangxin/Desktop -classpath ./bin com.study.jnilearn.HelloWorld
  2. Java Str:yangxin
  3. hello yangxin

JNI各种环境下编译方法及初期出错分析的更多相关文章

  1. 在SoCEDS环境下编译和更新preloader和uboot程序的方法

    在SoCEDS环境下编译和更新preloader和uboot程序的方法   前面有介绍preloader在HPS boot过程中的的作用,接下来讲述下用户在SoCEDS环境下改如何编译preloade ...

  2. Redhat环境下编译安装Google Bazel

    Redhat环境下编译安装bazel 作者:Jack47 目前Google Bazel没有提供各个操作系统下的二进制安装包,只提供源代码,需要我们自己编译安装,详情可以见我翻译的中文版Google B ...

  3. Android 环境下编译FFmpeg

    Android 环境下编译FFmpeg 开发环境:Ubuntu 12.04.2 LTS , android-sdk-linux, android-ndk-r8e 一 .X264 编译 1.    X2 ...

  4. centos7.6环境下编译安装tengine-2.2.2的编译安装

    centos7.6环境下编译安装tengine-2.2.2的编译安装 .获取tengine2..2的源码包 http://tengine.taobao.org/download/tengine-2.2 ...

  5. Boost学习总结(一)VS2010环境下编译STLport和Boost

    Boost学习总结(一)VS2010环境下编译STLport和Boost Boost简介 Boost库是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库.1998年,Beman G.Da ...

  6. 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/ ...

  7. libCURL开源库在VS2010环境下编译安装,配置详解

    libCURL开源库在VS2010环境下编译安装,配置详解 转自:http://my.oschina.net/u/1420791/blog/198247 http://blog.csdn.net/su ...

  8. 在Tex live和Beamer环境下编译中文

    在Tex live和Beamer环境下编译中文时,容易出现缺少$的提示错误.它有可能是由于特殊字符所致,如下划线: 也有可能是插图有误所致.

  9. 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...

随机推荐

  1. 怎样更好的设计android图标,拉伸不变形等等系列长处,并且减小apk大小

    android mvp框架:dileber(https://github.com/dileber/dileber.git) 继续为大家介绍android mvp开源框架 dileber  今天主要是字 ...

  2. 我的RTOS 之二 --Threadx在skyeye上仿真測试(基于2410)

    对于RTOS 移植来说,移植平台至少要提供双方面的设备. 1.OS执行时,须要tick,所以须要提供Timer定时器 2.OS执行时,须要调度,就是挂起当前线程,把控制权交给系统,所以须要訪问系统各个 ...

  3. java8新增特性(一)---Lambda表达式

    Lambda表达式也成为闭包,是java语言层次上的改变,Lambda同意把函数作为一个方法的參数(函数作为參数传递进方法中),或者把代码看成数据.函数式程序猿对这一概念非常熟悉. 在JVM平台上有非 ...

  4. 【HDOJ 5384】Danganronpa

    [HDOJ 5384]Danganronpa AC自己主动机. .. 当时感觉用字典树 标神也往自己主动机想来着..手太生加上时间紧迫也没敲--回来一看题解什么AB同一时候建自己主动机...顿时愣了 ...

  5. Redisclient连接方式Hiredis简单封装使用,连接池、屏蔽连接细节

    工作须要对Hiredis进行了简单封装,实现功能: 1.API进行统一,对外仅仅提供一个接口. 2.屏蔽上层应用对连接的细节处理: 3.底层採用队列的方式保持连接池,保存连接会话. 4.重连时採用时间 ...

  6. win7中下mysql-5.6.22免安装配置

    windows下mysql免安装配置 1. 下载mysql免安装压缩包 下载mysql-5.6.22-winx64.zip 解压到本地D:\mysql-5.6.22-winx64 2. 修改配置文件 ...

  7. CentOS下编译安装Apache

    与Apache 2.2.x相比,Apache 2.4.x提供了很多性能方面的提升,包括支持更大流量.更好地支持云计算.利用更少的内存处理更多的并发等.除此之外,还包括性能提升.内存利用.异步 I/O的 ...

  8. sqlserver 小计合计总计

    SELECT CASE WHEN GROUPING(F1) = 1 THEN '总计'WHEN GROUPING(F1) = 0 AND GROUPING(F2) = 1 THEN  F1+'合计'W ...

  9. Unity 3D 开发 —— 脚本编程

    Unity 相关资源 Unity 官网 :http://www.unity3D.com Unity 论坛 : http://forum.unity3d.com/forum.php Unity 问答 : ...

  10. C#开发 —— 异常处理

    System.ArithmeticException 在算术运行期间发生异常 System.ArrayTypeMismatchException 存储元素的实际类型与数组的实际类型不兼容而导致存储失败 ...