Linux 下 JNA 調用動態連接庫文件 so

  1. JNA

JNA(Java Native Access )提供一組 Java 工具類用於在運行期動態訪問系統本地庫(native library:如 Window 的 dll)而不需要編寫任何 Native/JNI 代碼。開發人員只要在一個 java 接口中描述目標 native library 的函數與結構,JNA 將自動實現 Java 接口到 native function 的映射。

https://github.com/java-native-access/jna 
https://java-native-access.github.io/jna/5.3.0/javadoc/

JNA 可以讓你像調用一般 java 方法一樣直接調用本地方法。就和直接執行本地方法差不多,而且調用本地方法還不用額外的其他處理或者配置什麼的,也不需要多餘的引用或者編碼,使用很方便。

JNA 類庫使用一個很小的本地類庫 sub 動態的調用本地代碼。程序員只需要使用一個特定的 java 接口描述一下將要調用的本地代碼的方法的結構和一些基本屬性。這樣就省了爲了適配多個平臺而大量的配置和編譯代碼。因爲調用的都是 JNA 提供的公用 jar 包中的接口。

JNA 是建立在 JNI 技術基礎之上的一個 Java 類庫,原來使用 JNI,你必須手工用 C 寫一個動態鏈接庫,在 C 語言中映射 Java 的數據類型。JNA 中,它提供了一個動態的 C 語言編寫的轉發器,可以自動實現 Java 和 C 的數據類型映射。你不再需要編寫 C 動態鏈接庫。當然,這也意味着,使用 JNA 技術比使用 JNI 技術調用動態鏈接庫會有些微的性能損失。可能速度會降低幾倍。但影響不大。

其實很多情況下,jna.jar 就完全滿足一般項目開發的需要了,比如數據 類型的映射和常用的方法等等,這些 C/C++ 中基礎的映射已經可以實現,包括一些基本的平臺方法,但是,真實涉及到比較深入的平臺方法的時候,就需要 platform.jar 的幫助了,platform.jar 是依賴於 jna.jar 實現的,包括了 FileMonitor、FileUtils、KeyboardUtils、WindowUtil 等 Win32 和平臺相關的簡化動態訪問功能類中的大部分常用方法,爲開發者開發自己的跨平臺映射方法提供參考。

所以platform.jar對於jna.jar是一種補充和擴展,jna.jar相當於核,platfrorm.jar相當於增量插件。

  1. JNA 使用

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.13.0</version>
</dependency>

使用的函數必須與鏈接庫中的函數原型保持一致,這是 JNA 甚至所有跨平臺調用的難點,因爲 C/C++ 的類型與 Java 的類型是不一樣的,必須轉換成 java 對應類型讓它們保持一致,這就是類型映射(Type Mappings),JNA 官方給出的默認類型映射表如下:

其中類型映射的難點在於結構體、指針和函數回調。

#ifndef _TestJna_h
#define _TestJna_h

#ifdef __cplusplus
extern "C" {
#endif

    int add(int a, int b);

    int sub(int a, int b);

#ifdef __cplusplus
}
#endif
#endif
#include "TestJna.h"

extern "C" int add(int a, int b){
  return a+b;
}
     
extern "C" int sub(int a, int b){
 return a-b;
}

**注意:**一定要加extern "C"否則生成的方法名跟 cpp 文件定義的方法名不一致。

查看 so 方法名

nm -D libTestJnaEx.so | grep add
nm -D libTestJnaEx.so | grep sub
g++ TestJna.cpp -fPIC  -shared -o libTestJnaEx.so
cp libTestJnaEx.so /usr/lib
import com.sun.jna.Library;
import com.sun.jna.Native;

public class TestJnaEx {
 
 public interface CLibrary extends Library {
  CLibrary INSTANCE = (CLibrary) Native.load("TestJnaEx", CLibrary.class);

  int add(int a, int b);
  
  int sub(int a, int b);
 }

 public static void main(String[] args) {
  int sum = CLibrary.INSTANCE.add(2, 3);
  System.out.println(sum);
  
  int diff = CLibrary.INSTANCE.sub(5, 3);
  System.out.println(diff);
 }
 
}

導出可執行 jar 文件TestJnaEx.jar

java -jar TestJnaEx.jar

結果

師傅領進門,修行在個人。

參考
https://blog.csdn.net/y666666y/article/details/128303464
https://www.javacui.com/java/520.html
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/jo6ALehyy6FOak1LGb44zA