UnsatisfiedLinkError in exported (Eclipse) executable jar file

你离开我真会死。 提交于 2019-12-01 17:15:09

问题


The code works fine when executing from Eclipse. I'm using OpenCV 2.4.11 and JavaFX for UI. When I export an Executable Jar from Eclipse and run it from cmd I get the following exception:

I followed many post here on SO and OpenCV forum(1, 2, 3, 4) but, none of the answers seems to help me.

I have added the OpenCV jar as library and Native Library is linked to /build/java/x64 as suggested in SO answers.

The exception occurs at the System.loadLibrary(Core.Native_Library_Name), I checked the Native_Library_Name and the OpenCV version is same as the one I imported in my project.

public class CustomFrame extends Application{

    @Override
    public void start(Stage primaryStage){
        Group root = new Group();
        Canvas canvas = new Canvas(1440, 840);

        ImageView imageView = new ImageView();
        imageView.setFitHeight(canvas.getHeight());
        imageView.setFitWidth(canvas.getWidth());
        new FrameController().startCamera(imageView);

        root.getChildren().addAll(imageView, canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    public static void main(String[] args)
    {
        // load the native OpenCV library
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        launch(args);
    }
}

If anybody thinks that I have missed something please do let me know.


回答1:


The UnsatisfiedLinkError is thrown when an application attempts to load a native library like

  1. .so in Linux,
  2. .dll on Windows or
  3. .dylib in Mac

and that library does not exist.

Specifically, in order to find the required native library, the JVM looks in both the PATH environment variable and the java.library.path system property.

Sometimes if the native library was already loaded by an application and the same application tries to load it again, this can cause this error also.


How to deal with the UnsatisfiedLinkError?

First of all we must verify that the parameter passed in the System.loadLibrary method is correct and that the library actually exists. Notice that the extension of the library is not required. Thus, if your library is named SampleLibrary.dll, you must pass the SampleLibrary value as a parameter.

Moreover, in case the library is already loaded by your application and the application tries to load it again, the UnsatisfiedLinkError will be thrown by the JVM. Also, you must verify that the native library is present either in the java.library.path or in the PATH environment library of your application. If the library still cannot be found, try to provide an absolute path to the System.loadLibrary method.

In order to execute your application, use the -Djava.library.path argument, to explicitly specify the native library. For example, using the terminal (Linux or Mac) or the command prompt (Windows), execute your application by issuing the following command:

java -Djava.library.path= "<path_of_your_application>" –jar <ApplicationJAR.jar>

You have missed the actual command. Use the following

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java\x64" -jar BlurDetector.jar

or

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java" -jar BlurDetector.jar

instead of your command

java -Djava.library.path="C:\Users\vivek_elango\Desktop" -jar BlurDetector.jar // you have given wrong path of your application



回答2:


It looks like you need to add the path containing the opencv-2411 native libraries to the -Djava.library.path when running from the command prompt.

So something like this:

java -Djava.library.path="C:\Opencv2.1.11\opencv\build\java\x64" -jar BlurDetector.jar



回答3:


In opposite to the other answers, I rather suggest you never use absolute paths, instead use relative ones. When you give your software to another user, the user most certainly won't have the libraries in the same path as you do. By using relative paths in regards to your application you guarantee that the software runs on other users systems as well, without them having to set path variables, jvm directives and what not. They don't even have to have OpenCV installed if you give them the library dll this way.

Here's code to load the libraries in a relative way:

public static void initOpenCv() {

    setLibraryPath();

    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

    System.out.println("OpenCV loaded. Version: " + Core.VERSION);

}

private static void setLibraryPath() {

    try {

        System.setProperty("java.library.path", "lib/x64");

        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);

    } catch (Exception ex) {
        ex.printStackTrace();
        throw new RuntimeException(ex);
    }

}

All you have to do is to

  • put the libraries into a lib/x64 folder relative to your jar file
  • in your application you have to invoke initOpenCv() at the start of your program

That's it. This way you can develop as before and maintain a distributable application.


Here's the full version:

import java.lang.reflect.Field;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import org.opencv.core.Core;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {

        initOpenCv();

        HBox root = new HBox();

        Label infoLabel = new Label();
        infoLabel.setText("OpenCV loaded. Version: " + Core.VERSION);

        root.getChildren().add(infoLabel);

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void initOpenCv() {

        setLibraryPath();

        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        System.out.println("OpenCV loaded. Version: " + Core.VERSION);

    }

    private static void setLibraryPath() {

        try {

            System.setProperty("java.library.path", "lib/x64");

            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);

        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

With a folder structure like this:

.\application.jar
.\lib\x64\*.dll

Hint: I packaged the opencv jar into the application.jar



来源:https://stackoverflow.com/questions/36780017/unsatisfiedlinkerror-in-exported-eclipse-executable-jar-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!