JNA加载存在多个依赖的so动态库
之前记录过在windows上加载单个ddl动态库(JNA简单使用(一)(java和c++互操作) - 浪迹天涯的派大星 - 博客园 (cnblogs.com)),这次记录一下在linux上调用存在多个依赖的so动态库。
1、背景
需要c++分片处理一种特殊格式的文件,Java接受分片数据后保存,采用JNA的方式调用c++动态库的方式实现。
2、Java代码
注:此处Java精简了逻辑,只为简单体现JNA调用c++的方式
2.1、Library接口代码
区别之一:load动态库时,windows上ddl不用写后缀,linux上so需要写后缀
import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.WString; public interface SlicerLibrary extends Library { SlicerLibrary LIBRARY = Native.load("libEnv.so", SlicerLibrary.class); /** * 初始化环境 * * @return 是否成功 */ boolean initSlice(); /** * 通知c++清除缓存 */ void freeSliceCache(); /** * 文件分片完成,释放资源 */ void unInitSlice(); /** * 获取分片数据 * * @param filePath 完整文件路径 * @param objCounts 每个分片文件包含的实体数量 * @return 总的分片个数 */ Integer fileSlice(WString filePath, int objCounts); /** * 获取序列号index的分片大小 * * @param index * @return 分片大小(单位byte) */ int getSliceBufferLength(int index); /** * 获取分片数据的字节数组 * * @param index 分片序号 * @param pSliceBuffer 分片数据 * @return 是否成功 */ boolean getSliceBuffer(int index, Pointer pSliceBuffer); }
2.2、调用动态库的Java代码
import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.WString; public class SlicerService { /** * 每个分片中包含的实体数量 */ private static final int objCountsPerPackage = 100; /** * 静态变量,确保不会被JVM垃圾回收 */ private static SlicerLibrary library = null; /** * 初始化动态库标志位 */ private static boolean initFlag = false; public void saveSliceFile(String filePath) { //初始化动态库 initSliceLibrary(); //c++对应的数据类型是w_chat WString path = new WString(filePath); //获取分片数量 Integer count = library.fileSlice(path, objCountsPerPackage); //循环处理所有的分片 if (count != null && count > 0) { for (int i = 0; i < count; i++) { //获取每个分片文件的数据长度 int size = library.getSliceBufferLength(i); //分配内存大小 Pointer buffer = new Memory(size); try { if (library.getSliceBuffer(i, buffer)) { //获取数据 byte[] data = buffer.getByteArray(0, size); //保存数据 saveData(data); } } finally { //清除分配的内存 Native.free(Pointer.nativeValue(buffer)); //避免GC时,重复调用Native.free().而导致程序异常退出 Pointer.nativeValue(buffer, 0L); //引用置空,便于垃圾回收 buffer = null; } } } } /** * 初始化动态库 */ private void initSliceLibrary() { if (!initFlag) { library = SlicerLibrary.LIBRARY; synchronized (this) { if (!initFlag) { initFlag = library.initSlice(); } } } } /** * 保存实际数据 * * @param data */ private void saveData(byte[] data) { //省略保存逻辑 } }
3、需要依赖的其他动态库的存放位置
将依赖的动态库,存放在linux服务器的任意文件夹下,然后将文件夹路径,配置进LD_LABRARY_PATH。
例如:/home/test,假设Java需要加载的入口so动态库是test1.so,c++文件工程结构如下:
则应该执行:
export LD_LABRARY_PATH=$LD_LABRARY_PATH:/home/test:/home/test/folder1:/home/test/folder2
注:$LD_LABRARY_PATH的作用是防止之前已经配置的路径被覆盖,在后面增加新的路径即可,多个文件夹路径通过冒号(:)分割。
4、export和LD_LABRARY_PATH说明
4.1、LD_LABRARY_PATH
LD_LABRARY_PATH是用于指定动态链接器(ld)查找ELF可执行文件运行时所依赖的动态库(so)的路径。即用于在程序运行期间查找动态链接库时,指定除了系统默认路径(/usr/lib)之外的路径。
LD_LABRARY_PATH,无法识别文件夹里面的子文件夹,子文件夹需要单独配置
4.2、export
Linux中,export
命令用于新增、修改和删除Linux上的环境变量(对PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH),只针对当前用户当前窗口登录有效,新开窗口需要重新执行;
如果要使其永久生效,则需要在linux环境变量中配置,编辑vim ~/.bashrc
,增加export语句,然后source ~/.bashrc
,使其立即生效。
参考:1、Linux中修改环境变量及生效方法(永久、临时)环境变量查看_linux 激活环境变量
2、Linux中PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH的区别_ld_library_path library_path 区别
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通