netnix.org
Networking and Unix


Creating a Windows Executable Bundled with Java OpenJDK

 July 19th, 2018Jul 19th, 2018        0

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


Leave a Reply

Comment:

Name:

e-mail Address: