Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.lang.UnsatisfiedLinkError: no jniopenblas_nolapack in java 11 #1435

Open
jkolobok opened this issue May 30, 2020 · 61 comments
Open

java.lang.UnsatisfiedLinkError: no jniopenblas_nolapack in java 11 #1435

jkolobok opened this issue May 30, 2020 · 61 comments

Comments

@jkolobok
Copy link

java 11
macos 10.14.6

Warning: Could not load Loader: java.lang.UnsatisfiedLinkError: no jnijavacpp in java.library.path: [/Users/jkolobok/Library/Java/Extensions, /Library/Java/Extensions, /Network/Library/Java/Extensions, /System/Library/Java/Extensions, /usr/lib/java, .]
Exception in thread "main" java.lang.UnsatisfiedLinkError: no jniopenblas_nolapack in java.library.path: [/Users/jkolobok/Library/Java/Extensions, /Library/Java/Extensions, /Network/Library/Java/Extensions, /System/Library/Java/Extensions, /usr/lib/java, .]
	at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2660)
	at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:827)
	at java.base/java.lang.System.loadLibrary(System.java:1871)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1631)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.load(Loader.java:1265)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.load(Loader.java:1109)
	at org.bytedeco.openblas/org.bytedeco.openblas.global.openblas_nolapack.<clinit>(openblas_nolapack.java:12)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:398)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.load(Loader.java:1176)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.load(Loader.java:1125)
	at org.bytedeco.javacv/org.bytedeco.javacv.OpenCVFrameConverter.<clinit>(OpenCVFrameConverter.java:43)
	at org.bytedeco.javacv/org.bytedeco.javacv.OpenCVFrameGrabber.<init>(OpenCVFrameGrabber.java:95)
	at recorder/recorder.DesktopRecorder.main(DesktopRecorder.java:11)
Caused by: java.lang.UnsatisfiedLinkError: no openblas_nolapack in java.library.path: [/Users/jkolobok/Library/Java/Extensions, /Library/Java/Extensions, /Network/Library/Java/Extensions, /System/Library/Java/Extensions, /usr/lib/java, .]
	at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2660)
	at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:827)
	at java.base/java.lang.System.loadLibrary(System.java:1871)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1631)
	at org.bytedeco.javacpp/org.bytedeco.javacpp.Loader.load(Loader.java:1213)
	... 9 more

Sample project:
javafxsample.zip
Workaround - remove module-info.java.. and it starts working...

@saudet
Copy link
Member

saudet commented May 30, 2020

Have you tried to add a line for requires org.bytedeco.javacv.platform?

@jkolobok
Copy link
Author

Just tried

Error occurred during initialization of boot layer
java.lang.module.FindException: Module org.bytedeco.flycapture.linux.armhf not found, required by org.bytedeco.flycapture.platform

I'm on mac. not linux

@saudet
Copy link
Member

saudet commented May 30, 2020

Yeah, that's a limitation of JPMS. It's not possible to have optional modules.

@HGuillemet What would be your recommendation?

@HGuillemet
Copy link
Contributor

I'm not sure to understand the problem.
Thanks @jkolobok for supplying a standalone sample project, but when I run it either on linux or macos, With requires org.bytedeco.javacv or requires org.bytedeco.javacv.platform, it does work.
What did I miss ?

There are some kind of optional modules in JPMS : requires static, but I'd like to understand the problem before recommending anything :)

@jkolobok
Copy link
Author

ok. one more thing: I had -Djavacpp.platform=macosx-x86_64 in maven importer in intellij settings

@jkolobok
Copy link
Author

Screenshot 2020-05-31 at 01 09 24

@HGuillemet
Copy link
Contributor

When declaring "dependencies", we must distinguish:

  1. The tree of maven dependencies (from the <dependency> in the poms)
  2. The module graph (determined by the requires in the module-infos)
    The javacpp.platform property affects maven dependencies only: it limits the dependencies of *-platform artifacts to those of one or several platforms. When it's not set, these artifacts depend on all native artifacts of all possible plaforms.

The native libraries are resources that must be accessible from your app, which means they are either in a "required" module or in the unnamed module.
Your first exception is thrown because the native libraries needed by OpenCFFrameGrabber (opencv, openblas...) are not accessible : they are not in the module path (not in a "required" module) neither in the unnamed module (not in a jar of the class path). You can add them in the classpath. That's what mvn javafx:run does: all modules from the module graph are added to the module path and all remaining dependency artifacts are added to the class path. So mvn javafx:run works in your sample app, but mvn javafx:jlink does not produce a working image because the image will only contain the named modules.

When you replace org.bytedeco.javacv by org.bytedeco.javacv.platform, all native jars are brought into the module graph, for all plaforms. So now the native libraries are found, both mvn javafx:run and mvn javafx:jlink work, but not if you specify the javacpp.platform property because the module graph will then contain modules (the native jars for other platforms) that are not in maven dependencies, so not in the module path. This explains your second exception.

I need to think a bit more about best fixes. Another post coming later or tomorrow.

@saudet
Copy link
Member

saudet commented Jun 1, 2020

@HGuillemet Would it work if we used requires static instead of just requires for all the entries in platform artifacts like the one at https://github.com/bytedeco/javacpp-presets/blob/master/opencv/platform/pom.xml#L173?

@HGuillemet
Copy link
Contributor

Unfortunately that won't be enough.
A "static required" module, even if present in the module path, will not be loaded into the module graph if the module is not "required" by some other module, or added explicitly on the command line with --add-module.
So in our case, replacing the requires by requires static in the *-platform presets will make require org.javacpp.javacv.platform act just like require org.javacpp.javacv: native libs won't be found.

The only options I can think about are:

  1. Add javacv-system-arch classifiers, like for presets, and have the users that do not want to load the universe of all possible native libraries to "require" these specific classifiers instead of javacv-platform, or maybe let them keep javacv-platform but have them add --add-module org.bytedeco.javacv.system.arch on the command line.
  2. Try to rethink the loader in terms of service binding, as already discussed some months ago, which is the standard JPMS-compatible way to query the environment for available implementations of something.

Do you see another option ?

@saudet
Copy link
Member

saudet commented Jun 2, 2020

Unfortunately that won't be enough.
A "static required" module, even if present in the module path, will not be loaded into the module graph if the module is not "required" by some other module, or added explicitly on the command line with --add-module.
So in our case, replacing the requires by requires static in the *-platform presets will make require org.javacpp.javacv.platform act just like require org.javacpp.javacv: native libs won't be found.

Ah, yes, I remember about that. It's actually a compile-only thing, not about optional modules.

The only options I can think about are:

  1. Add javacv-system-arch classifiers, like for presets, and have the users that do not want to load the universe of all possible native libraries to "require" these specific classifiers instead of javacv-platform, or maybe let them keep javacv-platform but have them add --add-module org.bytedeco.javacv.system.arch on the command line.

I don't think we need any additional modules for that to work.
We can already do something like this and it works, right?

module recorder {
    requires org.bytedeco.javacv;
    requires org.bytedeco.opencv.macosx.x86_64;
}

It's just annoying that we have to do that... I think we could wrap all that pretty easily with a Gradle plugin in Gradle JavaCPP, if only Gradle supported JPMS: gradle/gradle#890

  1. Try to rethink the loader in terms of service binding, as already discussed some months ago, which is the standard JPMS-compatible way to query the environment for available implementations of something.

Do you see another option ?

I don't see how that would help. Do you have an example of that?

@HGuillemet
Copy link
Contributor

  1. Add javacv-system-arch classifiers, like for presets, and have the users that do not want to load the universe of all possible native libraries to "require" these specific classifiers instead of javacv-platform, or maybe let them keep javacv-platform but have them add --add-module org.bytedeco.javacv.system.arch on the command line.

I don't think we need any additional modules for that to work.
We can already do something like this and it works, right?

module recorder {
    requires org.bytedeco.javacv;
    requires org.bytedeco.opencv.macosx.x86_64;
}

Yes, for each native module used by javacv. That's what I do in my modular apps, but I use the presets directly, not javacv.

It's just annoying that we have to do that... I think we could wrap all that pretty easily with a Gradle plugin in Gradle JavaCPP, if only Gradle supported JPMS: gradle/gradle#890

  1. Try to rethink the loader in terms of service binding, as already discussed some months ago, which is the standard JPMS-compatible way to query the environment for available implementations of something.

Do you see another option ?

I don't see how that would help. Do you have an example of that?

The specificity of service loaders is that it can, in a JPMS compatible way, load different modules depending of what it finds in the module path. So the javacpp.platform property will be enough and no need to specify the platform elsewhere (no more specific platforms in the module-info).

That could roughly work like this:
In the module-info of org.bytedeco.opencv.linux.x86_64:

  provides org.bytedeco.opencv.opencv_core.Implementation with org.bytedeco.opencv.linux.x86_64.opencv_core.Implementation

When loading opencv_core, instead of the getResource we do:

ServiceLoader<opencv_core.Implementation> loader = ServiceLoader.load(opencv_core.Implementation.class);

The resulting loader can then be used to iterate over all implementations found in the module path and select one having the right system and arch, by calling methods like Implementation.getArch(), or by looking for some annotations.
Once an implementation is found, extract and cache the library as usual.

Alternatively, instead of using the service facility to locate specific libraries like opencv_core, it could be used to simply locate the whole native module opencv and then we findResource the library in the module.

@HGuillemet
Copy link
Contributor

There is a 3rd option:

  1. Give up the modularization of native jars. In modular apps, add them to the class path and decide that the correct way to build a jlink image is to directly include the native libraries already extracted (@saudet, see our Gitter discussion of 2019-05-20).

@saudet
Copy link
Member

saudet commented Jun 3, 2020

That sounds like a lot trouble just to load resources... I think loading the JVM with options like --add-modules org.bytedeco.opencv.linux.x86_64,org.bytedeco.opencv.macosx.x86_64,etc sounds like a good compromise. It's easy to do since we're doing it at the same place where the module path gets set, and it's something that already works. It's also something we can set at runtime depending on the platform we're running, so we don't need to bake it in the application.

@jkolobok What do you think? Can you give it a try and see if that satisfies your needs?

There is a 3rd option:

  1. Give up the modularization of native jars. In modular apps, add them to the class path and decide that the correct way to build a jlink image is to directly include the native libraries already extracted (@saudet, see our Gitter discussion of 2019-05-20).

Yeah, it looks like JavaFX also gave up on that and they've decided to just fall back on the class path: openjfx/javafx-maven-plugin#58. IMO, if we're going to need the class path to do that, I wouldn't bother with the module path in the first place.

@saudet
Copy link
Member

saudet commented Jun 3, 2020

@HGuillemet BTW, could you try to update the ModiTect plugin to 1.0.0.RC1 and make sure there's no issues with the new version?

@HGuillemet
Copy link
Contributor

That sounds like a lot trouble just to load resources... I think loading the JVM with options like --add-modules org.bytedeco.opencv.linux.x86_64,org.bytedeco.opencv.macosx.x86_64,etc sounds like a good compromise. It's easy to do since we're doing it at the same place where the module path gets set, and it's something that already works. It's also something we can set at runtime depending on the platform we're running, so we don't need to bake it in the application.

module path is usually built automatically by maven, but why not. We would need to replace the requires by requires static in the *-platform modules so that the module paths to the native modules don't need to be added manually as well.
I still think that adding classifiers for javacv is the simplest for users and will make javacv behave like all presets.
We could do both.

@jkolobok What do you think? Can you give it a try and see if that satisfies your needs?

There is a 3rd option:

  1. Give up the modularization of native jars. In modular apps, add them to the class path and decide that the correct way to build a jlink image is to directly include the native libraries already extracted (@saudet, see our Gitter discussion of 2019-05-20).

Yeah, it looks like JavaFX also gave up on that and they've decided to just fall back on the class path: openjfx/javafx-maven-plugin#58. IMO, if we're going to need the class path to do that, I wouldn't bother with the module path in the first place.

Remember that modular app cannot read classes from the classpath, so moving classes to classpath just exclude the option to run modular apps. The Issue and PR you are linking doesn't involve anyone "official".

javafx uses a slighlty different approach : they have also, for instance, both artifacts javafx-graphics-14 and javafx-graphics-14-linux.
But javafx-graphics-14 is an empty artifact, an automatic module, only used for its pom which dispatch the maven dependency to, eg, javafx-graphics-14-linux, based on the javafx.platform property just like javacpp.platform.
javafx-graphics-14-linux contains both java and native libs and is the true module, named javafx.graphics.
So applications always have the same module-info with requires javafx.graphics (no requires javafx.graphics.linux) and the right platform jar javafx-graphics-14-linux is listed in the module path (usually automatically by their maven plugin).
The problem, raised by the issue you mentioned, is that there is no way to have a modular app with more than one platform (and even for non modular app it's a bit tricky like discussed in the issue). And also that using their maven plugin is more or less mandatory.
Shall we investigate to see if we'd better use the javafx approach for javacpp ? Maybe with moditect in lieu of javafx-maven-plugin ?

@HGuillemet
Copy link
Contributor

@HGuillemet BTW, could you try to update the ModiTect plugin to 1.0.0.RC1 and make sure there's no issues with the new version?

Done. No issue found.

@saudet
Copy link
Member

saudet commented Jun 4, 2020

module path is usually built automatically by maven, but why not. We would need to replace the requires by requires static in the *-platform modules so that the module paths to the native modules don't need to be added manually as well.

Right, by default, it's either all or nothing. If we can't remove them on demand, then I suppose the best we can do is force people to add them on demand.

I still think that adding classifiers for javacv is the simplest for users and will make javacv behave like all presets.
We could do both.

How would that help? The problem is with artifacts for OpenCV, FFmpeg, etc, not JavaCV.

The problem, raised by the issue you mentioned, is that there is no way to have a modular app with more than one platform (and even for non modular app it's a bit tricky like discussed in the issue). And also that using their maven plugin is more or less mandatory.
Shall we investigate to see if we'd better use the javafx approach for javacpp ? Maybe with moditect in lieu of javafx-maven-plugin ?

Why? That limitation is quite severe. Like I said, if we have to fall back on the class path to get it working, I don't see the point of using the module path at all, so let's try to figure out something else.

@jkolobok
Copy link
Author

jkolobok commented Jun 4, 2020

That sounds like a lot trouble just to load resources... I think loading the JVM with options like --add-modules org.bytedeco.opencv.linux.x86_64,org.bytedeco.opencv.macosx.x86_64,etc sounds like a good compromise. It's easy to do since we're doing it at the same place where the module path gets set, and it's something that already works. It's also something we can set at runtime depending on the platform we're running, so we don't need to bake it in the application.

@jkolobok What do you think? Can you give it a try and see if that satisfies your needs?

Hm. I'm not sure what the list of modules should look like depending of what parst of java vc I'm using.. Do I need to add all platforms? The app is a desktop application so it must be as small as possibe. Modules are note required they are just a nice to have if it's not too much pain

@saudet
Copy link
Member

saudet commented Jun 4, 2020

Hm. I'm not sure what the list of modules should look like depending of what parst of java vc I'm using.. Do I need to add all platforms? The app is a desktop application so it must be as small as possibe. Modules are note required they are just a nice to have if it's not too much pain

Ok, so you should probably not use the "-platform" artifacts anyway. As long as you don't get any errors, you don't need those modules that you're not adding.

@HGuillemet
Copy link
Contributor

HGuillemet commented Jun 4, 2020

I still think that adding classifiers for javacv is the simplest for users and will make javacv behave like all presets.
We could do both.

How would that help? The problem is with artifacts for OpenCV, FFmpeg, etc, not JavaCV.

The problem is with the *-platform modules that require all platforms artifacts, independently of the javacpp.platform property and of what is available on the module path.
For instance if @jkolobok delares a maven dependency towards javacv, classifier macosx-x86_64 (or towards javacv-platform and using the javacpp-platform property) AND changes his module-info.java to requires org.bytedeco.javacv.macosx.x86_64 then his problems will be solved. Only the macosx artifact will be downloaded and includes in the jlink image.
If needed, the platform in module-info can be automatically changed using either a maven plugin like templating-maven-plugin or using moditect.

The problem, raised by the issue you mentioned, is that there is no way to have a modular app with more than one platform (and even for non modular app it's a bit tricky like discussed in the issue). And also that using their maven plugin is more or less mandatory.
Shall we investigate to see if we'd better use the javafx approach for javacpp ? Maybe with moditect in lieu of javafx-maven-plugin ?

Why? That limitation is quite severe.

I agree.

@saudet
Copy link
Member

saudet commented Jun 5, 2020

The problem is with the *-platform modules that require all platforms artifacts, independently of the javacpp.platform property and of what is available on the module path.
For instance if @jkolobok delares a maven dependency towards javacv, classifier macosx-x86_64 (or towards javacv-platform and using the javacpp-platform property) AND changes his module-info.java to requires org.bytedeco.javacv.macosx.x86_64 then his problems will be solved. Only the macosx artifact will be downloaded and includes in the jlink image.
If needed, the platform in module-info can be automatically changed using either a maven plugin like templating-maven-plugin or using moditect.

Right, but that has nothing to do with JavaCV. We can do all that at the level of OpenCV, FFmpeg, etc.

If you know of a way to generate those module-info.java files on demand using the existing Maven profiles, that would be great: https://github.com/bytedeco/javacpp-presets/wiki/Reducing-the-Number-of-Dependencies

@saudet
Copy link
Member

saudet commented Jun 5, 2020

Or alternatively, a Maven extension, which would also allow us to define the target platforms in the pom.xml file instead: bytedeco/javacpp-presets#846

/cc @maxsenft

@saudet
Copy link
Member

saudet commented Jun 5, 2020

Looks like ModiTect is also available for Gradle:
https://github.com/moditect/moditect-gradle-plugin
Might be easier to implement something with that and Gradle JavaCPP:
https://github.com/bytedeco/gradle-javacpp

@HGuillemet
Copy link
Contributor

HGuillemet commented Jun 5, 2020

After some more thought, here is what I'm suggesting:

  • for artifacts dependencies, if we want to depend on native jars, we should always use the *-platform artifacts, using the javacpp.platform property if we want to limit the dependencies to some system/arch. Depending directly on the *-system-arch artifacts won't draw the native jars of depencies so it's not satisfactory.
  • for module graph, let's offer the choice to the user between:
    • not adding the native modules (useful when the user choose to add the native libs directly in the image): eg requires org.javacpp.opencv
    • adding modules of selective platforms, eg requires org.javacpp.opencv.linux.x86_64
    • adding modules for all the platforms, eg requires org.javacpp.opencv.platform

To illustrate this, I have updated the sample project stitching-jlink (PR) Here are the list of modules included in the jlink image in the 3 cases mentioned above:

java.base@14.0.1
jdk.unsupported@14.0.1
org.bytedeco.javacpp
org.bytedeco.openblas
org.bytedeco.opencv
org.bytedeco.samples.stitching
java.base@14.0.1
jdk.unsupported@14.0.1
org.bytedeco.javacpp
org.bytedeco.openblas
org.bytedeco.openblas.linux.x86_64 open
org.bytedeco.opencv
org.bytedeco.opencv.linux.x86_64 open
org.bytedeco.samples.stitching
java.base@14.0.1
jdk.unsupported@14.0.1
org.bytedeco.javacpp
org.bytedeco.openblas
org.bytedeco.openblas.ios.arm64 open
org.bytedeco.openblas.ios.x86_64 open
org.bytedeco.openblas.linux.arm64 open
org.bytedeco.openblas.linux.armhf open
org.bytedeco.openblas.linux.ppc64le open
org.bytedeco.openblas.linux.x86 open
org.bytedeco.openblas.linux.x86_64 open
org.bytedeco.openblas.macosx.x86_64 open
org.bytedeco.openblas.windows.x86 open
org.bytedeco.openblas.windows.x86_64 open
org.bytedeco.opencv
org.bytedeco.opencv.ios.arm64 open
org.bytedeco.opencv.ios.x86_64 open
org.bytedeco.opencv.linux.arm64 open
org.bytedeco.opencv.linux.armhf open
org.bytedeco.opencv.linux.ppc64le open
org.bytedeco.opencv.linux.x86 open
org.bytedeco.opencv.linux.x86_64 open
org.bytedeco.opencv.macosx.x86_64 open
org.bytedeco.opencv.platform
org.bytedeco.opencv.windows.x86 open
org.bytedeco.opencv.windows.x86_64 open
org.bytedeco.samples.stitching

Nothing needs to be changed to presets or javacpp for this to work.

I know 3 maven plugins that can run jlink: moditect, jlink and javafx. The jlink goal of moditect doesn't use maven dependencies to build the module path, it must be populated manually, which is cumbersome and error-prone. We could suggest the author to fix this. The jlink plugin constructs the module path from all maven dependencies. That's not what we want because of the *-platform artifacts. The javafx plugin somehow reconstructs the module graph from the module-infos and builds the module path. That's what works here.

In order to generate the module-info according to javacpp.platform, I had to use the build-helper plugin to replace the - by . (that's the annoying part), and the templating plugin. moditect could be used instead of the templating plugin but it's not compatible with the javafx plugin and the way it reads module-info.java files.

That said, the sample program does not work for some independent reason i didn't investigate:

reading panorama_image1.jpg
reading panorama_image2.jpg
OpenCL program build log: features2d/orb
Status -11: CL_BUILD_PROGRAM_FAILURE
-D ORB_RESPONSES -D blockSize=7 -D scale_sq_sq=3,847753306719e-16f -D HARRIS_K=0,039999999106f
<kernel>:35:49: error: invalid digit '9' in octal constant
responses[idx] = ((float)a * b - (float)c * c - HARRIS_K * (float)(a + b) * (a + b))*scale_sq_sq;
                                                ^
<built-in>:19:22: note: expanded from here
#define HARRIS_K 0,039999999106f

There are also spurious warnings about not finding jnijavacpp, I haven't investigate either.

What do you think ?
If you agree with this approach, let's see javacv case.

@saudet
Copy link
Member

saudet commented Jun 8, 2020

After some more thought, here is what I'm suggesting:

  • for artifacts dependencies, if we want to depend on native jars, we should always use the *-platform artifacts, using the javacpp.platform property if we want to limit the dependencies to some system/arch. Depending directly on the *-system-arch artifacts won't draw the native jars of depencies so it's not satisfactory.

  • for module graph, let's offer the choice to the user between:

    • not adding the native modules (useful when the user choose to add the native libs directly in the image): eg requires org.javacpp.opencv
    • adding modules of selective platforms, eg requires org.javacpp.opencv.linux.x86_64
    • adding modules for all the platforms, eg requires org.javacpp.opencv.platform

Ok, but ideally one would assume that the module path and graph could just be automatically adjusted to whatever Maven modules the user gave to the build...

Nothing needs to be changed to presets or javacpp for this to work.

I know 3 maven plugins that can run jlink: moditect, jlink and javafx. The jlink goal of moditect doesn't use maven dependencies to build the module path, it must be populated manually, which is cumbersome and error-prone. We could suggest the author to fix this. The jlink plugin constructs the module path from all maven dependencies. That's not what we want because of the *-platform artifacts. The javafx plugin somehow reconstructs the module graph from the module-infos and builds the module path. That's what works here.

maven-jlink-plugin seems abandoned and if javafx-maven-plugin works better for the purpose of the sample project, meh, sure, why not. Ideally, a general plugin like ModiTect should implement all that and JavaFX should then depend on it, but JavaFX is OpenJDK, which can't depend on anything external anyway so it's probably a lost cause, but maybe I'm mistaken, @johanvos? Do you think the guys at JavaFX could contribute their code to ModiTect?

In order to generate the module-info according to javacpp.platform, I had to use the build-helper plugin to replace the - by . (that's the annoying part), and the templating plugin. moditect could be used instead of the templating plugin but it's not compatible with the javafx plugin and the way it reads module-info.java files.

We can use JavaCPP for this. It returns that value as ${javacpp.platform.module} to the project.

That said, the sample program does not work for some independent reason i didn't investigate:

reading panorama_image1.jpg
reading panorama_image2.jpg
OpenCL program build log: features2d/orb
Status -11: CL_BUILD_PROGRAM_FAILURE
-D ORB_RESPONSES -D blockSize=7 -D scale_sq_sq=3,847753306719e-16f -D HARRIS_K=0,039999999106f
<kernel>:35:49: error: invalid digit '9' in octal constant
responses[idx] = ((float)a * b - (float)c * c - HARRIS_K * (float)(a + b) * (a + b))*scale_sq_sq;
                                                ^
<built-in>:19:22: note: expanded from here
#define HARRIS_K 0,039999999106f

That looks like an issue with your OpenCL driver... ?

There are also spurious warnings about not finding jnijavacpp, I haven't investigate either.

That just means javacpp-platform is missing somewhere, see issues #1305 and bytedeco/javacpp#393 for details.

What do you think ?
If you agree with this approach, let's see javacv case.

I'm not convinced that we're getting anywhere because we still have to list all the modules manually in the module-info.java file anyway, no?

@HGuillemet
Copy link
Contributor

Ok, but ideally one would assume that the module path and graph could just be automatically adjusted to whatever Maven modules the user gave to the build...

For the module path, yes, that's what maven-jlink plugin and javafx plugin do (the javafx plugin in a smarter way). But we cannot automatically generate the module-info of the user, there are information there we cannot guess: the name of the module, what it exports, opens, which dependencies are transitive... People building JPMS app should be used to write their module-info in addition to their artifact dependencies anyway.

maven-jlink-plugin seems abandoned and if javafx-maven-plugin works better for the purpose of the sample project, meh, sure, why not. Ideally, a general plugin like ModiTect should implement all that and JavaFX should then depend on it, but JavaFX is OpenJDK, which can't depend on anything external anyway so it's probably a lost cause, but maybe I'm mistaken, @johanvos? Do you think the guys at JavaFX could contribute their code to ModiTect?

Yes there is a lot in the javafx maven plugin that has nothing to do with javafx that could be in moditect or directly in maven.

In order to generate the module-info according to javacpp.platform, I had to use the build-helper plugin to replace the - by . (that's the annoying part), and the templating plugin. moditect could be used instead of the templating plugin but it's not compatible with the javafx plugin and the way it reads module-info.java files.

We can use JavaCPP for this. It returns that value as ${javacpp.platform.module} to the project.

Right, but the normal user does't need the javacpp maven plugin. and using the build mojo for just 1 line of Java (properties.setProperty("platform.module", module.replace('-', '.'));) seems a bit overkill. If you think of other features targeted to users and not preset-developers that could be isolated in a small mojo it could be the best solution.
Using the build-helper + the templating plugin in the sample project just to generate the module-info of the sample project is overkill too, but it allows to run the project from the command line without editing anything.

That looks like an issue with your OpenCL driver... ?

That was a strange locale problem. Running with LANG=C solved the issue in my case.

There are also spurious warnings about not finding jnijavacpp, I haven't investigate either.

That just means javacpp-platform is missing somewhere, see issues #1305 and bytedeco/javacpp#393 for details.

Shouldn't all the preset-platform have a maven and module dependency towards javacpp-platform ?

What do you think ?
If you agree with this approach, let's see javacv case.

I'm not convinced that we're getting anywhere because we still have to list all the modules manually in the module-info.java file anyway, no?

Yes, see above.

@HGuillemet
Copy link
Contributor

Done

@HGuillemet
Copy link
Contributor

The javafx-maven-plugin is being updated. To sum up, users of javacpp presets in JPMS applications will have to:

  • declare maven dependencies with the xxx-platform artifacts.
  • control the native dependencies with property javacpp.platform and the like.
  • requires the non-native module in their module-info (eg requires org.bytedeco.opencv).
  • configure the javafx-maven-plugin to:
    • populate the module path with the maven dependencies
    • add --add-modules ALL-MODULE-PATH to the jlink command and --add-modules ALL-SYSTEM to the launcher script.

This solution should also avoid the need to add native modules for JavaCV.

They will still have the option to explicitly add the native module (eg with requires org.bytedeco.opencv.linux.x86_64 in module-info or --add-modules org.bytedeco.opencv.linux.x86_64 on the command line) if the ALL-MODULE-PATH mechanism does not work for them. Or to add nothing if they extract "manually" the native libraries in the image.

However we need to change the module-info of all -platform modules and either replace the requires towards the native modules with requires static, or to remove the requires entirely. I don't think it makes any difference.

Am I overlooking some details ?

@saudet
Copy link
Member

saudet commented Jun 27, 2020

Sounds good! Let's use "requires static" just for good measure. :) Thanks!!

@saudet
Copy link
Member

saudet commented Jul 1, 2020

@HGuillemet When javafx-maven-plugin gets updated, please also update opencv-stitching-jlink! Thank you very much

@saudet
Copy link
Member

saudet commented Aug 19, 2020

@HGuillemet Any news??

@HGuillemet
Copy link
Contributor

openjfx/javafx-maven-plugin#92 (comment)

@saudet
Copy link
Member

saudet commented Oct 16, 2020

Ok, that PR has finally been merged. @HGuillemet Could you update the sample project and let's see what that looks like?

@HGuillemet
Copy link
Contributor

HGuillemet commented Oct 16, 2020

Unfortunately this commit only adds the option to populate the module path with maven dependencies. The required option to add the maven dependencies to the jlink image has been forked in another issue. So currently the javafx:run goal works as we need it to, but not javafx:jlink yet.

@saudet
Copy link
Member

saudet commented Nov 14, 2020

@HGuillemet It should now work for @jkolobok's use case though right?

@jkolobok Can you give it a try with the new version of javafx-maven-plugin?

@HGuillemet
Copy link
Contributor

We first need to replace the requires in *-platform modules by static requires. I can file a PR only for this if it helps.

@saudet
Copy link
Member

saudet commented Nov 15, 2020

Didn't you already do that in pull bytedeco/javacpp-presets#900?

@HGuillemet
Copy link
Contributor

Yes sorry, it's in javacpp.platform then that the static is missing.

@saudet
Copy link
Member

saudet commented Nov 15, 2020

Sure, please fix whatever needs fixing. Thanks!

@saudet
Copy link
Member

saudet commented Nov 16, 2020

@HGuillemet Thanks! @jkolobok Please give it a try with the snapshots: http://bytedeco.org/builds/

@saudet
Copy link
Member

saudet commented Mar 10, 2021

Ok, JavaCV 1.5.5 has been released with all the fixes, and I think we've done all that we can do on this end.

@HGuillemet Would you know if javafx-maven-plugin now supports everything we need as well?

@HGuillemet
Copy link
Contributor

HGuillemet commented Mar 19, 2021

It does not, the useful PR doesn't seem like a priority there :(
In the meantime, Apache Maven plugin has awaken and left the alpha status.
I'm going to submit a PR to update the sample project building a jlink image using the Apache plugin.

@johanvos
Copy link
Contributor

@HGuillemet Sorry about the lack of progress on openjfx/javafx-maven-plugin#109 -- I'll check that.

@saudet
Copy link
Member

saudet commented Feb 16, 2022

The same issue seems to be happening with javafx-gradle-plugin as well, see issue #1754.

@spectacularcrackers Thanks for reporting!

@jspinak
Copy link

jspinak commented Feb 3, 2024

I'm also getting this error on my project "Brobot":

Could not find jniopenblas_nolapack in class, module, and library paths.
java.lang.UnsatisfiedLinkError: Could not find jniopenblas_nolapack in class, module, and library paths.

Brobot uses Gradle 8.5 and Java 21. It is open-source and is found at https://github.com/jspinak/brobot. The build.gradle file is at https://github.com/jspinak/brobot/blob/main/library/build.gradle. I tried to solve the problem by including the openblas dependency in my build.gradle file and adding the .jar directly to the classpath with IntelliJ, but neither worked.

@saudet
Copy link
Member

saudet commented Feb 3, 2024

Please set the "org.bytedeco.javacpp.logger.debug" system property to "true" to get more information on the console.

@saudet
Copy link
Member

saudet commented Feb 3, 2024

@jspinak I don't see any dependencies on javacv-platform in your build.gradle file

@jspinak
Copy link

jspinak commented Feb 3, 2024

I have implementation group: 'org.bytedeco', name: 'javacv', version: '1.5.10'. This was working for me fine until this past week when I added database functionality. I made a number of updates to versions and other changes, too many to trace back to the point where JavaCV was working.

@saudet
Copy link
Member

saudet commented Feb 3, 2024

Well whatever the reason why it was working before is irrelevant, it shouldn't have been working. Add a dependency on javacv-platform and it will work again

@jspinak
Copy link

jspinak commented Feb 3, 2024

Thanks, it's working! Btw, your 2-second response time was very impressive, I usually don't get responses in live conversations that fast :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants