JavaCPP,当本机库存档在 JAR 中时出现 UnsatisfiedLinkError

JavaCPP, UnsatisfiedLinkError when native library is archived in JAR

我正在尝试使用 JavaCPP to help create the necessary JNI binding, as already discussed in this question.

从 Java 调用 Haskell 代码

我是这样使用它的:

<rootdir>
  /javacpp.jar
  /build (destination of libraris)
  /src   (contains Haskell code)
  /com/example/HSCode.java (Java class to load and use native lib)

HScode.java的内容:

package com.example;

import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

@Platform(include={"<HsFFI.h>","HScode_stub.h"})
public class HScode {
    static { Loader.load(); }
    public static native void hs_init(int[] argc, @Cast("char***") @ByPtrPtr PointerPointer argv);
    public static native String code_hs(String text);

    public static void main(String[] args) throws FileNotFoundException {
        String s = new Scanner(new File("test.txt")).useDelimiter("\Z").next();
        hs_init(null, null);
        String s1 = code_hs(s);
        System.out.println(s1);
    }
}

编译:

cd <rootdir>
ghc --make -isrc -dynamic -shared -fPIC src/HScode.hs \
     -o build/libHScode.so -lHSrts-ghc7.8.4 -optl-Wl,-rpath,.
javac -cp javacpp.jar com/example/HScode.java
java -jar javacpp.jar -d build \
     -Dplatform.compiler=ghc -Dplatform.includepath="src:com/example" \
     -Dplatform.compiler.output="-optl-Wl,-rpath,. -optc-O3 -Wall build/libHScode.so -dynamic -fPIC -shared -lstdc++ -lHSrts-ghc7.8.4 -o " com.example.HScode

按照这种方法,我可以使用 javacpp 创建一个 libHScode.so 和一个 libjniHScode.so,运行 可以:

$ java -cp javacpp.jar:. com.example.HScode

罐子

现在,接下来的步骤是我想将所有内容打包到一个 jar 中,并能够在更大的 java 项目中使用这个 jar 的 com.example.HScode

JavaCPP 的页面提到:

[...] Moreover, at runtime, the Loader.load() method automatically loads the native libraries from Java resources, which were placed in the right directory by the building process. They can even be archived in a JAR file, it changes nothing. Users simply do not need to figure out how to make the system load the files.

所以我认为这应该可行。

但是,如果我用上面 build 文件夹的内容制作一个 jar HScode.jar,那么我的 jar 包含 libjniHScode.solibHScode.so,并且运行 它与:

$ java -cp javacpp.jar:HScode.jar:. com.example.HScode

然后它找不到我的本机代码(为匿名编辑的异常):

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jniHScode in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1865)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)
    at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:597)
    at org.bytedeco.javacpp.Loader.load(Loader.java:438)
    at org.bytedeco.javacpp.Loader.load(Loader.java:381)
    at com.example.HScode.<clinit>(HScode.java:13)
Caused by: java.lang.UnsatisfiedLinkError: /compilation-path/linux-x86_64/libjniHScode.so: HScode.so: cannot open shared object file: No such file or directory
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1937)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1822)
    at java.lang.Runtime.load0(Runtime.java:809)
    at java.lang.System.load(System.java:1086)
    at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:580)

我错过了什么?有谁知道 JavaCPP 归档在 jar 中时是否真的可以找到本机代码?

通过调用 javacpp -jar javacpp.jar com.example.HScode 构建本机库会自动在 com/example/linux-x86_64/ 中输出它们,然后 Loader 从那里加载它们。因此,当通过其他方式构建本机库时,如果我们想让 Loader 找到它们,它们仍然需要移动到 com/example/linux-x86_64/,无论是在 JAR 文件内部还是外部作为普通文件。