最近看openjdk,想记录点东西,openjdk很多都是jni接口,于是自己仿照着些点例子玩玩。等熟悉 的差不多之后继续做笔记,研究openjdk。今天从最简单的开始,hello world,不带参数的jni调用。我是在linux下编写的。
#ifndef __HELLO_H__ //防止重复导入头文件内容
#define __HELLO_H__ //
#include <jni.h> //包含jni头文件
//如果定义了c++常量,则指定采用c的编译方式(extern "C")
#ifdef __cplusplus
extern "C"{
#endif
/**JNIEXPORT关键字 + void返回类型 + JNICALL关键字 + 方法名称(前缀Java_ + JAVA类名Hello + 加下划线_ + 本地方法名称) + 方法参数(JNIEnv是jni的环境通过这个指针你才能将java语言使用的对象或者参数传给c语言使用,jobject是this)
*/
JNIEXPORT void JNICALL Java_Hello_hello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif
//定义函数
#include<jni.h>
#include"hello.h"
#include<stdio.h>
JNIEXPORT void JNICALL
Java_Hello_hello(JNIEnv *env, jobject obj)
{
printf("Hello world jni !\n");
return;
}
第二步,编译成so
gcc -shared -I$JAVA_HOME/include hello.c -o libhello.so(-I可以指定额外包含的头文件位置)
问题1 : 执行上面语句居然报错了,/usr/tools/jdk1.7.0_60/include/jni.h:45:20: error: jni_md.h: No such file or directory
In file included from hello.c:1:,没有找到jni_md.h这个头文件。
我到jni.h中看到是包含了jni_md.h,find / -name "jni_md.h"发现在/usr/tools/jdk1.7.0_60/include/linux/jni_md.h,而jni.h的包含路径写错了,我改为了linux/jni_md.h。
问题2 :重新编译发现/usr/bin/ld: /tmp/cct09ZN0.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC,只读数据段冲突了,需要使用-fPIC重新编译,-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时在内存的位置不是固定的
gcc -shared -I$JAVA_HOME/include hello.c -o libhello.so重新编译,终于生成了so
第三步,编写java文件
class Hello{
//申明jni接口
public native void hello();
static{
/**
我这里想看看java去哪里找so位置,然后想加入当前目录,结果发现没有,还是报错。
*/
String libPath = System.getProperty("java.library.path");
System.out.println(libPath);
libPath += ":.";
System.setProperty("java.library.path",libPath);
System.out.println(System.getProperty("java.library.path"));
//加载so
System.loadLibrary("hello");
}
public static void main(String[] args){
System.out.println(System.getProperty("java.library.path"));
new Hello().hello();
}
}
编译javac Hello.java ,运行java -cp . Hello
问题1 : 运行java -cp . Hello报错/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib:.
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)
at java.lang.Runtime.loadLibrary0(Runtime.java:849)
at java.lang.System.loadLibrary(System.java:1088)
找不到so,解决办法1拷贝so到/usr/java/packages/lib/amd64 , /usr/lib64, /lib64, /lib,/usr/lib中的任何一个目录都可以;2 java -Djava.library.path=/home/leo/jni/test Hello指定java运行时-D是指定环境变量java.library.path的值。
最后运行结果/home/leo/jni/test
/home/leo/jni/test:.
/home/leo/jni/test:.
Hello world jni !