1、前言
-
这篇博客是关于如何使用Java的JNI技术完成so文件的创建,并且在linux系统下调用出现的一些坑和解决的办法
-
主要遇到的坑:
- Java文件中没有去掉包名,报了找不到的错误
- .c文件中可以直接在里面写关于jni的函数代码,然后去调用上面的c程序函数就行
- 报了undefined symbol的错,并且用ldd -r去查找了缺失的具体函数名,是sin,cos等基础的,最后在编译时加上-lm就行,主要参考这篇博客:https://bbs.csdn.net/topics/390290096
2、整体步骤
- 需要准备的文件,.c文件,.java文件
2.1、.java文件
-
public class Hello { static { System.loadLibrary("goodluck"); } public native double maxValue(String address); public static void main(String[] args) { Hello hello = new Hello(); double res = hello.maxValue("/myprojects/mytest/data.txt"); System.out.println(res); } }
这里的路劲地址是传入的自己放在linux下的文件地址,写自己的就行
2.2、.c文件
-
#include <stdio.h> #include "jni.h" #include "math.h" ... ... // 中间是C语言代码 ... ... jdouble Java_Hello_maxValue(JNIEnv* env, jobject obj, jstring address){ char* add = (char*)(*env)->GetStringUTFChars(env, address, NULL); double res = maxValue(add); // 调用上面的C语言代码的函数 (*env)->ReleaseStringUTFChars(env, address, add); return res; }
-
这里就是直接调用上面C语言代码中关于maxValue的函数,注意类型转换就好,具体的类型转换参考下面这篇博客:https://xuexiangjys.blog.csdn.net/article/details/83115117,注意函数名和参数返回值就行,实在不会的可以找找其他关于这方面的资料或者私信我,我也不是很懂,看缘分解决。
2.3、操作(在linux系统下)
-
我用的Xshell和Xftp
-
将这两个文件丢掉一个文件夹下,如果之前java文件里面有package xxx的话要创建对应的文件夹,不然的话删掉也行
-
依次运行如下命令
-
javah Hello # Hello是.java文件的名字,也就是类名,这里是生成头文件 javac Hello.java # 这里是编译生成class文件 gcc -lm -fpic -D_REENTRANT -I /environments/java/jdk1.8.0_311/include/ -I /environments/java/jdk1.8.0_311/include/linux/ -c Hello.c -std=c99 # 这里是调用自己安装的java路径下的头文件,编译生成.o文件,注意要加-lm,这里我也不清楚加不加,但加了是不报错的,这里std=c99是c语言代码中的问题,会报一个c99mode的错误,加上这个就好了 gcc -lm -shared Hello.o -o libgoodluck.so # 这里是生成.so文件,注意要lib打头,并且后面的名字是上面System.loadLibrary里面的名字,注意加-lm,加了不报错 export LD_LIBRARY_PATH=. # 这里是让自己的so文件能找到,不然会报下面的错
这里应该有永久性的方法,具体的去搜搜,我这里就简单处理一下了
-
java Hello # 运行,调用Hello里面的main方法
-
3、undefined symbol的问题
-
问题还原:
-
解决方案:就是我上面操作步骤中在gcc编译的时候加上
-lm