Open jkolobok opened 4 years ago
Have you tried to add a line for requires org.bytedeco.javacv.platform
?
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
Yeah, that's a limitation of JPMS. It's not possible to have optional modules.
@HGuillemet What would be your recommendation?
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 :)
ok. one more thing: I had -Djavacpp.platform=macosx-x86_64 in maven importer in intellij settings
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.
@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?
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 ?
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 therequires
byrequires static
in the*-platform
presets will makerequire org.javacpp.javacv.platform
act just likerequire 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:
- 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 ofjavacv-platform
, or maybe let them keepjavacv-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: https://github.com/gradle/gradle/issues/890
- 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?
- 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 ofjavacv-platform
, or maybe let them keepjavacv-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
- 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.
There is a 3rd option:
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:
- 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: https://github.com/openjfx/javafx-maven-plugin/issues/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.
@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?
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:
- 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 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.
module path is usually built automatically by maven, but why not. We would need to replace the
requires
byrequires 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.
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
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.
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.
The problem is with the
*-platform
modules thatrequire
all platforms artifacts, independently of thejavacpp.platform
property and of what is available on the module path. For instance if @jkolobok delares a maven dependency towardsjavacv
, classifiermacosx-x86_64
(or towardsjavacv-platform
and using thejavacpp-platform
property) AND changes hismodule-info.java
torequires 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 liketemplating-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
Or alternatively, a Maven extension, which would also allow us to define the target platforms in the pom.xml
file instead: https://github.com/bytedeco/javacpp-presets/issues/846
/cc @maxsenft
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
After some more thought, here is what I'm suggesting:
*-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.requires org.javacpp.opencv
requires org.javacpp.opencv.linux.x86_64
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.
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 thejavacpp.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 readsmodule-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 https://github.com/bytedeco/javacpp/issues/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?
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 readsmodule-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.
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.
I still think we can do better than that, but I'll leave it up to you :)
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.
@johanvos Is this due to something legal restriction from Oracle?
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 readsmodule-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.
I don't consider adding these 5 lines to the pom.xml file to be overkill:
<plugin>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.3</version>
</plugin>
But if you prefer build-helper, that's alright.
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 ?
They do, that's why it works, but again if it doesn't get added to the module graph, it won't work with JPMS, right? We have to add it manually, I guess?
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.
Are you sure? Really really sure? :)
I don't consider adding these 5 lines to the pom.xml file to be overkill:
<plugin> <groupId>org.bytedeco</groupId> <artifactId>javacpp</artifactId> <version>1.5.3</version> </plugin>
But if you prefer build-helper, that's alright.
We also need to execute the plugin somehow, don't we ?
Shouldn't all the preset-platform have a maven and module dependency towards javacpp-platform ?
They do, that's why it works, but again if it doesn't get added to the module graph, it won't work with JPMS, right? We have to add it manually, I guess?
This PR will do it automatically. If it's ok to assume that all native presets need the libraries in the native javacpp artifact.
We also need to execute the plugin somehow, don't we ?
Right, it doesn't look like we can set default executions. Something like this then:
<plugin>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.3</version>
</plugin>
<executions>
<execution>
<id>javacpp-validate</id>
<phase>validate</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
<executions>
They do, that's why it works, but again if it doesn't get added to the module graph, it won't work with JPMS, right? We have to add it manually, I guess?
This PR will do it automatically. If it's ok to assume that all native presets need the libraries in the native javacpp artifact.
Ok, I see, thanks! Also let's try to make this work: https://github.com/bytedeco/sample-projects/pull/49#discussion_r437876843
<plugin> <groupId>org.bytedeco</groupId> <artifactId>javacpp</artifactId> <version>1.5.3</version> </plugin> <executions> <execution> <id>javacpp-validate</id> <phase>validate</phase> <goals> <goal>build</goal> </goals> </execution> <executions>
That does the trick. If it's likely that we can find other use for this plugin for the user (as opposed to the preset builder), it might be worth creating a separate goal.
This PR will do it automatically. If it's ok to assume that all native presets need the libraries in the native javacpp artifact.
Ok, I see, thanks! Also let's try to make this work: bytedeco/sample-projects#49 (comment)
javacpp.platform.host
works. PR updated.
To go back to the OP issue: with JavaCV, we can already have option 1 of options mentioned here (no native jars in module),and option 3 (all native jars) available. If we want option 2 (native jars for selective platform in the module graph), then either:
module recorder {
requires org.bytedeco.javacv.linux-x86_64;
}
module recorder {
requires org.bytedeco.javacv;
requires org.bytedeco.opencv.linux-x86_64;
}
Another related issue: I'm not familiar with JavaCV, does the user has to access Java types defined in the JavaCV components, like opencv Mat
or whatever ? If yes, the requires
in the javacv module-info should be transitive
.
That does the trick. If it's likely that we can find other use for this plugin for the user (as opposed to the preset builder), it might be worth creating a separate goal.
Actually, for users, we need to create a Maven extension for this, see issue https://github.com/bytedeco/javacpp-presets/issues/846. We can't modify the dependencies of a project with just Maven plugins (although we can with a Gradle plugin, see https://github.com/bytedeco/gradle-javacpp#the-platform-plugin), so in this case as well, just using a Maven plugin creates inconsistencies in the build when all the magical properties are not perfectly aligned with the profiles.
javacpp.platform.host
works. PR updated.
:+1:
To go back to the OP issue: with JavaCV, we can already have option 1 of options mentioned here (no native jars in module),and option 3 (all native jars) available. If we want option 2 (native jars for selective platform in the module graph), then either:
- we add javacpp-system-arch modules, so that the user module-info will just contain:
module recorder { requires org.bytedeco.javacv.linux-x86_64; }
How would this work if/when we split JavaCV into multiple modules like https://github.com/bytedeco/javacv/issues/1071#issuecomment-518504533?
* or the user has to determine which component of JavaCV it needs and list native modules:
module recorder { requires org.bytedeco.javacv; requires org.bytedeco.opencv.linux-x86_64; }
Well, I still think the build system should be smart enough to add all this stuff on its own. Like: "Oh, we have opencv-linux-x86_64 on the module path, let's add that module too!" You know, it's really basic stuff, but if we have to do it manually for now, that's alright.
Another related issue: I'm not familiar with JavaCV, does the user has to access Java types defined in the JavaCV components, like opencv
Mat
or whatever ? If yes, therequires
in the javacv module-info should betransitive
.
Yes, it's part of the "API", and users are expected to use those classes.
BTW, if one of your goals is to produce executables that are as small as possible, give it a try with GraalVM Native Image as well. It produces much smaller images. Here's what I get on linux-x86_64
with GraalVM 20.1.0 for OpenJDK 11:
$ git clone https://github.com/bytedeco/sample-projects
$ cd sample-projects/opencv-stitching-jlink
$ mvn clean package -Djavacpp.platform.custom -Djavacpp.platform.host
$ tar -cJvf image.tar.xz target/image
$ ln -lh image.tar.xz
-rw-rw-r--. 1 saudet saudet 54M Jun 13 11:58 image.tar.xz
$ cd ../opencv-stitching-native
$ mvn clean package -Djavacpp.platform.custom -Djavacpp.platform.host
$ tar -cJvf stitching.tar.xz target/stitching
$ ls -lh stitching.tar.xz
-rw-rw-r--. 1 saudet saudet 23M Jun 13 11:57 stitching.tar.xz
I will.
Well, I still think the build system should be smart enough to add all this stuff on its own. Like: "Oh, we have opencv-linux-x86_64 on the module path, let's add that module too!" You know, it's really basic stuff, but if we have to do it manually for now, that's alright.
Here is something that should make you happy:
--add-modules ALL-MODULE-PATH
That works for javac
, java
AND jlink
(but unfortunately not jdeps
).
Here is something that should make you happy:
--add-modules ALL-MODULE-PATH
That works for
javac
,java
ANDjlink
(but unfortunately notjdeps
).
Nice, does it actually work? If you figure out how to use it with javafx-maven-plugin, please update the sample project! Thanks
After some experiments:
ALL-MODULE-PATH
.javacpp.platform
property is enough for bringing the right modules into the module graph and building the jlink image. No interest in using ALL-MODULE-PATH
either. However, we need to replace all requires
in *-platform
modules by requires static
(or removing them).The apache jlink-maven-plugin solution seems then more user-friendly : no need to duplicate the platform selection in the module-info in addition to the javacpp.platform
property, no need for the javacpp maven plugin nor for the templating plugin.
Too bad this plugin is still alpha and more or less abandoned. I saw this fork that may be promising.
I'll have to read the whole thread do understand what is missing, but if you want to make changes in the javafx-maven-plugin, you are very welcome to file an issue at https://github.com/openjfx/javafx-maven-plugin/issues (and a PR?).
For usage with GraalVM, we actually use a different plugin: https://github.com/gluonhq/client-maven-plugin (which is targeting desktop/mobile/embedded)
@johanvos tl;dr We're basically missing something that can add all modules found on the module path, well actually just Maven dependencies are fine, to the module graph, especially in the case of jlink but in general as well. Apparently javafx-maven-plugin doesn't do that.
@jkolobok or @HGuillemet Please open an issue over there about this issue! Thanks
The javafx-maven-plugin is being updated. To sum up, users of javacpp presets in JPMS applications will have to:
xxx-platform
artifacts.javacpp.platform
and the like.requires
the non-native module in their module-info (eg requires org.bytedeco.opencv
).--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 ?
Sounds good! Let's use "requires static" just for good measure. :) Thanks!!
@HGuillemet When javafx-maven-plugin gets updated, please also update opencv-stitching-jlink! Thank you very much
@HGuillemet Any news??
Ok, that PR has finally been merged. @HGuillemet Could you update the sample project and let's see what that looks like?
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.
@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?
We first need to replace the requires
in *-platform
modules by static requires
. I can file a PR only for this if it helps.
Didn't you already do that in pull https://github.com/bytedeco/javacpp-presets/pull/900?
Yes sorry, it's in javacpp.platform then that the static is missing.
Sure, please fix whatever needs fixing. Thanks!
java 11 macos 10.14.6
Sample project: javafxsample.zip Workaround - remove module-info.java.. and it starts working...