Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

iOS Graal JDK 25

This repository produces the iOS/arm64 runtime inputs used by Godot-JVM's GraalVM Native Image build. It is one release unit containing the two things that used to live in separate repositories:

  • a patched, JDK 25-based iOS runtime built as libjava-release.a and libjvm-release.a;
  • a matching C Annotation Processor (CAP) cache, generated by cap-cache-generator.

The result is not an iOS app and is not a normal JDK installation. It is a small toolchain bundle that the Godot-JVM Gradle plugin downloads before it turns a user's JVM code into an iOS native library.

The downloadable bundle is one ZIP file named ios-graal-jdk-<release-version>.zip. Its contents are:

libjava-release.a
libjvm-release.a
caps/
  *.cap
  cap-cache-files.txt
SHA256SUMS
manifest.json

manifest.json identifies the JDK, GraalVM, source revisions, release version, and every required asset. SHA256SUMS verifies all downloadable inputs.

The reason for the custom toolchain

GraalVM Native Image does not ship an officially supported iOS target toolchain. It does expose the building blocks needed to make one, but somebody must provide iOS-specific native runtime libraries and the target-platform information normally discovered while building an image.

Two static libraries make up the native runtime part of that contract:

  • libjava.a contains the native JDK implementations used by Java code, such as the native side of java.base functionality.
  • libjvm.a contains the Substrate VM runtime used by Native Image. Despite the historical name, it is not HotSpot running inside the app; it is linked into the final ahead-of-time compiled image.

When the Gradle plugin builds an iOS export, the final link combines the user's compiled code, Native Image's generated code, these two iOS archives, and the iOS SDK frameworks. All three pieces must match: a CAP cache from a different JDK or GraalVM build is not interchangeable with these archives.

CAP means C Annotation Processor cache. Native Image needs facts from C headers for the target platform: sizes and layouts of native types, constant values, function signatures, and similar ABI details. Normally it generates and runs small C query programs to obtain those facts. That is not possible when the build host cannot run the iOS target code, so this project generates the answers once against the iOS SDK and saves one .cap file per native query. During a user's iOS build, -H:+UseCAPCache reads those files instead of trying to run target code.

This project therefore carries a small OpenJDK iOS patch, Xcode projects for the two archives, and GraalVM's CAP-generation step. It is intentionally an unofficial, version-locked port; it does not claim that GraalVM officially supports iOS.

From source to a Gradle-consumable release

The source inputs are pinned in .gitmodules:

  • labs-openjdk/labs-openjdk-25: the JDK 25 JVMCI source;
  • svm/graal: the matching GraalVM 25 source.

toolchain.env is the single place that records the JDK, GraalVM, JVMCI, iOS deployment, and default release versions. labs-openjdk/ios-jdk.patch is applied to the pinned JDK source before it is built.

The source submodules are Git links to exact commits, not floating branches. CI fetches those commits shallowly, without their full history. The expensive OpenJDK native build output and Gradle/CAP task state are cached only when those source revisions and their relevant build inputs match.

Build on macOS with Xcode and a GraalVM 25.0.4 JDK that includes native-image:

git clone --recurse-submodules <repository-url>
cd ios-graal-jdk-25
export GRAALVM_HOME=/path/to/graalvm-jdk-25
./scripts/build-release.sh

The script performs this sequence:

  1. Initializes submodules and applies the iOS JDK patch.
  2. Builds the JDK's Graal builder image.
  3. Uses Xcode to build the iOS/arm64 libjava.a and libjvm.a archives.
  4. Runs cap-cache-generator, which asks Native Image to create a new iOS CAP cache and exits once the cache is complete.
  5. Copies the archives and every generated CAP file into dist/, writes their dynamic index, checksums, and manifest.

The CAP filenames are deliberately discovered from the generated output and listed in caps/cap-cache-files.txt; consumers must not maintain a hard-coded list. A future Gradle plugin downloads this one ZIP, verifies it using SHA256SUMS, then extracts the two archives and the caps/ directory.

The included GitHub workflow has two entry points:

  • Running it manually from the Actions tab builds and uploads the already-ZIPed bundle as a workflow artifact. archive: false prevents GitHub from wrapping that ZIP inside a second ZIP.
  • Pushing a tag builds the same ZIP, creates a GitHub Release named after that tag, and uploads that exact ZIP as its sole release asset. The tag becomes the bundle's releaseVersion.

No current release is created by these files alone: a release is only published when somebody pushes a tag to GitHub.

Before changing either source submodule, update toolchain.env, port labs-openjdk/ios-jdk.patch, then run:

./scripts/verify.sh

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages