【隐私盘算篇】Java(JDK17)通过JNI实现调用C++动态链接库(.so) ...

张春  金牌会员 | 2024-8-21 10:53:29 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 571|帖子 571|积分 1713

在最近的工作中,须要通过Java调用C++的动态链接库(.so文件)。为此,我使用了Java的JNI(Java Native Interface)技能。我整理了一个简单的示例,供大家参考。
  
  JNI 是Java提供的一种机制,允许Java代码与本地应用步伐或库举行交互,尤其是那些用C或C++编写的库。这在须要与底层系统举行高效交互或调用现有的本地库时非常有效。
  
步骤1:创建工具静态库 (libcalc.a)

首先,我们编写一个简单的 cpp 文件(calc.cpp),这个文件包含一个执行加法运算的函数,然后将其编译成静态库。
calc.h
  
  1. // calc.h
  2. #ifndef CALC_H
  3. #define CALC_H
  4. class Calculator {
  5. public:
  6.     int add(int a, int b);
  7. };
  8. #endif // CALC_H
复制代码
calc.cpp
  
  1. // calc.cpp
  2. #include "calc.h"
  3. int Calculator::add(int a, int b) {
  4.     return a + b;
  5. }
复制代码
将这个文件编译成静态库: 
  
  1. g++ -c calc.cpp -o calc.o
  2. ar rcs libcalc.a calc.o
复制代码
这将生成一个名为 libcalc.a 的静态库文件。

步骤2:编写 Java 代码调用动态库 

接下来,使用 Java 17 编写一个类,加载动态库并调用本地方法。
CalcJNI.java
  
  1. public class CalcJNI {static {
  2.         System.loadLibrary("jni_add");
  3.     }
  4.     // 声明本地方法
  5.     public native int add(int a, int b);
  6.    
  7.     public static void main(String[] args) {
  8.     CalcJNI calc = new CalcJNI();
  9.     int result = calc.add(5, 3);
  10.     System.out.println("Result of 5 + 3 = " + result);
  11.     }
  12. }
复制代码

步骤3:生成 JNI 头文件 

从 JDK 10 开始,javah 已被弃用,我们可以直接使用 javac 的 -h 选项生成 JNI 头文件。
执行生成 JNI 头文件(CalcJNI.h)命令。
  
  1. javac -h . CalcJNI.java
复制代码
这会在当前目录生成 CalcJNI.h 文件,供我们在 C++ 代码中使用。

步骤4:创建桥接动态库 (libjni_add.so) 

接下来,我们编写一个动态库,动态库会链接到上面创建的静态库,并通过 JNI 袒露给 Java 使用。
jni_add.cpp
  
  1. #include <jni.h>
  2. #include "CalcJNI.h"  // 由 javah 生成的 JNI 头文件
  3. #include "calc.h"     // 包含静态库头文件
  4. JNIEXPORT jint JNICALL Java_CalcJNI_add(JNIEnv *env, jobject obj, jint a, jint b) {
  5.     Calculator calc;
  6.     return calc.add(a, b);
  7. }
复制代码
编译这个文件并生成动态库 
  
  1. g++ -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -c jni_add.cpp -o jni_add.o
  2. g++ -shared -o libjni_add.so jni_add.o -L. -lcalc
复制代码
上面的命令生成一个名为 libjni_add.so 的动态库文件。

步骤5:运行 Java 步伐 

最后,运行 Java 步伐:
  
  1. java CalcJNI
复制代码
如果一切顺遂,输出应该是:
  
  1. Result of 5 + 3 = 8
复制代码
小结

本次我们使用 C++ 实现了工具静态库和桥接动态库,并通过JNI与Java举行了集成。我们还使用了 JDK 17,并展示了怎样使用 javac 生成 JNI 头文件。
这套流程不仅支持更复杂的 C++ 功能,还能更好地与当代 Java 版本兼容。

改进代码组织结构

CMake管理代码组织结构

  
  1. project/
  2. ├── CMakeLists.txt
  3. ├── calc/            # 步骤1的静态库代码
  4. │   ├── CMakeLists.txt
  5. │   ├── calc.h
  6. │   └── calc.cpp
  7. ├── calc_jni/        # 步骤4的动态库及JNI封装代码
  8. │   ├── CMakeLists.txt
  9. │   ├── calc_jni_wrapper.h
  10. │   ├── calc_jni_wrapper.cpp
  11. │   ├── jni_add.cpp
  12. │   └── calc_jni.h   # 步骤3生成的头文件
  13. └── calc_project/    # 步骤2的Java代码
  14.     ├── CMakeLists.txt
  15.     ├── CalcJNI.java
  16.     ├── CalcTool.java
  17.     └── Demo.java
  18. # 需要事先定义CalcJNI接口,并通过javac生成calc_jni.h 头文件。
复制代码
外层的CMakeLists.txt

  
  1. cmake_minimum_required(VERSION 3.10)
  2. project(CalcProject)
  3. # 添加子目录
  4. add_subdirectory(calc)
  5. add_subdirectory(calc_jni)
  6. add_subdirectory(calc_project)
复制代码
 新建一个build.sh

  
  1. rm -rf build
  2. javac -h ./calc_jni ./calc_project/CalcJNI.java
  3. mkdir build
  4. cd build
  5. cmake ..
  6. cmake --build .
  7. cd calc_project
  8. java -Djava.library.path=../calc_jni -cp calc_project.jar Demo
复制代码
   
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表