beryx / badass-jlink-plugin

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

merged module and jpackage #26

Closed jperedadnr closed 5 years ago

jperedadnr commented 5 years ago

When you have non-modular dependencies and you use automatic module to include then in your module descriptor, that works fine for running your app or even using the jlink plugin to create a custom image.

However it doesn't work for the jpackage (ea) tool, as it fails saying that jlink (the built in tool) doesn't work with automatic modules.

I've done a quick test, where I replaced the module and the non-modular dependencies with the merged module resulting from the jlink plugin. I could successfully build the installer in this way. However when running the resulting app, it failed because it couldn't find the main class in this merged module.

So I was wondering if we could split the merged module in two modules: the app module without the non-modular dependencies, and the merged module with all those non-modular dependencies.

That would be useful as we could have, as a result of the jlink task, a folder with all the modules, and still set the module argument of jpackage to the app module (and not to the merged module).

siordache commented 5 years ago

I didn't try jpackage yet, but I'm very interested in adding support for it. I will look into it.

siordache commented 5 years ago

In the 2.6.0 release, all modularized artifacts (including the main module) are placed in the build/jlinkbase/jlinkjars directory. This makes the use of jpackage pretty straightforward.

The newly introduced jpackage task is able to create application installers for the current platform.

To test it on a non-trivial application I wrote this small FXGL game. The installers are correctly generated. The only problem is that on runtime FXGL needs to create some files in the application's current directory and crashes if it doesn't have the necessary permissions. However, this is an issue that should be addressed by FXGL and not by the jlink plugin. On Windows, it can be easily circumvented by using the --win-per-user-install option.

I'm curious if the jpackage task also works for your use case.

Burtan commented 5 years ago

it's crashing for me

The jpackage task is experimental. Use it at your own risk.
Error: Invalid Option: [--force]
siordache commented 5 years ago

Yes, build 17 (2019/2/13) of jpackage introduced a few breaking changes. For example, the --force option has been renamed to --overwrite. I made the necessary adjustments in 2.6.1. Please give it a try.

Burtan commented 5 years ago

Thanks, its now building. Still the jpackager version does not run. The jlink version with the script runs fine. I will try to make some adoptions to your kotlin example project tomorrow for an example, unless you want to do it yourself. Anyway thank you for the fast response, as always ;-)

siordache commented 5 years ago

What doesn't run? The generated installer or the application installed using the generated installer? Do you get some error messages?

I had problems with missing permissions for applications that try to store data in the current directory. On Windows, I solved this problem by putting the following line in the jpackage script block:

installerOptions = ['--win-per-user-install', '--win-dir-chooser']

Also, '--win-console' may help to see the error messages on Windows.

On Linux, my workaround for problems caused by missing write permissions was to start the installed application with sudo.

Burtan commented 5 years ago

The application installed using the generated installer doesn't start. On Linux: Error: Could not find or load main class app.livesets.manager.LiveSetsManager in module livesets.manager.app On Windows I don't get any error message, it just does nothing, even with --win-console

siordache commented 5 years ago

I'm not sure why this happens. Can you post your build.gradle.kts and the output of:

./gradlew -is clean jpackage
jperedadnr commented 5 years ago

Using 2.6.1 with jpackage build 27, fails for me on my hellofx sample:

Successfully started process 'command '/path/to/Downloads/jdk-13.jdk/Contents/Home/bin/jpackage''
Error: App image directory "/path/to/hellofx/build/jpackage/hellofx" does not exist

I see that you are trying to use --app-image, and I take that comes from the result of jlink, but the path seems wrong:

Starting process 'command '/path/to/Downloads/jdk-13.jdk/Contents/Home/bin/jpackage''. 
Working directory: /path/to/hellofx 
Command: /path/to/Downloads/jdk-13.jdk/Contents/Home/bin/jpackage create-installer 
--overwrite --output /path/to/hellofx/build/jpackage --name hellofx
 --app-image /path/to/hellofx/build/jpackage/hellofx

The --app-image path has jpackage/hellofx, but on Mac, I have jpackage/hellofx.app, that contains Contents/Java (with a cfg file), Contents/MacOS (with a hellofx script), Contents/Plugins (with Java.runtime/Contents), Contents/Resources (with icon).

If run manually the same jpackage command as above but ending in jpackage/hellofx.app, I get:

Error: App image directory "/path/to/hellofx/build/jpackage/hellofx.app" does not 
contain "app" sub-directory

Exactly the same happens with your puzzle sample.

I'm not sure if this a problem with the jpackage tool itself, as I've already tried --app-image on Mac before to no avail. Probably related to this issue JDK-8217902

Burtan commented 5 years ago

Hi, I got it working now, although I didn't really change anything. Must have been some build errors. However, I didn't find a way to add JvmArgs.

jperedadnr commented 5 years ago

By the way, the jpackage task works fine for me on Windows.

siordache commented 5 years ago

@Burtan The jvmArgs configured in the launcher script block also apply for jpackage.

siordache commented 5 years ago

@jperedadnr On Mac OS the output of jpackage create-image is AppName.app, which looks like a bug to me. As a workaround, in 2.6.3 the plugin moves this output to AppName/app .

Now, without additional installerOptions, jpackage fails on Mac OS because the app is not signed.

Wth the --mac-sign option, it complains about not finding a signing key.

I stopped my experiments here because I don't have a Mac, but I think jpackage will succeed if the --mac-signing-key-user-name and --mac-signing-keychain options are also configured with appropriate values. Maybe you can make it work for your hellofx sample.

jperedadnr commented 5 years ago

I get to the same point you do, I can look into getting some keys to sign it tomorrow.

The weird thing is I've use the jpackage tool a few times already, never needed to sign the app

Burtan commented 5 years ago

@Burtan The jvmArgs configured in the launcher script block also apply for jpackage.

This is not the case for me. Using the jlink image the args work, using the jpackage installer, it doesn't. Tested on linux.

siordache commented 5 years ago

You're right. I also noticed that it doesn't work. It's fixed in 2.6.4. Now you can either rely on the jvmArgs configured in the launcher block or you can provide specific jvmArgs in the jpackage block. See the documentation of the jpackage block.

Burtan commented 5 years ago

thanks for the fix. I now have jpackage working on linux, however on windows I can install and start the app, but there seem to be some dependecies missing as not every function works. But I cannot get any error logs, even with --win-console.

Edit: I'm now getting the errors with --win-console in imageOptions. There seem to be some different module dependencies on windows compared to linux. I'm trying to change some opens/exports.

With some additional opens on my library I got it working on windows now!

Burtan commented 5 years ago

Hey, I got some troubles adding jpackage options. For example --app-version should add a version number. However it throws an error or doesn't have an effect: installerOptions.add("--app-version 1.2.3") -> error: Invalid Option imageOptions.add("--app-version 1.2.3") -> error: Invalid Option options.add("--app-version 1.2.3") -> no effect

Ok I got it: installerOptions.add("--app-version", "1.2.3")

siordache commented 5 years ago

This should also work:

jlink {
    ...
    jpackage {
        ...    
        imageOptions = listOf("--app-version", "1.2.3")
        installerOptions = listOf("--app-version", "1.2.3")
    }
}
lenborje commented 5 years ago

@jperedadnr On Mac OS the output of jpackage create-image is AppName.app, which looks like a bug to me. As a workaround, in 2.6.3 the plugin moves this output to AppName/app .

That is not a bug, it's a feature! In the Mac Finder (i.e. desktop file browser) the directory will be displayed as "AppName" even if the directory is called "AppName.app". Finder picks up the "user friendly name", which can be localised etc, from the Contents/Info.plist file.

But there really is a bug in the current jpackagepreview download, which requires the presence of a sub-directory called app. This bug has been corrected in hg bug 8217902, but it has not yet propagated to the early access download.

Anyway, this means that is wrong to move to output to "appName/app". For the moment, due to bug 8217902 (using the current jdk13+jpackage download), one must create an empty subdirectory called AppName.app/app, but copying the whole thing actually prevents Finder from recognising the directory as an app!

lenborje commented 5 years ago

Now, without additional installerOptions, jpackage fails on Mac OS because the app is not signed.

This must be a bug in jpackage. If you don't specify any installer type all supported types should be created. The previous javafxpackager simply skipped the ones it couldn't create, so even while I got the same error message before, I still got both a pkg and a dmg.

Currently it seems I must call jpackage create-installer twice, first with --installer-type pkgand then with --installer-type dmg.

siordache commented 5 years ago

Thanks for pointing this out, @lenborje ! I will adjust the plugin when the next early access build of jpackage becomes available.

jperedadnr commented 5 years ago

FYI, I've tested jpackage from build 36 (2019/3/28), with the plugin 2.8.0, and it works fine on Mac.

I've tried a simple hellofx app, and also the puzzle sample. For the latter I had to remove the jvmArgs arguments, as I was getting:

Error: Invalid Option: [--jvm-args]

Without it, it worked fine. Running directly fxgl-sliding-puzzle.app works, and running the installer fxgl-sliding-puzzle.dmg works too, but when running the app: /Volumes/fxgl-sliding-puzzle/fxgl-sliding-puzzle.app/Contents/MacOS/fxgl-sliding-puzzle I get:

Error during launch:
java.nio.file.FileSystemException: logs: Read-only file system
    at java.base/sun.nio.fs.UnixException.translateToIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(Unknown Source)
    at java.base/sun.nio.fs.UnixFileSystemProvider.createDirectory(Unknown Source)
    at java.base/java.nio.file.Files.createDirectory(Unknown Source)
    at sslogger.main/com.almasb.sslogger.FileOutput.getOrCreateLogDir(Unknown Source)
    at sslogger.main/com.almasb.sslogger.FileOutput.<init>(Unknown Source)
    at sslogger.main/com.almasb.sslogger.FileOutput.<init>(Unknown Source)
    at sslogger.main/com.almasb.sslogger.FileOutput.<init>(Unknown Source)
    at fxgl.all/com.almasb.fxgl.app.GameApplication.initLogger(Unknown Source)
    at fxgl.all/com.almasb.fxgl.app.GameApplication.launch(Unknown Source)
    at fxgl.all/com.almasb.fxgl.app.GameApplication.launch(Unknown Source)
    at org.beryx.fxgl.puzzle/org.beryx.fxgl.puzzle.SlidingPuzzle.main(Unknown Source)

Which is probably related to the game itself trying to write the log in Volumes (read only), not to jpackage.

lenborje commented 5 years ago

Cf. issue #44.

siordache commented 5 years ago

@jperedadnr, @lenborje Thanks for the info. In release 2.9.0 I replaced --jvm-args with --java-options.

The sliding puzzle uses FXGL, which needs to create some files in the application's current directory. On Windows, I configured the --win-per-user-install option to avoid the read-only issue. On Linux, my workaround was to start the installed application with sudo.

danielpeintner commented 5 years ago

Thanks for the plugin in the first place!

Having said that, I have a similar issue mentioned before in this thread.

Everything works fine, no errors or so for gradle jlink or gradle jpackage and it creates executables and installers under "build\jpackage"

However, once I try to run the executable nothing happens. No failure or any other information. It just does not happen anything.

I am not sure what I can share else. Hence I did upload this simple test on Github (https://github.com/danielpeintner/Java11Test)

I am on Windows and use the latest jpackage (Build 36 (2019/3/28)). I tried older versions also but same issue.

FYI: gradle run etc works just fine.

siordache commented 5 years ago

Executing the runtime image produced by jlink (build\image\bin\hello-fx.bat) I got the following error:

class org.controlsfx.control.HyperlinkLabel (in module org.controlsfx.controls) cannot access class com.sun.javafx.event.EventHandlerManager (in module javafx.base) because module javafx.base does not export com.sun.javafx.event to module org.controlsfx.controls

To fix this problem put the following in the jlink block:

jvmArgs = ["--add-exports", "javafx.base/com.sun.javafx.event=org.controlsfx.controls"]
danielpeintner commented 5 years ago

@siordache Thanks, this solved my issue.

Sorry, I am still not very familiar with where to put similar statements for --add-opens, --add-exports, etc.

jperedadnr commented 5 years ago

@siordache I guess we can close this issue now?

FYI: See https://openjfx.io/openjfx-docs/#modular (section modular with Gradle), and IDE links for modular with Gradle as well... 😃

siordache commented 5 years ago

@jperedadnr Yes, we can close it now. And I'm glad to see the plugin mentioned on the OpenJFX site.