当前位置:首页 > 芯闻号 > 充电吧
[导读]  首先我实在 ubantu12.04 下进行操作的,还要有 eclipse ~~1.JNI的工作原理JNI : Java Native Interface 即JAVA本地调用(1)java的本质  

  首先我实在 ubantu12.04 下进行操作的,还要有 eclipse ~~

1.JNI的工作原理

JNI : Java Native Interface 即JAVA本地调用

(1)java的本质

  想搞明白jni的本质,还要从java的本质说起.从本质上来说,java这门语言就是一门脚本语言(这是偶的个人理解,希望java大侠们不要用板砖拍我),它的运行完全依赖于脚本引擎对java的代码进行解释和执行(当然了,现代的java已经先进许多,可以从源代码编译成.class之类的中间格式的二进制文件,这种处理会大大地加快java脚本的运行速度,但是基本的执行方式仍然不变,由脚本引擎(我们称之为JVM)来执行,与python、perl之类的纯脚本相比,它只是把脚本变成了二进制格式而已.另外就是java本身对面向对象的概念支持得很好,拥有完善的功能库可供调用,把这个脚本引擎移植到所有平台上,那么这个脚本自然就实现所谓的“跨平台”了).绝大多数的脚本引擎都支持一个很显著的特性,就是可以通过c/c++编写模块,在脚本中调用这些模块,以此来类比java,也是一样的,java一定要提供一种在脚本中调用c/c++编写的模块的机制,才能称得上是一个相对完善的脚本引擎.

  (2)android中的java

  android平台从本质上是 由arm-linux操作系统 和一个叫做dalvik的java虚拟机组成的.所有在android模拟器上面看到的那些华丽的界面,都是用java语言编写的(参见android平台源代码的frameworks/base目录).目前看来dalvik只是提供了一个标准的支持jni调用的java虚拟机环境.android平台中所有的硬件相关的操作均是采用jni技术进行了封装,由java去调用jni模块,而jni模块使用c/c++调用android本身的arm-linux底层驱动.

  例如,frameworks/base/libs/ui目录下面有一个叫做“EGLDisplaySurface.cpp”的文件,里面的:
  status_t EGLDisplaySurface::mapFrameBuffer()函数中,就有直接对android的arm-linux中的framebuffer的初始化代码.
  这也更加印证了,android其实是依靠java+jni建立起来的王国.hoho,如此一来,就凸显出jni在Android开发中的重要性(当然,一些简单的小程序是完全可以只用java就搞定的).
  “jni”的子目录,这个目录将用来存放.c的文件.


2.使用JNI两个原因

1、运行JAVA程序的虚拟机是用Native语言编写的,而虚拟机运行在具体的平台上,所以虚拟机本身无法做到平台无关,而利用JNI技术即可对JAVA层屏蔽不同操作系统平台之间的差异,如file,socket等
2、在JAVA语言诞生前,很多程序使用Native语言编写,JAVA直接利用JNI使用,避免造重复轮子的坏名声。而且JNI的运行效率和速度会更高


3.JNI 之 HelloWorld

  在Ubantu 中打开 eclipse ,写 java 代码:

HelloWorld.java


public class HelloWorld {

	static{
		System.loadLibrary("hello");
	}
	public native void DisplayHello();
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new HelloWorld().DisplayHello();
		//System.out.println( System.getProperty("java.library.path"));
	}

}


进入src目录下,编译该JAVA类,(我是用默认包,不用写包名,有创建包的同鞋们要自己加包名)

命令:javac HelloWorld.java 在该 HelloWorld.java 所在目录下生成 HelloWorld.class 然后使用javah生成头文件, 命令:javah -jni HelloWorld 在当前目录下生成 HelloWorld.h 头文件,此文件供C、C++程序来引用并实现其中的函数

HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    DisplayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_DisplayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

注:1)、此头文件是不需要用户编译的,直接供其它C、C++程序引用。      2)、此头文件中的JNIEXPORT void JNICALL Java_HelloWorld_DisplayHello(JNIEnv *, jobject);方法,是将来与动态链接库交互的接口,并需要名字保持一致。

创建HelloWorld.cpp 实现头文件中的方法:

#include "jni.h"
#include "HelloWorld.h"
#includeJNIEXPORT void JNICALL Java_HelloWorld_DisplayHello
(JNIEnv *env, jobject obj)
{
    printf("From HelloWorld.cpp :");
    printf("Hello world ! n");
    return;
}

此C++文件实现了上述头文件中的函数,注意方法函数名要保持一致。

编译生成动态库libHello.so

编译c程序:
gcc -shared -fpic XXX.c -o XXX.so

编译c++程序:
g++ -shared -fpic XXX.cpp -o XXX.so


我是用下面这种方法:

g++ -I /usr/lib/jvm/java-6-sun/include/linux/ -I /usr/lib/jvm/java-6-sun/include/ -fPIC -c Hello.cpp

生成Hello.o

g++ -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o

生成libhello.so.1.0

接下来将生成的共享库拷贝为标准文件名

cp libhello.so.1.0 libhello.so

或者使用:

g++ -I /usr/lib/jvm/java-6-sun/include/linux/ -I /usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o libLexical.so Lexical.cpp


编译好 .so接下来的任务是要让 java library path 能找到 .so
第一种方法:
现在HelloWorld.java 用 System.out.println( System.getProperty("java.library.path")); 打印出 java library 的路径, 然后把 libhello.so 复制到 java library path 的文件夹下面,如果没有权限的话用 sudo mv  ./x ...(我是用这种方法)

第二种方法:
设置当前的 .so 的路径为 java library path 可以访问的路径
export LD_LIBRARY_PATH=...../(路径):$LD_LIBRARY_PATH

设置好路径点运行成功
From HelloWorld.cpp :Hello world !

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

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

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

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

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

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

注意

1. 在linux下,动态链接库的名字必须是 lib****.so,必须以lib开头

2. 加载.so 文件时 ,我的c同事给我的.so 文件名为libswdes.so 我在java类里面调用时 需要这样写System.loadLibrary("swdes"); 不能带前面的lib和后缀名.so!

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

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭