我正在发布一个使用 OpenCV 作为单个可执行 jar 的应用程序。为了避免最终用户需要在自己的系统上下载 OpenCV,OpenCV 二进制文件存储在 jar 内,并提取到临时文件,并使用
System.load()
和临时文件路径加载,按照 this stackoverflow post suggest,如下如下:
public class NativeLibraryLoader {
private static Logger logger = LogManager.getLogger();
/**
* This is a safe way to load a native library from a jar, assuming that library
* is inside your resource director/classpath.
*/
public static void loadLibraryFromJar(String libraryName) throws IOException {
logger.debug("Loading native library %s".formatted(libraryName));
InputStream is = NativeLibraryLoader.class.getResourceAsStream("/" + libraryName);
File library = File.createTempFile("jni-temp-file", "tmp");
library.deleteOnExit();
try (OutputStream os = new FileOutputStream(library)) {
logger.debug("Copying library input stream to temp file " + library.getPath());
os.write(is.readAllBytes());
}
logger.debug("Loading library " + library.getPath());
System.load(library.getPath().replace("\\", "/"));
}
}
当我加载
opencv_490.so
时,此方法在Linux上运行得很好。库加载,我可以使用 OpenCV。但是,当使用 opencv_490.dll
在 Windows 上运行相同的命令时,它找不到该库,并且我得到 UnsatisfiedLink。 loadLibraryFromJar
方法在调用 System.load()
时抛出错误,并在单元测试期间产生以下错误:
[ERROR] Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.188 s <<< FAILURE! - in com.toughdata.autogrowth.TestOpenCVCaptchaProcessor
[ERROR] testSolveRotateCaptchaIsKnownValue Time elapsed: 0.187 s <<< ERROR!
java.lang.UnsatisfiedLinkError: C:\Users\greg\AppData\Local\Temp\jni-temp-file78576686543799615tmp: Can't find dependent libraries
at com.toughdata.autogrowth.TestOpenCVCaptchaProcessor.testSolveRotateCaptchaIsKnownValue(TestOpenCVCaptchaProcessor.java:16)
[ERROR] testSolvePuzzleCaptchaIsKnownValue Time elapsed: 0 s <<< ERROR!
java.lang.NoClassDefFoundError: Could not initialize class com.toughdata.autogrowth.automation.captcha.OpenCVCaptchaProcessor
at com.toughdata.autogrowth.TestOpenCVCaptchaProcessor.testSolvePuzzleCaptchaIsKnownValue(TestOpenCVCaptchaProcessor.java:24)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.UnsatisfiedLinkError: C:\Users\greg\AppData\Local\Temp\jni-temp-file78576686543799615tmp: Can't find dependent libraries [in thread "main"]
at com.toughdata.autogrowth.TestOpenCVCaptchaProcessor.testSolveRotateCaptchaIsKnownValue(TestOpenCVCaptchaProcessor.java:16)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR] TestOpenCVCaptchaProcessor.testSolvePuzzleCaptchaIsKnownValue:24 NoClassDefFound
[ERROR] TestOpenCVCaptchaProcessor.testSolveRotateCaptchaIsKnownValue:16 » UnsatisfiedLink
[INFO]
[ERROR] Tests run: 19, Failures: 0, Errors: 2, Skipped: 8
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.035 s
[INFO] Finished at: 2024-03-11T09:04:46+11:00
[INFO] ------------------------------------------------------------------------
我可以看到临时文件已创建,并且库已提取并写入临时文件。有谁知道什么可能导致在 Linux 上正常工作时对
System.load()
的调用在 Windows 上失败?
好吧,我能弄清楚这一点。在创建临时文件时,我冒险将
tmp
扩展名更改为 .dll
。事实证明,Windows 希望库以 .dll
文件扩展名结尾。 Linux 不关心你的库是否以 .so
结尾,但在 Windows 上它们必须以 .dll
结尾