In the past I have been a great fan of Launch4j which I have used on projects like TemplateFx to create a single Windows executable for my Java application. This has always relied on the end user having a version of Java installed as it wasn’t able to support bundling a JRE into the actual EXE file.
Over the last 12 months or so the development model of Java has changed – instead of having a new release every 3 years, we are now seeing a new release every 6 months. Java 11 will also be the first release where we don’t have a public Oracle JRE available for non-commercial use. Oracle will continue to provide support for Java 8 up until 2019/2020, but beyond Java 8 they expect you to start using OpenJDK for non-commercial use (64-bit only as they dropped support for 32-bit with Java 9) and recommend you bundle OpenJDK with your applications – see http://www.oracle.com/technetwork/java/eol-135779.html.
With this in mind, I am looking at ways that I can continue to advance the code beyond Java 8, but still provide a solution that works for people – it is unlikely that people will upgrade beyond Java 8 as Oracle isn’t automatically updating people beyond it. It is also unlikely that people will go out of their way to download OpenJDK, hence the reason for this post.
Under Project Jigsaw introduced in Java 9, where the JRE is now split out into smaller run-time modules, it has now become feasible to start bundling a version of the JRE with your application (this does have some disadvantages unless you update your application when the JRE is updated). Historically if you tried to bundle a JRE with your application then you would end up with a 200MB executable, but this post will show you how I was able to bundle OpenJDK 10 with my TemplateFx distribution, taking up a total of around 25MB.
Once you have an up to date version of OpenJDK installed, your first step is to work out what modules your Java application requires. This is done using the jdeps
tool which will output a summary of all the modules that your JAR file is using:
jdeps -s TemplateFx.jar
For TemplateFx this results in the following output:
TemplateFx.jar -> java.base TemplateFx.jar -> java.datatransfer TemplateFx.jar -> java.desktop TemplateFx.jar -> java.naming TemplateFx.jar -> java.prefs TemplateFx.jar -> java.scripting
We can then use the jlink
tool to create our own smaller JRE which includes only those modules – this JRE will be placed into the “jre-10.0.2” directory. It also includes some optimisations which seriously reduce the size of the JRE – down from 68MB to around 38MB.
jlink --module-path "..\jdk-10.0.2\jmods" --add-modules java.base,java.datatransfer,java.desktop,java.naming,java.prefs,java.scripting,jdk.scripting.nashorn,jdk.naming.dns --output jre-10.0.2 --strip-debug --compress 2 --no-header-files --no-man-pages
We now have TemplateFx.jar as well as our cut down version of the JRE. I then opted to use NSIS (nullsoft scriptable install system) as it allows you to create a self extracting EXE file which will auto-run a command after extraction – as well as being totally silent to the user. The following configuration file was used with NSIS to create TemplateFx.exe.
!include LogicLib.nsh !include WinMessages.nsh !include FileFunc.nsh SilentInstall silent RequestExecutionLevel user ShowInstDetails hide OutFile "TemplateFx.exe" Icon "TemplateFx.ico" VIProductVersion 2.67.0.00000 VIAddVersionKey ProductName "TemplateFx" VIAddVersionKey LegalCopyright "Copyright (c) 2011-2018 Chris Mason" VIAddVersionKey FileDescription "Dynamic Templating Tool" VIAddVersionKey FileVersion 2.67.0.00000 VIAddVersionKey ProductVersion "2.67 / OpenJRE 10.0.2 (x64)" VIAddVersionKey InternalName "Templatefx" VIAddVersionKey OriginalFilename "TemplateFx.exe" Section SetOverwrite off SetOutPath "$TEMP\jre-10.0.2" File /r "jre-10.0.2\*" InitPluginsDir SetOutPath $PluginsDir File "TemplateFx.jar" SetOutPath $TEMP ${GetParameters} $R0 nsExec::Exec '"$TEMP\jre-10.0.2\bin\java.exe" -jar $PluginsDir\TemplateFx.jar $R0' RMDir /r $PluginsDir SectionEnd
The above script will produce TemplateFx.exe with the correct icon and application details – from looking at it you wouldn’t know it was NSIS. When it runs it will silently extract the relevant files into a temporary directory – it will store the JRE in “jre-10.0.2” so it can be re-used on subsequent executions. It will then finally execute TemplateFx using the extracted JRE.
General Java
Thoughts on "Creating a Windows Executable Bundled with Java OpenJDK"...
thanks for this!
Hi,
nice work. Thank You.
Did You find a way to create a Windows exe file from the runnable jar-file using Launch4j?
With a bundled JRE? No
How about not bundling JRE?
This is brilliant! Thanks for taking the trouble to post it.
I don’t think it’s necessary to include ‘LogicLib.nsh’, but I can’t see that it does any harm.
Maybe it’s a hangover from an earlier version when it was necessary.