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
192 changes: 184 additions & 8 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: 57b4a0e102d837ba3271699297b69278fcefedef
CORE_EXTENDED_REF: feb1e4c595debbe28a015cdd11a30f4713068bf4
# 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 @@ -178,7 +178,7 @@ jobs:
shell: bash
working-directory: core-extended/extended/window
run: |
perl -0pi -e 's/^ platforms: \[ jvm, macosArm64 \]$/ platforms: [ jvm ]/m' scene/module.yaml
perl -0pi -e 's/^ platforms: \[.*\]$/ 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
Expand Down Expand Up @@ -224,11 +224,8 @@ jobs:
- name: linux-arm64
os: ubuntu-24.04-arm
nik: vm-openjdk25.0.4.1+2-25.0.4.1+1-linux-aarch64
# Kotlin/Native packaging cells go here. Each one runs check-native-config.sh (already
# scans extended/window/native) and, after linking, `nm` on the executable for
# Objective-C or class-name lookups; see the K/N section of the plugin change list.
# Kotlin/Native packaging cells go here. The K/N window agent adds them: one per
# platform, building the native window modules into an executable and starting it.
# The Kotlin/Native cells are the kn-* jobs below: their build is the core fork's
# toolchain, not packageNativeImage.
runs-on: ${{ matrix.os }}
timeout-minutes: 240
env:
Expand Down Expand Up @@ -304,7 +301,7 @@ jobs:
shell: bash
working-directory: core-extended/extended/window
run: |
perl -0pi -e 's/^ platforms: \[ jvm, macosArm64 \]$/ platforms: [ jvm ]/m' scene/module.yaml
perl -0pi -e 's/^ platforms: \[.*\]$/ 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
Expand Down Expand Up @@ -445,6 +442,19 @@ jobs:
else
bash extended/native-image/check-one-executable.sh "$out" "$RUNNER_TEMP/one-executable"
fi
# The window chrome and a screen reader, on the same executable: openbox drags its caption
# and every edge, double clicks to maximise, and libatspi walks its AT-SPI tree for the
# field, its label and the button, sets the field and presses the button and Close.
- name: Window chrome and a reader (openbox and at-spi2, under a virtual display)
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
sudo apt-get install -y -q --no-install-recommends openbox xdotool x11-utils dbus at-spi2-core libatspi2.0-dev
out="$(find "$SAMPLE_AWTFREE/build/compose/native-image" -mindepth 1 -maxdepth 1 -type d | head -1)"
exe="$(find "$out" -mindepth 1 -maxdepth 1 -type f | head -1)"
bash extended/native-image/check-linux-chrome.sh "$exe" core-extended "$RUNNER_TEMP/chrome"

# 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
Expand Down Expand Up @@ -473,3 +483,169 @@ jobs:
extended/native-image/*/build/tmp/packageNativeImage/**/*.log
extended/native-image/*/build/reports/
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/
# hello-awtfree says why). Kotlin/Native has no arm64 Linux host, so both architectures are
# built here on x86-64; the arm64 executable is linked against the arm64 desktop libraries
# and run on an arm64 runner by kn-linux-arm64.
kn-build:
name: Build (Kotlin/Native, linux-x64 and linux-arm64)
runs-on: ubuntu-24.04
timeout-minutes: 240
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
extended/native-desktop/hello-awtfree
extended/native-image/hello-awtfree/src/main/kotlin
extended/ci
- uses: actions/checkout@v4
with:
repository: thisisthepy/compose-multiplatform-core-extended
ref: ${{ env.CORE_EXTENDED_REF }}
path: core-extended
sparse-checkout: extended/window
- name: Make room for the Compose build
run: |
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup /usr/local/share/boost \
/opt/hostedtoolcache/CodeQL /usr/share/swift /usr/local/share/powershell \
/usr/local/lib/node_modules /usr/local/julia* /opt/microsoft /opt/google
df -h /
- name: The X11, GL, fontconfig and FreeType development libraries
run: |
sudo apt-get update -q
sudo apt-get install -y -q pkg-config libx11-dev libxext-dev libgl1-mesa-dev \
libfontconfig1-dev libfreetype6-dev
# The arm64 executable is linked here, so the arm64 libraries it names have to be here,
# where native/linux's x11.def looks for them (/usr/lib/aarch64-linux-gnu).
- name: The arm64 desktop libraries to link against
run: |
set -euo pipefail
sudo dpkg --add-architecture arm64
for sources in /etc/apt/sources.list.d/*.sources; do
sudo sed -i '/^Types: deb$/a Architectures: amd64' "$sources"
done
[[ ! -f /etc/apt/sources.list ]] || sudo sed -i 's/^deb \(http\)/deb [arch=amd64] \1/' /etc/apt/sources.list
printf '%s\n' 'Types: deb' 'URIs: http://ports.ubuntu.com/ubuntu-ports' \
'Suites: noble noble-updates noble-security' 'Components: main universe' \
'Architectures: arm64' | sudo tee /etc/apt/sources.list.d/arm64-ports.sources
sudo apt-get update -q
sudo apt-get install -y -q libx11-dev:arm64 libxext-dev:arm64 libgl-dev:arm64 libegl-dev:arm64 \
libfontconfig-dev:arm64 libfreetype-dev:arm64
# Both architectures, because native/linux declares both and the toolchain resolves every
# platform a module declares.
- name: The core fork's Compose for Kotlin/Native Linux
uses: ./extended/ci/core-compose
with:
ref: ${{ env.CORE_EXTENDED_REF }}
targets: linuxX64 linuxArm64
- name: Cache the Kotlin toolchain
uses: actions/cache@v4
with:
path: |
~/.konan
~/.cache/JetBrains/Kotlin
key: kn-hello-linux-${{ env.CORE_EXTENDED_REF }}
restore-keys: kn-hello-linux-
# The sample becomes a module of the window project, with its links followed. The scene
# declares the JVM and macOS as well, whose Compose is not built here, so it is built as
# the Linux module it is for this executable; the sample is built for one architecture
# at a time.
- name: The sample as a module of the core fork's window project
shell: bash
working-directory: core-extended/extended/window
run: |
set -euo pipefail
mkdir -p samples
cp -RL "$GITHUB_WORKSPACE/extended/native-desktop/hello-awtfree" samples/hello-awtfree
ls -la samples/hello-awtfree/src
perl -0pi -e 's/^ platforms: \[.*\]$/ platforms: [ linuxX64, linuxArm64 ]/m' scene/module.yaml
printf 'modules:\n - common\n - scene\n - native/linux\n - native/linux-scene\n - samples/hello-awtfree\n' > project.yaml
cat project.yaml
- name: Build the executables
shell: bash
working-directory: core-extended/extended/window
run: |
set -euo pipefail
for cell in linux-x64:linuxX64 linux-arm64:linuxArm64; do
name="${cell%%:*}"; platform="${cell#*:}"
perl -0pi -e "s/^ platforms: \\[.*\\]\$/ platforms: [ $platform ]/m" samples/hello-awtfree/module.yaml
grep -n '^ platforms:' samples/hello-awtfree/module.yaml
rm -rf build/tasks/*hello-awtfree*
./kotlin build -m hello-awtfree -p "$platform"
exe="$(find build -type f -name '*.kexe' -path '*hello-awtfree*' | head -1)"
[[ -n "$exe" ]] || { echo "no executable under build/:" >&2; find build -name '*.kexe' >&2; exit 1; }
mkdir -p "$RUNNER_TEMP/kn-out-$name/hello-awtfree"
cp "$exe" "$RUNNER_TEMP/kn-out-$name/hello-awtfree/hello-awtfree"
file "$RUNNER_TEMP/kn-out-$name/hello-awtfree/hello-awtfree"
done
- uses: actions/upload-artifact@v4
with:
name: kn-hello-awtfree-linux-x64
path: ${{ runner.temp }}/kn-out-linux-x64
retention-days: 3
- uses: actions/upload-artifact@v4
with:
name: kn-hello-awtfree-linux-arm64
path: ${{ runner.temp }}/kn-out-linux-arm64
retention-days: 3

# The gate the GraalVM cells run, on the Kotlin/Native executable, on its own architecture:
# one file, only the system's libraries, Korean laid out with no ICU data file, the Compose
# content presented at the window's size; then the window chrome and a screen reader.
kn-run:
needs: kn-build
name: One executable (Kotlin/Native, ${{ matrix.name }})
strategy:
fail-fast: false
matrix:
include:
- { name: linux-x64, os: ubuntu-24.04 }
- { name: linux-arm64, os: ubuntu-24.04-arm }
runs-on: ${{ matrix.os }}
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: extended/native-image
- uses: actions/checkout@v4
with:
repository: thisisthepy/compose-multiplatform-core-extended
ref: ${{ env.CORE_EXTENDED_REF }}
path: core-extended
sparse-checkout: extended/window/scripts
- uses: actions/download-artifact@v4
with:
name: kn-hello-awtfree-${{ matrix.name }}
path: ${{ runner.temp }}/kn-out
- name: Linux packages
run: |
sudo apt-get update -q
sudo apt-get install -y -q --no-install-recommends xvfb xauth libgl1-mesa-dri libglx-mesa0 libegl1 \
libx11-6 libxext6 libfontconfig1 libfreetype6 fonts-noto-cjk binutils gdb build-essential pkg-config \
openbox xdotool x11-utils dbus at-spi2-core libatspi2.0-dev
chmod +x "$RUNNER_TEMP/kn-out/hello-awtfree/hello-awtfree"
- name: Take every ICU data file off the runner
shell: bash
run: |
{ find /usr /opt /Library /Applications /home /Users /snap -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: |
xvfb-run -a -s '-screen 0 1280x1024x24' bash extended/native-image/check-one-executable.sh \
"$RUNNER_TEMP/kn-out/hello-awtfree" "$RUNNER_TEMP/one-executable"
- name: Window chrome and a reader (openbox and at-spi2, under a virtual display)
shell: bash
run: |
bash extended/native-image/check-linux-chrome.sh "$RUNNER_TEMP/kn-out/hello-awtfree/hello-awtfree" \
core-extended "$RUNNER_TEMP/chrome"
- 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
4 changes: 2 additions & 2 deletions extended/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,8 @@ The plugin is published under this fork's own name, so that it can sit beside Je
`-ext.<N>-dev` for a local build. The probes and samples use `1.11.1-ext.1-dev`.
- the aliases (`compose.desktop.currentOs`, `compose.foundation`, `compose.material3` and the rest)
resolve to compose-multiplatform-core-extended's `org.thisisthepy.compose.*` libraries at
`-Pcompose.version` (`1.11.1-ext.1`) and `-Pcompose.material3.version`
(`1.11.0-alpha07-ext.1`). `compose("org.jetbrains.compose.ui:ui")` is turned into the fork's
`-Pcompose.version` and `-Pcompose.material3.version` (`1.11.1-ext.1`).
`compose("org.jetbrains.compose.ui:ui")` is turned into the fork's
coordinate too.
- the components and Compose HTML stay JetBrains', at the upstream version (`1.11.1`), because
the core fork does not build them.
Expand Down
2 changes: 1 addition & 1 deletion extended/README_ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ compose.desktop.application {
로컬 빌드는 `-ext.<N>-dev` 이고, probe 와 예제는 `1.11.1-ext.1-dev` 를 씁니다.
- 별칭(`compose.desktop.currentOs`, `compose.foundation`, `compose.material3` 등)은
compose-multiplatform-core-extended 의 `org.thisisthepy.compose.*` 라이브러리를 `-Pcompose.version`
(`1.11.1-ext.1`)과 `-Pcompose.material3.version`(`1.11.0-alpha07-ext.1`)으로 가리킵니다.
과 `-Pcompose.material3.version`(`1.11.1-ext.1`)으로 가리킵니다.
`compose("org.jetbrains.compose.ui:ui")` 도 포크의 좌표로 바뀝니다.
- components 와 Compose HTML 은 JetBrains 것을 업스트림 버전(`1.11.1`)으로 씁니다. core 포크가
빌드하지 않기 때문입니다.
Expand Down
76 changes: 76 additions & 0 deletions extended/native-desktop/hello-awtfree/module.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# The AWT-free sample as a Kotlin/Native executable for Linux: the same Compose content as
# extended/native-image/hello-awtfree, hosted by the core fork's scene module in its
# Kotlin/Native X11 window (native/linux), with no virtual machine in the file.
#
# An Amper module of the core fork's window project, not a Gradle build of its own: the window
# modules and their Kotlin/Native klibs are built by that project's toolchain, and a klib is
# read only by the compiler that wrote it or a newer one. The "One executable (Kotlin/Native)"
# cells copy this directory into a checkout of the core fork as extended/window/samples/
# hello-awtfree (src/ follows its links), list it in project.yaml beside common, scene,
# native/linux and native/linux-scene, and build it for one architecture at a time. arm64 is cross compiled on x86-64,
# because Kotlin/Native has no arm64 Linux host, and linked against the arm64 desktop libraries
# native/linux's x11.def points at.
product:
type: linux/app
platforms: [ linuxX64, linuxArm64 ]

# Compose's compiler plugin through the core fork's template, as the window modules do.
apply:
- ../../compose.module-template.yaml

repositories:
- id: mavenLocal
url: mavenLocal

dependencies:
- ../../common
- ../../scene
- ../../native/linux
# x11WindowSurface, where the scene draws on the Kotlin/Native X11 window.
- ../../native/linux-scene

dependencies@linuxX64:
- org.thisisthepy.compose.runtime:runtime-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.runtime:runtime-saveable-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.animation:animation-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.animation:animation-core-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.foundation:foundation-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.foundation:foundation-layout-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.material:material-ripple-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.material3:material3-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-backhandler-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-geometry-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-graphics-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-text-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-tooling-preview-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-unit-linuxx64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-util-linuxx64:1.11.1-ext.1

dependencies@linuxArm64:
- org.thisisthepy.compose.runtime:runtime-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.runtime:runtime-saveable-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.animation:animation-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.animation:animation-core-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.foundation:foundation-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.foundation:foundation-layout-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.material:material-ripple-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.material3:material3-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-backhandler-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-geometry-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-graphics-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-text-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-tooling-preview-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-unit-linuxarm64:1.11.1-ext.1
- org.thisisthepy.compose.ui:ui-util-linuxarm64:1.11.1-ext.1

settings:
native:
entryPoint: awtfree.main
kotlin:
freeCompilerArgs:
- -module-name
- org.thisisthepy.compose.samples:hello-awtfree
optIns:
- kotlinx.cinterop.ExperimentalForeignApi
1 change: 1 addition & 0 deletions extended/native-desktop/hello-awtfree/src/Content.kt
1 change: 1 addition & 0 deletions extended/native-desktop/hello-awtfree/src/TextSelfCheck.kt
Loading
Loading