简体   繁体   English

导出的(Eclipse)可执行jar文件中的UnsatisfiedLinkError

[英]UnsatisfiedLinkError in exported (Eclipse) executable jar file

The code works fine when executing from Eclipse. 从Eclipse执行时,代码工作正常。 I'm using OpenCV 2.4.11 and JavaFX for UI. 我正在使用OpenCV 2.4.11和JavaFX for UI。 When I export an Executable Jar from Eclipse and run it from cmd I get the following exception: 当我从Eclipse导出可执行Jar并从cmd运行它时,我得到以下异常:

在此输入图像描述

I followed many post here on SO and OpenCV forum( 1 , 2 , 3 , 4 ) but, none of the answers seems to help me. 我跟很多张贴在这里的SO和OpenCV论坛( 1234 ),但是,没有一个答案似乎帮助我。

I have added the OpenCV jar as library and Native Library is linked to /build/java/x64 as suggested in SO answers. 我已经将OpenCV jar添加为库,而Native Library链接到/ build / java / x64,如SO答案中所建议的那样。

Java构建路径

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. System.loadLibrary(Core.Native_Library_Name)发生异常,我检查了Native_Library_Name,OpenCV版本与我在项目中导入的版本相同。

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. 如果有人认为我错过了什么,请告诉我。

The UnsatisfiedLinkError is thrown when an application attempts to load a native library like 当应用程序尝试加载本机库时,抛出UnsatisfiedLinkError

  1. .so in Linux, .so在Linux中,
  2. .dll on Windows or Windows上的.dll
  3. .dylib in Mac Mac中的.dylib

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. 具体来说,为了找到所需的本机库,JVM同时查找PATH environment variablejava.library.path系统属性。

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? 如何处理UnsatisfiedLinkError?

First of all we must verify that the parameter passed in the System.loadLibrary method is correct and that the library actually exists. 首先,我们必须验证System.loadLibrary方法中传递的参数是否正确并且库实际存在。 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. 因此,如果您的库名为SampleLibrary.dll ,则必须将SampleLibrary值作为参数传递。

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. 此外,如果应用程序已加载库并且应用程序尝试再次加载它,则JVM将抛出UnsatisfiedLinkError 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. 此外,您必须验证本机库是否存在于应用程序的java.library.pathPATH environment library中。 If the library still cannot be found, try to provide an absolute path to the System.loadLibrary method. 如果仍无法找到库,请尝试提供System.loadLibrary方法的绝对路径。

In order to execute your application, use the -Djava.library.path argument, to explicitly specify the native library. 要执行应用程序,请使用-Djava.library.path参数显式指定本机库。 For example, using the terminal (Linux or Mac) or the command prompt (Windows), execute your application by issuing the following command: 例如,使用终端(Linux或Mac)或命令提示符(Windows),通过发出以下命令来执行您的应用程序:

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

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. 从命令提示符运行时,您似乎需要将包含opencv-2411本机库的路径添加到-Djava.library.path

So something like this: 所以像这样:

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

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. 通过使用与应用程序相关的相对路径,您可以保证软件也可以在其他用户系统上运行,而无需设置路径变量,jvm指令等等。 They don't even have to have OpenCV installed if you give them the library dll this way. 如果你以这种方式给他们库dll,他们甚至不必安装OpenCV。

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 将库放入相对于jar文件的lib / x64文件夹中
  • in your application you have to invoke initOpenCv() at the start of your program 在您的应用程序中,您必须在程序开始时调用initOpenCv()

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 提示:我将opencv jar打包到application.jar中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM