I'm using the edu.sc.seis.launch4j plugin to build distributable applications using a gradle build script. I'm trying to produce these with a bundled JRE.
This is the gradle script
plugins {
id 'org.jetbrains.intellij' version '0.3.7'
id 'java'
id 'edu.sc.seis.launch4j' version '2.4.4'
}
group 'worldbuilders'
version '0.4.4-SNAPSHOT'
apply plugin: 'application'
sourceCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
}
mainClassName = 'hello.HelloWorld'
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
intellij {
version '2017.3.5'
}
launch4j {
bundledJrePath = "jre" //my jre to use is in the projectRoot/jre folder but I think that's not what this parameter is for anyway
mainClassName = 'hello.HelloWorld'
bundledJre64Bit = true
//icon = "${projectDir}/icons/myApp.ico"
}
Frustratingly this creates an application that runs (exe created by the gradle task createExe) but clearly doesn't have a JRE bundled in/next to it, presumably because it runs because it falls back to using the system jre, which makes testing things difficult. If I put a deliberately corrupted jre at /jre/ it still seems to run, which is even more confusing
How can i bundle a JRE with my exe distributable created using the gradle-launch4j plugin? (And that is actually used by the exe rather than using the system jre)
The debug XML created by the plugin (that is consumed by launch4j):
Created with the command gradle createExe -Pl4j-debug
<?xml version='1.0' encoding='UTF-8'?>
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>lib/onemillionworlds-0.4.4-SNAPSHOT.jar</jar>
<outfile>onemillionworlds.exe</outfile>
<errTitle></errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl>http://java.com/download</downloadUrl>
<supportUrl></supportUrl>
<stayAlive>false</stayAlive>
<restartOnCrash>false</restartOnCrash>
<manifest></manifest>
<icon></icon>
<classPath>
<mainClass>hello.HelloWorld</mainClass>
<cp>lib\onemillionworlds-0.4.4-SNAPSHOT.jar</cp>
<cp>lib\tools.jar</cp>
<cp>lib\jme3-lwjgl-3.2.0-stable.jar</cp>
<cp>lib\jme3-desktop-3.2.0-stable.jar</cp>
<cp>lib\jme3-core-3.2.0-stable.jar</cp>
<cp>lib\lwjgl-2.9.3.jar</cp>
<cp>lib\lwjgl-platform-2.9.3-natives-windows.jar</cp>
<cp>lib\lwjgl-platform-2.9.3-natives-linux.jar</cp>
<cp>lib\lwjgl-platform-2.9.3-natives-osx.jar</cp>
<cp>lib\jinput-2.0.5.jar</cp>
<cp>lib\jutils-1.0.0.jar</cp>
<cp>lib\jinput-platform-2.0.5-natives-linux.jar</cp>
<cp>lib\jinput-platform-2.0.5-natives-windows.jar</cp>
<cp>lib\jinput-platform-2.0.5-natives-osx.jar</cp>
</classPath>
<jre>
<path>jre</path>
<bundledJre64Bit>true</bundledJre64Bit>
<bundledJreAsFallback>false</bundledJreAsFallback>
<minVersion>1.8.0</minVersion>
<maxVersion></maxVersion>
<jdkPreference>jdkOnly</jdkPreference>
<runtimeBits>64/32</runtimeBits>
</jre>
<versionInfo>
<fileVersion>0.0.0.1</fileVersion>
<txtFileVersion>unspecified</txtFileVersion>
<fileDescription>onemillionworlds</fileDescription>
<copyright>unknown</copyright>
<productVersion>0.0.0.1</productVersion>
<txtProductVersion>unspecified</txtProductVersion>
<productName>onemillionworlds</productName>
<companyName></companyName>
<internalName>onemillionworlds</internalName>
<originalFilename>onemillionworlds.exe</originalFilename>
<trademarks></trademarks>
<language>ENGLISH_US</language>
</versionInfo>
</launch4jConfig>
Looking at this with 2 years distance I realise my question was effectively "I want Launch4J to behave exactly like a bat file". For the linux release I used the linux equivalent of a bat, an sh file, and in retrospect I should have done the same for the windows release.
The bundledJrePath config for launch4j is telling launch4j where to find the JRE, not where to put it, you must seperately put it there. And if launch4j can't find it it will use the installed JRE (or download one).
My relevant Gradle config ended up like this
launch4j { //used for windows
mainClassName = 'mygame.Main'
bundledJrePath = 'jre'
bundledJre64Bit = true
jreMinVersion = '11'
}
task packageExecutableDistribution(type: Zip) {
archiveName = "oneMillionWorlds.zip"
destinationDir = file("$buildDir/distExecutable")
from "$buildDir/launch4j"
}
task addJreToDistributable(type: Copy) {
from zipTree("resources/desktop-deployment/OpenJDK11U-jre_x64_windows_hotspot_11.0.4_11.zip")
destinationDir = file("$buildDir/launch4j")
}
packageExecutableDistribution.dependsOn createExe
packageExecutableDistribution.dependsOn addJreToDistributable
And my folder structure ended up like this
As its become a little hard to find JREs these days, you can find adoptium builds of JREs at https://adoptium.net/en-GB/temurin/releases/ or if you want to be able to programmatically grab JREs you can find links to them in json format from https://api.adoptium.net/v3/assets/feature_releases/[DESIRED_VERSION]/ga?image_type=jre
, so for example https://api.adoptium.net/v3/assets/feature_releases/19/ga?image_type=jre
Alternatively you can start with the JDK and use JLink to produce a minimal JRE for your use case