JavaCPP, UnsatisfiedLinkError when native library

2019-02-26 22:18发布

问题:

I'm trying to call Haskell code from Java, using JavaCPP to help create the necessary JNI binding, as already discussed in this question.

This is how I'm using it:

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

Content of 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);
    }
}

Compilation:

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

Following this approach, I can create a libHScode.so and a libjniHScode.so using javacpp, which runs fine with:

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

Jar

Now, the following step is that I want to package everything in a jar, and be able to use this jar's com.example.HScode from a larger java project.

JavaCPP's page mentions:

[...] 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.

So I thought this should work.

However, if I make a jar HScode.jar out of the content of the build folder above, so that my jar contains both libjniHScode.so and libHScode.so, and run it with:

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

then it cannot find my native code (exception edited for anonymization):

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)

What am I missing? Does anyone know whether JavaCPP can actually find the native code when it's archived in a jar?

回答1:

Building for the native libraries by calling javacpp -jar javacpp.jar com.example.HScode outputs them in com/example/linux-x86_64/ automatically and the Loader loads them from there. So when building the native libraries by some other means, they still need to be moved to com/example/linux-x86_64/, whether inside a JAR file or outside as normal files, if we want the Loader to find them.