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

Ale*_*x B 95 java java-native-interface jar clojure tokyo-cabinet

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

我想要在一个JAR文件中包含本机库,JNI库和所有Java API类,以避免重新分发问题.

似乎在GitHub尝试了这个,但是

  1. 它不包括实际的本机库,只包括JNI库.
  2. 它似乎特定于Leiningen的native dependencies插件(它不能用作可再发行的插件).

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

PS:是的,我意识到它可能具有可移植性的含义.

小智 43

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

流程如下:

  • 在平台特定位置的JAR文件中包含本机JNI库,例如在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库。


dav*_*avs 38

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 使用NativeUtils.loadLibraryFromJar("/ natives /"+ System.mapLibraryName("crypt")); 有待改善 (22认同)

Eva*_*van 16

看看One-JAR.它将你的应用程序包装在一个jar文件中,该文件包含一个专门的类加载器,它可以处理"jars in jars"等等.

它通过根据需要将它们解压缩到临时工作文件夹来处理本机(JNI)库.

(免责声明:我从来没有使用过One-JAR,还没有使用它,只是在下雨的时候给它添加了书签.)


tek*_*ara 5

JarClassLoader是一个类加载器,用于从单个怪物JAR和怪物JAR内的JAR加载类,本机库和资源.


lev*_*tov 5

1)将本机库作为资源包含在您的JAR中。例如 使用Maven或Gradle以及标准项目布局,将本机库放入main/resources目录中。

2)在与此库相关的Java类的静态初始化程序中的某个地方,将代码如下所示:

String libName = "myNativeLib.so"; // The name of the file in resources/ dir
URL url = MyClass.class.getResource("/" + libName);
File tmpDir = Files.createTempDirectory("my-native-lib").toFile();
tmpDir.deleteOnExit();
File nativeLibTmpFile = new File(tmpDir, libName);
nativeLibTmpFile.deleteOnExit();
try (InputStream in = url.openStream()) {
    Files.copy(in, nativeLibTmpFile.toPath());
}
System.load(nativeLibTmpFile.getAbsolutePath());
Run Code Online (Sandbox Code Playgroud)