Fix release ProGuard: Adoptium JDK 25 ships no jmods

Compose Desktop's AbstractProguardTask builds ProGuard's -libraryjars by
walking <javaHome>/jmods and nothing else. Adoptium stopped shipping the
jmods/ directory in JDK 25 archives (verified: 0 jmods entries in both the
linux/x64 and macOS/aarch64 Temurin 25.0.4.1 tarballs, vs 71 for Temurin
17), so on the runners the desktop packaging JDK resolves to
/usr/lib/jvm/temurin-25-jdk-amd64 and ProGuard gets no JDK whatsoever.
Every class then fails to resolve java.lang.Object — 1.3M
"can't find superclass or interface java.lang.Object" warnings, followed by
"Please correct the above warnings first".

This is why the Java 25 toolchain bump broke every release while the
v1.2.0-beta release on the toolchain 17 build kept working, and why a local
build with the JetBrains Runtime (which does ship jmods) succeeded while CI
did not. ProGuard's version was never the cause; 7.10.0 was still kept
because it is what understands this project's Kotlin 2.4 metadata.

Install Zulu 25 (still ships jmods) in the desktop-proguard job and export
it as FROMCHAT_PACKAGING_JDK; setup-java runs before Temurin 17 so JAVA_HOME
stays on 17 for Gradle and the Android build. resolvePackagingJdkHome() now
warns loudly when the JDK it picks has no jmods/, instead of leaving it to
ProGuard's wall of warnings.
This commit is contained in:
2026-10-16 18:45:41 +03:00
Unverified
parent 9192ef09d9
commit b0159eb987
3 changed files with 48 additions and 4 deletions
@@ -6,6 +6,16 @@ inputs:
description: Optional JDK architecture (x64). Omit for host default.
required: false
default: ""
desktop-jdk:
description: >
Optional desktop JDK version. When set, a Zulu build of it is installed and exported as
FROMCHAT_PACKAGING_JDK. Needed by anything that runs Compose Desktop's release/ProGuard
tasks: Adoptium stopped shipping the jmods/ directory in JDK 25 archives, and the Compose
plugin derives ProGuard's -libraryjars by walking <javaHome>/jmods. A JDK without jmods
leaves ProGuard with no java.* classes at all, so the build dies on ~1.3M
"can't find superclass or interface java.lang.Object" warnings. Zulu still ships jmods.
required: false
default: ""
cache-read-only:
description: Restore Gradle User Home only; do not save (avoids parallel cache write races).
required: false
@@ -14,12 +24,26 @@ inputs:
runs:
using: composite
steps:
# Installed first so setup-java leaves JAVA_HOME on Temurin 17 below: Gradle itself and the
# Android build must keep running on 17.
- uses: actions/setup-java@v5
if: inputs.desktop-jdk != ''
id: desktop-jdk
with:
distribution: zulu
java-version: ${{ inputs.desktop-jdk }}
- uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "17"
architecture: ${{ inputs.java-architecture }}
- name: Export the jmods-capable desktop JDK
if: inputs.desktop-jdk != ''
shell: bash
run: echo "FROMCHAT_PACKAGING_JDK=${{ steps.desktop-jdk.outputs.java-path }}" >> "$GITHUB_ENV"
- uses: gradle/actions/setup-gradle@v5
with:
gradle-version: wrapper
+2
View File
@@ -181,6 +181,8 @@ jobs:
with:
version: ${{ needs.resolve-version.outputs.version }}
- uses: ./.github/actions/setup-java-gradle
with:
desktop-jdk: "25"
- uses: ./.github/actions/cache-gradle-build
id: gradle-build-cache
with:
+22 -4
View File
@@ -263,6 +263,24 @@ fun resolvePackagingJdkHome(): String {
)
}
// Compose Desktop's release tasks run ProGuard on this JDK, and the Compose plugin builds
// ProGuard's -libraryjars by walking <javaHome>/jmods. Adoptium stopped shipping the jmods/
// directory with JDK 25 archives, so a jmods-less JDK leaves ProGuard with no java.* classes
// at all — the build then dies on a million "can't find superclass or interface
// java.lang.Object" warnings. Fail noisily here rather than in ProGuard's wall of text.
fun withJmods(home: String): String {
if (!File(home, "jmods").isDirectory) {
project.logger.warn(
"Packaging JDK $home ships no jmods/ directory. The release/ProGuard build needs " +
"one: Compose Desktop reads the JDK from <javaHome>/jmods, so ProGuard will " +
"report \"can't find superclass or interface java.lang.Object\" for every " +
"class and abort. Point FROMCHAT_PACKAGING_JDK at a JDK that ships jmods " +
"(e.g. Azul Zulu $desktopJvmTarget).",
)
}
return home
}
System.getenv("FROMCHAT_PACKAGING_JDK")?.takeIf { it.isNotBlank() }?.let { candidate ->
val major = jdkMajorVersion(File(candidate))
if (major != null && major < desktopJvmTarget) {
@@ -274,7 +292,7 @@ fun resolvePackagingJdkHome(): String {
"FROMCHAT_PACKAGING_JDK must be ARM64 on Windows ARM64 (os.arch=$arch): $candidate"
}
}
return candidate
return withJmods(candidate)
}
}
System.getenv("JAVA_HOME")?.takeIf { it.isNotBlank() }?.let { home ->
@@ -289,7 +307,7 @@ fun resolvePackagingJdkHome(): String {
"JAVA_HOME must be ARM64 on Windows ARM64 (os.arch=$arch): $home"
}
}
return home
return withJmods(home)
}
}
}
@@ -351,7 +369,7 @@ fun resolvePackagingJdkHome(): String {
if (major != null && major < desktopJvmTarget) return@firstOrNull false
if (!isWindowsArm64Host()) return@firstOrNull true
jdkReportsArch(File(home, "bin/java.exe")) == "aarch64"
}?.let { return it }
}?.let { return withJmods(it) }
// Toolchain fallback: foojay provisions the jvmToolchain JDK on every machine that builds
// this project, and the full JDK ships jpackage — so the bundled runtime always matches the
@@ -372,7 +390,7 @@ fun resolvePackagingJdkHome(): String {
if (isWindowsArm64Host() && jdkReportsArch(File(jdk, "bin/java.exe")) != "aarch64") {
return@forEach
}
return jdk.absolutePath.replace('\\', '/')
return withJmods(jdk.absolutePath.replace('\\', '/'))
}
error(