简体   繁体   English

在使用 JPMS Java 模块时,如何使用 JavaCPP 本机库解决 UnsatisfiedLinkError?

[英]How do I resolve UnsatisfiedLinkError with JavaCPP native libraries while using JPMS Java modules?

I have a Java 17 project using Gradle with a multitude of JavaCPP libraries.我有一个 Java 17 项目,使用 Gradle 和大量 JavaCPP 库。 I started with a simple demo project that I cloned from the JavaCPP Github repo.我从一个从 JavaCPP Github 存储库克隆的简单演示项目开始。 This sample project incorporates several native libs such as OpenCV, ffmpeg, etc., so I thought it'd be a good test.这个示例项目包含了几个原生库,例如 OpenCV、ffmpeg 等,所以我认为这是一个很好的测试。 And, no surprise, it worked just fine.而且,毫不奇怪,它工作得很好。 It brought up my camera, did the face detection, etc. All very cool.它打开了我的相机,进行了人脸检测等。一切都非常酷。

My aim - I want to modularize my JavaCPP projects to be JPMS compliant.我的目标 -我想模块化我的 JavaCPP 项目以符合 JPMS。

Not easy.不容易。 So, to troubleshoot, I figure that I would start with good test code, which is why I'm working with the official JavaCPP Gradle demo program.因此,为了排除故障,我想我会从好的测试代码开始,这就是我使用官方 JavaCPP Gradle 演示程序的原因。

So, I did the following to convert it to be JPMS compliant:因此,我执行了以下操作以将其转换为 JPMS 兼容:

  1. Created a module-info.java placed down src/main/java .src/main/java下创建了一个module-info.java I added the appropriate requires statements (see below).我添加了适当的requires声明(见下文)。
  2. Modified build.gradle to add several *-platform dependencies and a few other plugins, including JavaFX.修改build.gradle以添加几个*-platform依赖项和一些其他插件,包括 JavaFX。

The TL;DR - I got it to work (though the camera appears at an angle in the app window, which is just weird, but I'm assuming I'm still missing a library in module-info.java ).长话短说 - 我让它工作了(虽然相机在应用程序 window 中以一定角度出现,这很奇怪,但我假设我仍然缺少module-info.java中的库)。 The problem is that it only worked after I not only specified numerous additional *-platform dependencies in build.gradle , but also needed to list the actual native platform libraries in module-info.java .问题是它只有在我不仅在build.gradle中指定了许多额外的*-platform依赖项,而且还需要在module-info.java中列出实际的本机平台库之后才起作用。 So, for instance, I need to add the following statement:因此,例如,我需要添加以下语句:

requires org.bytedeco.opencv.macosx.x86_64;

If I do not do that, then I get the following error:如果我不这样做,则会收到以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no jniopencv_core in java.library.path: /Users/brk009/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.线程“main”中的异常 java.lang.UnsatisfiedLinkError:java.library.path 中没有 jniopencv_core:/Users/brk009/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System /图书馆/Java/扩展:/usr/lib/java:.

My main question - How can I make a modular JavaCPP project build and execute properly without hard coding the platform dependent native libraries in module-info.java ?我的主要问题 -如何在module-info.java中依赖于平台的本机库进行硬编码的情况下正确构建和执行模块化 JavaCPP 项目? I thought that just specifying the *-platform libraries in module-info.java would do it, but nope.我认为只需在module-info.java中指定*-platform库就可以了,但是不行。

If this was just a project for my own system, then fine - I'd live with it.如果这只是我自己系统的一个项目,那很好——我愿意接受它。 However, I want to pass some of my example code off to my students.但是,我想将我的一些示例代码传递给我的学生。 It'd be fine if they all ran Macs.如果他们都运行 Mac 就好了。 However, my students have quite a heterogeneous platform base (ie a mix of Mac, Windows, and Linux users.) Ideally, it'd be great to have a platform-independent codebase and let my program build and run regardless of the platform.然而,我的学生有相当多的平台基础(即 Mac、Windows 和 Linux 用户的混合体)。理想情况下,拥有一个独立于平台的代码库并让我的程序构建和运行而不管平台如何。 Heck, I'd even be happy if I only needed to specify the platform as a parameter for gradlew as a command-line argument, such as indicated here , where I could just specify -PjavacppPlatform=linux-x86_64 .哎呀,如果我只需要将平台指定为gradlew的参数作为命令行参数,我什至会很高兴,如此处 所示,我可以只指定-PjavacppPlatform=linux-x86_64 But that did not work either.但这也不起作用。

I did verify that Loader.Detector.getPlatform() returns the correct platform string, and Loader.getCacheDir() returns ~/.javacpp/cache as you would expect.我确实验证了Loader.Detector.getPlatform()返回正确的平台字符串,并且Loader.getCacheDir()返回 ~/.javacpp/cache 正如您所期望的那样。

Any help/guidance would be immensely appreciated.任何帮助/指导将不胜感激。 Thank you kindly.非常感谢你。


module-info.java模块信息.java

module HelloJavaCPP {
    requires java.base;
    requires java.desktop;
    requires org.bytedeco.javacpp;
    requires org.bytedeco.javacpp.macosx.x86_64;  // I do NOT WANT to hard code any platform!
    requires org.bytedeco.javacv;
    requires org.bytedeco.opencv;
    requires org.bytedeco.opencv.macosx.x86_64;
    requires org.bytedeco.ffmpeg;
    requires org.bytedeco.ffmpeg.macosx.x86_64;
    requires org.bytedeco.openblas;
    requires org.bytedeco.openblas.macosx.x86_64;
}

build.gradle build.gradle

plugins {
    id 'application'
    id 'java'
    id 'java-library'
    id 'org.openjfx.javafxplugin' version '0.0.12'
    id 'org.javamodularity.moduleplugin' version '1.8.10'
    id 'org.bytedeco.gradle-javacpp-platform' version '1.5.7'
}

group = 'org.hello'
version = '1.5.7'

repositories {
    mavenLocal()
    mavenCentral()
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

javafx {
    version = "17.0.2"
    modules = [ 'javafx.graphics','javafx.controls', 'javafx.fxml' ]
}

dependencies {
    api "org.bytedeco:javacv-platform:1.5.7"
    api 'org.bytedeco:opencv-platform:4.5.5-1.5.7'
//    api "org.bytedeco:opencv-platform-gpu:4.5.5-$version"
    api "org.bytedeco:ffmpeg-platform-gpl:5.0-$version"
    api 'org.bytedeco:openblas-platform:0.3.19-1.5.7'
    testImplementation 'junit:junit:4.13.2'
}

application {
    mainModule = "$moduleName"
    mainClass = "org.hello.Demo"
}


settings.gradle I'm including this just incase. settings.gradle我包括这个以防万一。

pluginManagement {
    repositories {
        mavenLocal()
        mavenCentral()
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
        gradlePluginPortal()
    }
}

rootProject.name = 'HelloJavaCPP'

gradle.rootProject { ext.javacppVersion = '1.5.7' }

Those links posted by Samuel above were immensely helpful. Samuel 上面发布的那些链接非常有帮助。 It turns out there are some modularity peculiarities with JavaFX that can wreck havoc when using JavaFX with non-JavaFX modules such as those in JavaCPP.事实证明,JavaFX 存在一些模块化特性,当将 JavaFX 与非 JavaFX 模块(例如 JavaCPP 中的模块)一起使用时,这些特性可能会造成严重破坏。 See here .这里

The key part that was important:重要的关键部分:

We can either use the run goal of the JavaFX Maven plugin, the java goal of the Exec Maven plugin, or manually launch java with a module path computed from Maven dependencies and option --add-modules ALL-MODULE-PATH .我们可以使用 JavaFX Maven 插件的运行目标,Exec Maven 插件的 java 目标,或者使用从 Maven 依赖项和选项计算的模块路径手动启动 java 和选项--add-modules ALL-MODULE-PATH DULE-DUPALETHPA

Once I figured out how to add a JVM argument in Gradle, I was able to remove all hard-coded architecture requires statements, and I can now use gradlew run , let JavaCPP's Loader class do all the work of discovering the architecture itself and loading the appropriate native libraries!一旦我弄清楚如何在 Gradle 中添加一个 JVM 参数,我就能够删除所有硬编码的体系结构requires语句我现在可以使用gradlew run ,让 JavaCPP 的Loader class 完成发现体系结构本身和加载合适的原生库!

The two most important files that need to change:需要更改的两个最重要的文件:


module-info.java模块信息.java

Notice how much simpler this becomes, and it has NO hard-coded platform system architecture information, which is exactly what we want:请注意这变得多么简单,并且它没有硬编码的平台系统架构信息,这正是我们想要的:

module HelloJavaCPP {
    requires java.base;
    requires java.desktop;
    requires org.bytedeco.javacpp;
    requires org.bytedeco.javacv;
    requires org.bytedeco.opencv;
    requires org.bytedeco.ffmpeg;
    requires org.bytedeco.openblas;
}

build.gradle build.gradle

The most important change I needed to make (which I got from information posted here was to add a run configuration, and specify the JVM argument `--add-modules我需要做的最重要的改变(我从这里发布的信息中得到的是添加一个run配置,并指定 JVM 参数 `--add-modules

plugins {
    id 'application'
    id 'java'
    id 'java-library'
    id 'org.openjfx.javafxplugin' version '0.0.12'
    id 'org.javamodularity.moduleplugin' version '1.8.10'
    id 'org.bytedeco.gradle-javacpp-platform' version "$javacppVersion"
}

group = 'org.hello'
version = '1.5.7'

repositories {
    mavenCentral()
}

ext {
    // javacppPlatform - should be autodetected, but can also specify on cmd line
    // as -PjavacppPlatform=macosx-x86_64
//    javacppPlatform = 'linux-x86_64,macosx-x86_64,windows-x86_64,etc' // defaults to Loader.getPlatform()
    javacppPlatform = 'macosx-x86_64' // defaults to Loader.getPlatform()
}

javafx {
    version = "17.0.2"
    modules = [ 'javafx.graphics','javafx.controls', 'javafx.fxml' ]
}

dependencies {
    api "org.bytedeco:javacpp-platform:$javacppVersion"
    api "org.bytedeco:javacv-platform:$javacppVersion"
    api "org.bytedeco:opencv-platform:4.5.5-1.5.7"
    api "org.bytedeco:ffmpeg-platform-gpl:5.0-1.5.7"
    api "org.bytedeco:openblas-platform:0.3.19-1.5.7"
    testImplementation 'junit:junit:4.13.2'
}

application {
    mainModule = "$moduleName"
    mainClass = "org.hello.Demo"
}

// THIS WAS THE PRIMARY CHANGE: 
run {
    jvmArgs = ['--add-modules', 'ALL-MODULE-PATH']
}

It's worth noting that I was able to remove the ext configuration in build.gradle , which allows Loader.getPlatform() to do the work of determining the platform at runtime, and it worked just fine.值得注意的是,我能够删除build.gradle中的ext配置,它允许Loader.getPlatform()在运行时完成确定平台的工作,并且它工作得很好。 (I left it in place just for reference purposes.) (我把它留在原地仅供参考。)

I hope this helps others.我希望这对其他人有帮助。 I did NOT test out building an image, as judging from what I read, that is quite an additional level of complexity.我没有测试构建图像,从我读到的内容来看,这是一个额外的复杂程度。 We'll tackle that another time.我们下次再解决这个问题。

Thank you again.再次感谢你。

暂无
暂无

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

相关问题 java.lang.UnsatisfiedLinkError:org.bytedeco.javacpp.avutil在android中使用“gpuImage”和“javacv” - java.lang.UnsatisfiedLinkError: org.bytedeco.javacpp.avutil while using “gpuImage” with “javacv” in android 如何解决此 UnsatisfiedLinkError? - How do I resolve this UnsatisfiedLinkError? 如何使用JavaCpp将函数调用从c ++映射到Java? - How do I map a function call from c++ to Java using JavaCpp? 将本机库与 Tomcat 9 与多个 webapp 一起使用 - java.lang.UnsatisfiedLinkError - Using native libraries with Tomcat 9 with multiple webapps - java.lang.UnsatisfiedLinkError 使用Java 9模块时的java.lang.NoSuchMethodError(JPMS) - java.lang.NoSuchMethodError when using Java 9 modules (JPMS) 我应该如何为JNI加载本机库以避免出现UnsatisfiedLinkError? - How should I load native libraries for JNI to avoid an UnsatisfiedLinkError? 运行 javacpp 时出现 java.lang.UnsatisfiedLinkError - java.lang.UnsatisfiedLinkError when run javacpp 我如何获取我的Java程序以在Linux中正确导入Javacv库(编辑-现在变得不满意LinkError) - How do i get my java program to import the javacv libraries properly in linux (EDIT - now getting unsatisfiedLinkError) 如何在 JPMS 中使用动态创建的层执行“--add-modules”? - How to do "--add-modules" with dynamically created layer in JPMS? 如何使用 Maven 和 NetBeans 将 package 应用程序应用到 JPMS 模块中? - How to package an application into JPMS modules using Maven and NetBeans?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM