beryx / badass-jlink-plugin

Create a custom runtime image of your modular application
https://badass-jlink-plugin.beryx.org
Apache License 2.0
379 stars 25 forks source link

non modular dependencies issues #133

Closed knakul853 closed 4 years ago

knakul853 commented 4 years ago

I have been working on the mzmine build system and trying to use jlink. The issue I am facing is that when I try to import dependencies in the project it asks to add in the module descriptor even if it is nonmodular dependencies.for the sake of simplicity when I add (as IntelliJ suggest toPackage 'X' is declared in module 'Y', but module 'mymodule' does not read it ) this error goes but since package 'X' is in multiple modules so it throws an error. I am very new so it might be trivial but after stack and doc i am still not able to cope up with this problem i am getting short of this kind of errors link

here is my build script link

siordache commented 4 years ago

mzmine is currently a non-modular application. Do you try to modularize it?

tomas-pluskal commented 4 years ago

@knakul853 It's best if you push your current source code into a separate branch, including the build script and the new module-info.java. Then post a link to the branch here.

knakul853 commented 4 years ago

here is the link https://github.com/knakul853/mzmine3/tree/build

siordache commented 4 years ago

@knakul853 Thanks for the link! A lot of dependencies in this project have split packages, which leads to errors of the form: "module m reads package p from both m1 and m2". This means that it's not possible to modularize mzmine, unless you fix all these dependencies. That would require a huge amount of work and is probably not worth the effort, but if you still want to go this way, here are your options:

  1. Convince the maintainers of these dependencies to refactor them in order to get rid of the split packages.
  2. Get the source code and do the refactoring yourself.
  3. For each group of dependencies with split packages, create a fat jar containing all dependencies in this group. For example, to get rid of the split packages in the org.openscience.cdk dependencies, you can create a jar named cdk-all.jar that contains all the cdk libraries. You can then place this jar in the src/main/lib directory. This is the most pragmatic option, but it still requires a lot of work because there are many dependencies with split packages.

There is also the possibility to modularize the application only partially, by putting some dependencies on the module-path and some on the classpath. In this case, you need to continue using the badass-runtime plugin.

Personally, I would leave this application non-modularized.

tomas-pluskal commented 4 years ago

@siordache Thanks for the explanation!

I thought the badass-jlink-plugin used the merged jar to combine the non-modular dependencies according to the description on the website: The badass-jlink plugin takes a more pragmatic approach by combining all non-modular dependencies into a single jar. This way, only the resulting merged module needs a module descriptor. Am I missing something here?

By the way, is there any way to use the jpackage tool when using the badass-runtime plugin?

siordache commented 4 years ago

The badass-jlink-plugin was not designed to help creating a modularized application. It assumes you already have it. (Otherwise, you need to use the badass-runtime-plugin.)

So, what does badass-jlink do? It allows you create a custom runtime image, even if your application has automatic modules (that is, non-modular dependencies). The jlink tool cannot work with automatic modules, so here is where the merged module comes into play. It is created only after your modular application has been compiled. From the point of view of your application's module descriptor, there is no such thing as a "merged module". The requires clauses in the module descriptor reference only (proper or automatic) modules corresponding to your dependencies.

The badass-jlink-plugin doesn't help solving split packages issues. Instead, the gradle-modules-plugin provides support for patching modules to prevent split packages. This is an option that I somehow forgot to mention in my previous post. I have only limited experience with patching modules using the gradle-modules-plugin and I don't know how well the IDEs support this feature, but this is actually the most interesting option to consider.

The badass-runtime plugin also allows creating platform-specific installers via jpackage.

tomas-pluskal commented 4 years ago

Thanks a lot! Now everything is clear.

siordache commented 4 years ago

@tomas-pluskal & @knakul853 I decided to try if patching the modules is a viable approach. The first problem is that currently the gradle-modules-plugin does not handle multiple jars. To overcome this issue, I created a custom variant of the gradle-modules-plugin that supports this feature. (It's just a quick-and-dirty fix, which is not compatible with Kotlin and also not conform with the proposed fix, so it doesn't qualify for a pull request.)

I also created a custom variant of the javafx-gradle-plugin that applies this modified gradle-modules-plugin. With this custom javafx-gradle-plugin and with a lot of patching and additional exports, the application builds successfully.

However, jlink is not able to create the runtime image, due to this bug, which will hopefully be fixed soon.

I submitted a pull request with my changes to the build branch of @knakul853, so you can experiment with it. This PR should be regarded only as a proof-of-concept. For a proper solution we should wait until the gradle-modules-plugin adds supoort for patching multiple jars and a version of javafx-gradle-plugin applying it is released. Also, we need to wait until the above-mentioned jlink bug is fixed.

tomas-pluskal commented 4 years ago

Hi @siordache Thanks a lot, that is a super helpful analysis! I think at the moment using the badass-runtime plugin is the best option for us. But for the future modularization is clearly the way to go.

siordache commented 4 years ago

@tomas-pluskal I totally agree with you.