Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,15 @@ This repository has multiple entry points that may trigger compilation/build beh
wurst4vscode starts the server with `-XX:+AutoCreateSharedArchive`: the JVM writes an AppCDS archive next to the
compiler jar when the first session ends, and the sessions after it start from it. That archive sits on the
runtime's own base archive, which `deploy.gradle` makes (`jlink --generate-cds-archive`; macOS copies a full JDK, which
has one) and `assembleSlimCompilerDist` checks for. Without it the JVM silently runs without any archive, which is
how the earlier attempt went unnoticed. jlink writes the archive with a JVM of its own, which takes on the options it is started with: the
CI exports `JAVA_TOOL_OPTIONS=-XX:+UseCompactObjectHeaders`, so `deploy.gradle` removes it (and the other JVM option variables) for that
step, or only `classes_coh.jsa` is made, which a runtime started without that option cannot use. The extension passes `-Xlog:disable` because the JVM reports archive trouble
on stdout, which is the protocol stream: never print anything of your own there.
usually has one, and `assembleSlimCompilerDist` dumps one with `java -Xshare:dump` when the JDK has none: the Temurin
for macOS x64 on CI does not). `assembleSlimCompilerDist` then starts the runtime with `-Xshare:on`, which fails when
there is no usable archive. Without one the JVM silently runs without any, which is how the earlier attempt went
unnoticed. A base archive is written by a JVM which takes on the options it is started with: the CI exports
`JAVA_TOOL_OPTIONS=-XX:+UseCompactObjectHeaders`, so `deploy.gradle` removes it (and the other JVM option variables) for
the JVMs it starts, or only `classes_coh.jsa` is made, which a runtime started without that option cannot use. Pull-request
CI packages nothing (only pushes to master do, on every host), so a change here is not tested on macOS before it merges.
The extension passes `-Xlog:disable` because the JVM reports archive trouble on stdout, which is the protocol stream:
never print anything of your own there.

### Build-map pipeline (centralized)

Expand Down
32 changes: 30 additions & 2 deletions de.peeeq.wurstscript/deploy.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def jdepsPathProvider = javaHomeProvider.map { home ->
def jlinkPathProvider = javaHomeProvider.map { home ->
new File(home, "bin/jlink${os.isWindows() ? '.exe' : ''}").absolutePath
}
def javaExecutableName = os.isWindows() ? "java.exe" : "java"
def jmodsDirProvider = javaHomeProvider.map { home ->
new File(home, "jmods").absolutePath
}
Expand Down Expand Up @@ -97,6 +98,27 @@ abstract class JdepsRawTask extends DefaultTask {
}
}

/**
* Runs the java of a runtime image without the JVM option variables of the build machine: CI exports JAVA_TOOL_OPTIONS
* for its tests, and a base class data sharing archive takes on the options of the JVM which writes it (compact
* object headers make it classes_coh.jsa, which a JVM started without them cannot use).
*/
class RuntimeJava {
static String run(File java, List<String> options) {
def command = [java.absolutePath] + options
def pb = new ProcessBuilder(command)
pb.redirectErrorStream(true)
["JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "JDK_JAVA_OPTIONS"].each { pb.environment().remove(it) }
def process = pb.start()
def output = process.inputStream.getText("UTF-8")
def exit = process.waitFor()
if (exit != 0) {
throw new org.gradle.api.GradleException("`" + command.join(" ") + "` exited with " + exit + ": " + output)
}
return output
}
}

def fatJarProvider = tasks.named("shadowJar").flatMap { it.archiveFile } // Provider<RegularFile>

tasks.register("jdepsRaw", JdepsRawTask) {
Expand Down Expand Up @@ -228,10 +250,16 @@ tasks.register("assembleSlimCompilerDist", Copy) {
doLast {
logger.lifecycle("[dist] Folder ready at: ${distRoot.get().asFile}")
def runtime = new File(distRoot.get().asFile, "wurst-runtime")
def java = new File(runtime, "bin/" + javaExecutableName)
// jlink made the archive of the slim runtime, and a full JDK (macOS) normally brings its own, but not every
// build does: the Temurin for macOS x64 on CI has none. -Xshare:dump writes it next to the JVM library.
if (!["bin/server/classes.jsa", "lib/server/classes.jsa"].any { new File(runtime, it).exists() }) {
throw new GradleException("The runtime has no base CDS archive (classes.jsa under bin/server or lib/server), " +
"so the language server cannot start from an AppCDS archive.")
logger.lifecycle("[dist] The runtime has no base CDS archive, dumping it")
RuntimeJava.run(java, ["-Xshare:dump"])
}
// -Xshare:on makes the JVM fail when it has no usable base archive, where it would otherwise run without one
// and nobody would notice
RuntimeJava.run(java, ["-Xshare:on", "-version"])
}
}

Expand Down
Loading