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
30 changes: 29 additions & 1 deletion .github/workflows/extended-native-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,15 @@ jobs:
run: |
perl -0pi -e 's/^ platforms: \[ jvm, macosArm64 \]$/ platforms: [ jvm ]/m' scene/module.yaml
grep -q '^ platforms: \[ jvm \]$' scene/module.yaml
perl -0pi -e 's/^ platforms: \[.*\]$/ platforms: [ jvm ]/m' common/module.yaml
grep -q '^ platforms: \[ jvm \]$' common/module.yaml
- name: Publish the window modules to mavenLocal
shell: bash
working-directory: core-extended/extended/window
run: |
set -euo pipefail
mkdir -p ~/.cache/JetBrains/Kotlin/download.cache
curl -fsSL -o ~/.cache/JetBrains/Kotlin/download.cache/bd467c5b70-OpenJDK25U-jdk_x64_linux_hotspot_25.0.5_8.tar.gz "https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.5%2B8/OpenJDK25U-jdk_x64_linux_hotspot_25.0.5_8.tar.gz" || true
cp project.yaml project.yaml.all
printf 'modules:\n' > project.yaml
for m in common scene graalvm/graalvm-macos graalvm/graalvm-linux; do printf ' - %s\n' "$m" >> project.yaml; done
Expand Down Expand Up @@ -253,7 +257,7 @@ jobs:
sudo apt-get install -y -q --no-install-recommends \
build-essential pkg-config xvfb xauth libgl1-mesa-dev libegl-dev libgl1-mesa-dri \
libx11-dev libxext-dev libxi-dev libxrender-dev libxtst-dev libxrandr-dev libxcursor-dev \
libfontconfig1-dev libfreetype-dev libdbus-1-dev zlib1g-dev fonts-noto-cjk jq gdb
libfontconfig1-dev libfreetype-dev libdbus-1-dev zlib1g-dev fonts-noto-cjk jq gdb strace

- name: GraalVM 25 (Liberica NIK, or upstream where the cell names it)
shell: bash
Expand Down Expand Up @@ -302,12 +306,23 @@ jobs:
run: |
perl -0pi -e 's/^ platforms: \[ jvm, macosArm64 \]$/ platforms: [ jvm ]/m' scene/module.yaml
grep -q '^ platforms: \[ jvm \]$' scene/module.yaml
perl -0pi -e 's/^ platforms: \[.*\]$/ platforms: [ jvm ]/m' common/module.yaml
grep -q '^ platforms: \[ jvm \]$' common/module.yaml
- name: Publish the window modules to mavenLocal
if: runner.os == 'macOS'
shell: bash
working-directory: core-extended/extended/window
run: |
set -euo pipefail
if [ "$RUNNER_OS" = macOS ]; then
cache="$HOME/Library/Caches/JetBrains/Kotlin/download.cache"
mkdir -p "$cache"
curl -fsSL -o "$cache/f8362503fc-OpenJDK25U-jdk_aarch64_mac_hotspot_25.0.5_8.tar.gz" "https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.5%2B8/OpenJDK25U-jdk_aarch64_mac_hotspot_25.0.5_8.tar.gz" || true
elif [ "$RUNNER_OS" = Linux ]; then
cache="$HOME/.cache/JetBrains/Kotlin/download.cache"
mkdir -p "$cache"
curl -fsSL -o "$cache/bd467c5b70-OpenJDK25U-jdk_x64_linux_hotspot_25.0.5_8.tar.gz" "https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.5%2B8/OpenJDK25U-jdk_x64_linux_hotspot_25.0.5_8.tar.gz" || true
fi
# The module lists are core-extended's own extended-window-publish matrix.
# The samples link the GraalVM window layers, and hello-awtfree hosts a scene in them.
# native/macos is the Kotlin/Native window and compiles against the core fork's
Expand Down Expand Up @@ -430,6 +445,19 @@ jobs:
else
bash extended/native-image/check-one-executable.sh "$out" "$RUNNER_TEMP/one-executable"
fi
# Said here rather than left out: an application built from source with this plugin needs a
# JDK on the machine that builds it, because Gradle, the Kotlin compiler and native-image
# all run on one. Needing nothing but the platform's linker holds only where the renderer
# arrives already built, as compose-rust's does (its build script downloads it); it cannot
# hold for this build, so this gate does not check it.
- name: What this gate does not check, and why
shell: bash
run: |
echo "The executable checked above needs no Java runtime to run. Building it did need one:"
echo " java: $(java -version 2>&1 | head -1)"
echo " native-image: $("$GRAALVM_HOME/bin/native-image" --version 2>&1 | head -1)"
echo "A build that needs only the platform's linker is one whose renderer arrives prebuilt."

- name: Keep the self-check drawing
if: always()
uses: actions/upload-artifact@v4
Expand Down
7 changes: 6 additions & 1 deletion extended/native-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,12 @@ syllable whole, lines broken between words), draws it into a PNG, and presents f
Compose content in its window, none at a size other than the window's. `hello-awtfree` is a
Compose application with no AWT: the core fork's scene module hosts its content in the GraalVM
window, through the window's own surface (`appKitWindowSurface`, `x11WindowSurface`). A run
that does not end within 120 s is stopped with every thread's stack printed.
that does not end within 120 s is stopped with every thread's stack printed. It then runs the
executable once more, watched (every file it touches on Linux, through `strace`; every library
it loads on macOS, through `DYLD_PRINT_LIBRARIES`), and fails if it looks for a Java runtime:
anything under the JDK or GraalVM on the runner, a module image, `jvm.cfg`, `libjvm` or
`libjava`. What the gate does not check is the build machine: building from source needs a JDK,
for Gradle, the Kotlin compiler and native-image, and the gate says so in a step of its own.
An executable that needs an ICU data file shows it there: a double click would select one
syllable, and lines would wrap inside words.

Expand Down
48 changes: 47 additions & 1 deletion extended/native-image/check-one-executable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ fi
fail() {
echo "fail $1" >&2
shift
for line in "$@"; do echo " $line" >&2; done
for arg in "$@"; do
while IFS= read -r line; do [[ -n "$line" ]] && echo " $line" >&2; done <<< "$arg"
done
exit 1
}

Expand Down Expand Up @@ -189,4 +191,48 @@ if grep -E '^(java|kotlin|org)\.[A-Za-z0-9_.$]*(Exception|Error)\b' "$log"; then
fi
[[ "$status" -eq 0 ]] || fail "the executable did not run to the end on its own (exit $status)"

# 5. A native image carries its own runtime, so running it must not look for a Java one: no file
# under a JDK or GraalVM, no module image, no jvm.cfg, no libjvm or libjava loaded. Run once more,
# alone, watched: every file access on Linux (strace), every library loaded on macOS (dyld).
runtime_log="$scratch/runtime.log"
case "$os" in
linux)
command -v strace > /dev/null || fail "strace is not installed" "It is how the run is watched for a Java runtime."
( cd "$scratch/run" && HELLO_SELF_CHECK="$scratch/again.png" timeout 120 \
strace -f -qq -e trace=file -o "$runtime_log" "./$name" ) > /dev/null 2>&1 || true
accessed="$(sed -n 's/.*"\(\/[^"]*\)".*/\1/p' "$runtime_log" | sort -u)"
;;
macos)
( cd "$scratch/run" && HELLO_SELF_CHECK="$scratch/again.png" DYLD_PRINT_LIBRARIES=1 exec "./$name" ) > "$runtime_log" 2>&1 &
pid=$!
for _ in $(seq 120); do kill -0 "$pid" 2>/dev/null || break; sleep 1; done
if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
else
wait "$pid" 2>/dev/null || true
fi
accessed="$(sed -n 's/^dyld\[[0-9]*\]: <[^>]*> //p; s/^dyld\[[0-9]*\]: //p' "$runtime_log" | awk '{print $1}' | sort -u)"
;;
windows) accessed="" ;;
esac
[[ "$os" == windows || -n "$accessed" ]] || fail "watching the run recorded nothing, so it proves nothing" "$(tail -5 "$runtime_log")"
java_paths=()
for home in "${GRAALVM_HOME:-}" "${JAVA_HOME:-}"; do [[ -n "$home" ]] && java_paths+=("$home"); done
found=""
while IFS= read -r path; do
[[ -n "$path" && "$path" == /* ]] || continue
case "$path" in
*/lib/modules|*/jvm.cfg|*/libjvm.*|*/libjava.*|*/conf/security/java.security) found+="$path"$'\n'; continue ;;
esac
for home in "${java_paths[@]+"${java_paths[@]}"}"; do
[[ "$path" == "$home"/* ]] && found+="$path"$'\n'
done
if [[ "$os" == macos ]]; then
case "$path" in /usr/lib/*|/System/*) ;; *) [[ "$path" == "$scratch/run/$name" ]] || found+="$path (a library outside the system)"$'\n' ;; esac
fi
done <<< "$accessed"
[[ -z "$found" ]] || fail "running the executable looked for a Java runtime or a library of its own" "$found"
echo "-- run watched ($( [[ "$os" == macos ]] && echo "every library loaded" || echo "every file accessed")): $(wc -l <<< "$accessed" | tr -d ' ') paths, none in a Java runtime"

echo "ok $name is one executable: system libraries only, Korean laid out with no ICU data file"
Loading