Skip to content

Notebook E2E in a macOS GraalVM native image (#191 milestone 1, #249) - #250

Merged
b-re-w merged 2 commits into
developfrom
feat/notebook-e2e-native-image
Oct 17, 2026
Merged

b-re-w merged 2 commits into
developfrom
feat/notebook-e2e-native-image

Conversation

@b-re-w

@b-re-w b-re-w commented Oct 17, 2026

Copy link
Copy Markdown
Member

Closes #249

#191's first milestone, met locally: the notebook E2E's 20 scenarios pass inside a GraalVM native image on macOS.

  • The run had JAVA_HOME and PYTHONHOME removed, and the image links no libjvm; otool -L shows only system frameworks.
  • A relocated copy run under env -i also passes 20/20.
  • Image: 129 MB (Liberica NIK 25.0.4.1). The prefix beside it is 43 MB.

Feature added (python-multiplatform-compose/fixtures/notebook-e2e):

  • NotebookE2eMain runs the same 20 scenarios by direct calls after each class's @BeforeTest, with no JUnit or reflection. It prints NOTEBOOK_E2E: n passed, m failed of 20 and exits non-zero on any failure.
  • Tasks:
    • notebookE2eJvm: the JVM sanity run.
    • notebookE2eNativeAgent: records the Compose and Skiko configuration into src/desktopTest/native-image, which is committed and contains no machine paths.
    • notebookE2eNativeCompile: calls native-image directly, as :sample:nativeCompile does, with --no-fallback --enable-native-access=ALL-UNNAMED. It registers the 28 downcalls and 5 upcalls from python-multiplatform's jar metadata, plus Skiko's JNI.
    • notebookE2eNativeRun.
  • Beside the executable: python-multiplatform-home/ (stageNativeImagePythonHome, Desktop: find PYTHONHOME beside a native-image executable, and stage it there #246), site-packages/ (the wheel) and app/.

What it took, and why the fork's Compose:

  • On upstream Compose, GlobalSnapshotManager and postDelayed dispatch to Skiko's SwingDispatcher, which starts AWT. The first image ran cell05 and then failed every scenario looking for libawt_lwawt.dylib.
  • Shipping the JDK's AWT libraries is ruled out, because libawt.dylib links @rpath/libjvm.dylib (checked with otool).
  • The fork's ui-desktop sends that work to Dispatchers.Main when compose.main.dispatcher=coroutines (ExtendedMainDispatcher). So the image's classpath, and only it, takes ui, ui-text and foundation from compose-multiplatform-core-extended's mavenLocal build.
  • NotebookE2eMainDispatcherFactory supplies a single-thread Dispatchers.Main with no AWT. It is registered from src/desktopTest/native-image-main/ on the image's classpath only.
  • The walker's composable thunks are added to the copied classpath explicitly; the first copy lost them.
  • One place for the fork's coordinates: composeExtended.version, .groupPrefix, .modules and .mavenLocal in the root gradle.properties. The coming move to org.thisisthepy.compose.* / 1.11.1-ext.1 is a property edit.
  • desktopTest keeps upstream Compose: 20 passed after this change.

Not done here: the macOS CI job. The fork's artefacts exist only in this machine's mavenLocal, which a CI runner cannot reach. It follows once the fork publishes to a repository CI can read, and I'll open it as its own issue.

The same 20 scenarios run in a GraalVM native image with JAVA_HOME and
PYTHONHOME removed and no libjvm, the prefix, wheel and app beside the
executable; the image takes ui, ui-text and foundation from the fork,
whose main-thread work can go to an AWT-free Dispatchers.Main.
NotebookE2eMain calls the 20 scenarios after their @BeforeTest, with no
JUnit, and prints a summary. notebookE2eJvm runs it on the JVM,
notebookE2eNativeAgent records Compose and skiko's configuration into
src/desktopTest/native-image, notebookE2eNativeCompile builds the image,
and notebookE2eNativeRun requires 20 of 20 with JAVA_HOME and PYTHONHOME
removed and no libjvm. The image's classpath takes the fork's ui,
ui-text and foundation (composeExtended.* in gradle.properties, one
place) and registers a single-thread Dispatchers.Main with no AWT.

Closes #249
@b-re-w
b-re-w merged commit cac9613 into develop Oct 17, 2026
@b-re-w
b-re-w deleted the feat/notebook-e2e-native-image branch October 17, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant