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
105 changes: 100 additions & 5 deletions .github/workflows/extended-native-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ permissions:
env:
# thisisthepy/compose-multiplatform-core-extended, the commit the window modules and
# extended/skiko come from.
CORE_EXTENDED_REF: feb1e4c595debbe28a015cdd11a30f4713068bf4
CORE_EXTENDED_REF: fd733c8395fb24d107752a56d6893f486e46a62a
# The plugin as a local development build, asking for the core fork's Compose at its own
# version. The core fork's desktop Compose is built once from CORE_EXTENDED_REF, by the
# core-compose job (extended/ci/core-compose), and handed to the jobs that need it.
Expand Down Expand Up @@ -128,7 +128,7 @@ jobs:

- name: Plugin to mavenLocal
working-directory: gradle-plugins
run: ./gradlew --no-daemon -q :compose:publishToMavenLocal :jdk-version-probe:publishToMavenLocal -Pdeploy.version=${{ env.PLUGIN_VERSION }} -Pcompose.version=${{ env.COMPOSE_VERSION }}
run: ./gradlew --no-daemon -q :compose:publishToMavenLocal :jdk-version-probe:publishToMavenLocal -Pdeploy.version=${{ env.PLUGIN_VERSION }} -Pcompose.version=${{ env.COMPOSE_VERSION }} -Pcompose.material3.version=${{ env.COMPOSE_VERSION }}
- name: createDistributable
working-directory: extended/samples/hello-jvm
run: ./gradlew --no-daemon createDistributable
Expand Down Expand Up @@ -224,8 +224,7 @@ jobs:
- name: linux-arm64
os: ubuntu-24.04-arm
nik: vm-openjdk25.0.4.1+2-25.0.4.1+1-linux-aarch64
# The Kotlin/Native cells are the kn-* jobs below: their build is the core fork's
# toolchain, not packageNativeImage.
# The Kotlin/Native cells are the package-kn and kn-* jobs below.
runs-on: ${{ matrix.os }}
timeout-minutes: 240
env:
Expand Down Expand Up @@ -343,7 +342,7 @@ jobs:

- name: Plugin to mavenLocal
working-directory: gradle-plugins
run: ./gradlew --no-daemon -q :compose:publishToMavenLocal :jdk-version-probe:publishToMavenLocal -Pdeploy.version=${{ env.PLUGIN_VERSION }} -Pcompose.version=${{ env.COMPOSE_VERSION }}
run: ./gradlew --no-daemon -q :compose:publishToMavenLocal :jdk-version-probe:publishToMavenLocal -Pdeploy.version=${{ env.PLUGIN_VERSION }} -Pcompose.version=${{ env.COMPOSE_VERSION }} -Pcompose.material3.version=${{ env.COMPOSE_VERSION }}

# The AwtFree sample: packageNativeImage with the no-JAWT archive and the window layer.
- name: packageNativeImage (AwtFree sample)
Expand Down Expand Up @@ -484,6 +483,102 @@ jobs:
extended/native-image/*/build/reports/
if-no-files-found: ignore

# The same gate for a Kotlin/Native executable: hello-awtfree's content in the core fork's
# Kotlin/Native window (native-macos), linked by Gradle with the native desktop plugin against
# the core fork's macosArm64 Compose, then checked as the GraalVM images are. Linux cells join
# this matrix with the Linux window; Windows comes later.
package-kn:
name: One executable (Kotlin/Native, ${{ matrix.name }})
strategy:
fail-fast: false
matrix:
include:
- name: macos-arm64
os: macos-26
runs-on: ${{ matrix.os }}
timeout-minutes: 300
env:
SAMPLE_KN: extended/native-desktop/hello-awtfree-kn
steps:
- uses: actions/checkout@v4

- uses: actions/checkout@v4
with:
repository: thisisthepy/compose-multiplatform-core-extended
ref: ${{ env.CORE_EXTENDED_REF }}
path: core-extended
sparse-checkout: extended/window

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

# Built once per CORE_EXTENDED_REF and restored from the cache after that.
- name: The core fork's Compose for macosArm64
uses: ./extended/ci/core-compose
with:
ref: ${{ env.CORE_EXTENDED_REF }}
targets: macosArm64

- name: Cache the Kotlin toolchain and konan
uses: actions/cache@v4
with:
path: |
~/Library/Caches/JetBrains/Kotlin
~/.konan
key: kn-window-${{ matrix.name }}-${{ env.CORE_EXTENDED_REF }}-${{ hashFiles('extended/native-desktop/hello-awtfree-kn/*.kts') }}
restore-keys: |
kn-window-${{ matrix.name }}-

- name: Publish the Kotlin/Native window modules to mavenLocal
shell: bash
working-directory: core-extended/extended/window
run: |
set -euo pipefail
cp project.yaml project.yaml.all
printf 'modules:\n - common\n - native/macos\n' > project.yaml
./kotlin publish mavenLocal
cp project.yaml.all project.yaml
find ~/.m2/repository/org/thisisthepy/compose/window -name '*.module' | sort

- name: The native desktop plugin to mavenLocal
working-directory: gradle-plugins
run: ./gradlew --no-daemon --console=plain :kotlin-native-desktop:publishToMavenLocal -Pdeploy.version=0.1.0-extended-dev

- name: Link the Kotlin/Native sample
working-directory: ${{ env.SAMPLE_KN }}
run: ./gradlew --no-daemon --console=plain linkReleaseExecutableMacosArm64

- name: Stage the executable alone
shell: bash
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/kn-out"
cp "$SAMPLE_KN/build/bin/macosArm64/releaseExecutable/hello-awtfree-kn.kexe" "$RUNNER_TEMP/kn-out/hello-awtfree-kn"
otool -l "$RUNNER_TEMP/kn-out/hello-awtfree-kn" | grep -A 2 LC_RPATH | awk '/path /{print $2}' | while read -r rpath; do
install_name_tool -delete_rpath "$rpath" "$RUNNER_TEMP/kn-out/hello-awtfree-kn"
done
ls -la "$RUNNER_TEMP/kn-out"

- name: Take every ICU data file off the runner
shell: bash
run: |
{ find /usr /opt /Library /Applications /Users -name 'icudtl.dat' 2>/dev/null || true; } |
while IFS= read -r file; do echo "removing $file"; sudo rm -f "$file"; done

- name: One file, system libraries only, Korean with no ICU data, run alone
shell: bash
run: bash extended/native-image/check-one-executable.sh "$RUNNER_TEMP/kn-out" "$RUNNER_TEMP/one-executable"

- name: Keep the self-check drawing
if: always()
uses: actions/upload-artifact@v4
with:
name: one-executable-kn-${{ matrix.name }}
path: ${{ runner.temp }}/one-executable/*.png
if-no-files-found: ignore

# The same application as a Kotlin/Native executable for Linux: the content of hello-awtfree
# hosted by the core fork's scene in its Kotlin/Native X11 window (native/linux), built by the
# core fork's own toolchain as a module of its window project (extended/native-desktop/
Expand Down
16 changes: 15 additions & 1 deletion extended/ci/core-compose/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,26 @@ inputs:
runs:
using: composite
steps:
# Keyed by what the Compose build reads, not by the commit: the whole tree except extended/
# and .github/ (the fork's own modules and CI), plus the publishing script, as the core
# fork's own fork-compose action keys it. A commit that only changes the window modules
# then reuses the Compose already built, which for macosArm64 takes hours. Trees only are
# fetched, so working the key out costs seconds.
- name: Cache key
id: key
shell: bash
run: |
set -euo pipefail
targets="$(echo '${{ inputs.targets }}' | tr ' ' '\n' | sort | paste -sd- -)"
echo "key=core-compose-${{ runner.os }}-${{ runner.arch }}-$targets-${{ inputs.ref }}" >> "$GITHUB_OUTPUT"
probe="$RUNNER_TEMP/core-compose-key"
rm -rf "$probe"
git init -q "$probe"
git -C "$probe" fetch -q --depth=1 --filter=blob:none \
https://github.com/thisisthepy/compose-multiplatform-core-extended.git '${{ inputs.ref }}'
sources="$(git -C "$probe" ls-tree FETCH_HEAD | awk -F'\t' '$2 != "extended" && $2 != ".github" { print }' | git -C "$probe" hash-object --stdin)"
script="$(git -C "$probe" rev-parse FETCH_HEAD:extended/compose)"
rm -rf "$probe"
echo "key=core-compose-${{ runner.os }}-${{ runner.arch }}-$targets-$sources-$script" >> "$GITHUB_OUTPUT"

- name: Restore the core fork's Compose
id: restore
Expand Down
37 changes: 37 additions & 0 deletions extended/native-desktop/hello-awtfree-kn/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// The AWT-free sample as a Kotlin/Native macOS executable: the same Compose content as
// extended/native-image/hello-awtfree, in the core fork's Kotlin/Native AppKit and Metal window
// (org.thisisthepy.compose.window:native-macos), with no JVM at all. The one-executable gate
// checks it the way it checks the GraalVM images.
//
// ./gradlew linkReleaseExecutableMacosArm64
//
// Kotlin has to be at least the version the window klibs were compiled with: a klib from a newer
// compiler does not link.
plugins {
kotlin("multiplatform") version "2.4.10"
kotlin("plugin.compose") version "2.4.10"
id("org.thisisthepy.kotlin.native.desktop") version "0.1.0-extended-dev"
}

// The core fork's Compose and window modules, as compose-multiplatform-core-extended publishes
// them to the local Maven repository.
val compose = "1.11.1-ext.1"
val window = "1.11.1-ext.1"

kotlin {
macosArm64 {
binaries.executable {
baseName = "hello-awtfree-kn"
entryPoint = "awtfree.main"
}
}
sourceSets.macosMain {
dependencies {
implementation("org.thisisthepy.compose.window:common:$window")
implementation("org.thisisthepy.compose.window:native-macos:$window")
implementation("org.thisisthepy.compose.runtime:runtime:$compose")
implementation("org.thisisthepy.compose.foundation:foundation:$compose")
implementation("org.thisisthepy.compose.ui:ui:$compose")
}
}
}
2 changes: 2 additions & 0 deletions extended/native-desktop/hello-awtfree-kn/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kotlin.code.style=official
org.gradle.jvmargs=-Xmx3g
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading
Loading