如何将本机库和 JNI 库捆绑在 JAR 中?

有问题的图书馆是东京内阁

我想要的是将本机库,JNI库和所有Java API类放在一个JAR文件中,以避免重新分发问题。

在GitHub上似乎有这方面的尝试,但是

  1. 它不包括实际的本机库,仅包括 JNI 库。
  2. 它似乎特定于Leiningen的本机依赖项插件(它不会作为可再发行组件工作)。

问题是,我可以将所有内容捆绑在一个JAR中并重新分发它吗?如果是,如何?

P.S.:是的,我意识到它可能具有可移植性影响。


答案 1

可以创建单个 JAR 文件,其中包含所有依赖项,包括一个或多个平台的本机 JNI 库。基本机制是使用 System.load(File) 来加载库,而不是搜索 java.library.path 系统属性的典型 System.loadLibrary(String)。此方法使安装变得更加简单,因为用户不必在其系统上安装 JNI 库,但代价是可能不支持所有平台,因为平台的特定库可能不包含在单个 JAR 文件中。

流程如下:

  • 将本机 JNI 库包含在特定于平台的 JAR 文件中,例如 NATIVE/${os.arch}/${os.name}/libname.lib
  • 在主类的静态初始化器中创建代码以
    • 计算当前的 os.arch 和 os.name
    • 使用 Class.getResource(String) 在 JAR 文件中的预定义位置查找库
    • 如果存在,请将其解压缩到临时文件,并使用 System.load(File) 加载它。

我为jzmq添加了功能,即ZeroMQ(无耻插件)的Java绑定。代码可以在这里找到。jzmq 代码使用混合解决方案,因此,如果无法加载嵌入式库,代码将恢复为沿 java.library.path 搜索 JNI 库。


答案 2

https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/

是很棒的文章,它解决了我的问题..

在我的情况下,我有以下代码用于初始化库:

static {
    try {
        System.loadLibrary("crypt"); // used for tests. This library in classpath only
    } catch (UnsatisfiedLinkError e) {
        try {
            NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR
        } catch (IOException e1) {
            throw new RuntimeException(e1);
        }
    }
}

推荐