Skip to content

Add Windows arm64, Linux aarch64, native build target - #23

Merged
BenjaminAmos merged 9 commits into
masterfrom
linux-aarch64-natives
Aug 5, 2026
Merged

Add Windows arm64, Linux aarch64, native build target#23
BenjaminAmos merged 9 commits into
masterfrom
linux-aarch64-natives

Conversation

@soloturn

@soloturn soloturn commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

AI-assisted change proposal. Filed by agent driven by @soloturn via GDD.

Summary

JNBullet only ever built linux-amd64, windows-amd64, and macos (amd64/aarch64) natives, so Terasology has no working physics on Linux ARM64 (e.g. Raspberry Pi, Asahi Linux, Arch Linux ARM). NativeSupport already resolves the expected filename (libbullet-linux-aarch64.so) for that platform — it just was never built.

  • Add toolchains/linux_aarch64_gcc.cmake, matching the existing linux_amd64_gcc.cmake but targeting aarch64.
  • build.gradle: on a Linux aarch64 host, build only the linux_aarch64_gcc target (skip the amd64 + MinGW-w64 Windows cross-compile, which targets a different architecture and isn't reliably available from an aarch64 host).
  • build.gradle: replace the doLast { exec { ... } } call for make with a plain ProcessBuilder invocation — Project.exec(Closure) was removed in Gradle 9, this now works on both Gradle 8 and 9+.
  • Bump the Gradle wrapper to 9.6.1 so the project can build on JDKs newer than what Gradle 8.2.1 supports (e.g. JDK 21+).
  • CI: add ubuntu-24.04-arm to the swig/build matrices so aarch64 natives get built and published going forward.

Test plan

  • Built libbullet-linux-aarch64.so locally on Arch Linux ARM (aarch64) via ./gradlew build buildNatives
  • Published a 1.0.5-SNAPSHOT to mavenLocal
  • Ran a full Terasology game session against it end-to-end (Bullet init, world generation, chunk physics, save) with no native-library errors

JNBullet only ever built linux-amd64, windows-amd64, and macos
(amd64/aarch64) natives, so Terasology has no working physics on
Linux ARM64 (e.g. Raspberry Pi, Apple Silicon under Linux, Asahi,
Arch Linux ARM). NativeSupport already resolves the expected filename
(libbullet-linux-aarch64.so) for that platform, it just was never built.

- Add toolchains/linux_aarch64_gcc.cmake, matching the existing
  linux_amd64_gcc.cmake but targeting aarch64.
- build.gradle: on a Linux aarch64 host, build only the
  linux_aarch64_gcc target (skip the amd64 + MinGW-w64 Windows
  cross-compile, which targets a different architecture/isn't reliably
  available from an aarch64 host).
- build.gradle: replace the doLast { exec { ... } } call for `make`
  with a plain ProcessBuilder invocation - Project.exec(Closure) was
  removed in Gradle 9, this now works on both Gradle 8 and 9+.
- Bump the Gradle wrapper to 9.6.1 so the project can build on JDKs
  newer than what Gradle 8.2.1 supports (e.g. JDK 21+).
- CI: add ubuntu-24.04-arm to the swig/build matrices so aarch64
  natives get built and published going forward.

Verified locally on Arch Linux ARM (aarch64): built
libbullet-linux-aarch64.so, published a 1.0.5-SNAPSHOT to mavenLocal,
and ran a Terasology game session against it end-to-end (physics
init, world generation, save) with no native-library errors.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fc42c20-69ca-457c-b009-544307183a25

📥 Commits

Reviewing files that changed from the base of the PR and between efc77c7 and c3359c5.

📒 Files selected for processing (10)
  • .github/workflows/allInOne.yml
  • build.gradle
  • toolchains/android_armeabi_gcc.cmake
  • toolchains/linux_amd64_gcc.cmake
  • toolchains/linux_i686_gcc.cmake
  • toolchains/linux_windows_arm64_llvm_mingw32.cmake
  • toolchains/macosx_aarch64_clang.cmake
  • toolchains/macosx_amd64_clang.cmake
  • toolchains/windows_amd64_msvc.cmake
  • toolchains/windows_i686_msvc.cmake

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for building on 64-bit ARM Linux systems.
    • Added Windows ARM64 build support.
    • Expanded automated build coverage to include ARM-based Ubuntu and newer macOS environments.
    • Added optimized Release build configuration for Linux ARM64.
  • Bug Fixes

    • Improved native build output and failure reporting, making unsuccessful builds easier to identify.
  • Chores

    • Updated project build tooling and raised the required Java version to 17.
    • Updated supported build tool configurations for improved platform compatibility.

Walkthrough

The change adds Linux AArch64 and Windows ARM64 native build support. Gradle now requires Java 17 and reports native build failures. CMake toolchains require CMake 3.5. CI uses updated runners, PCRE headers, LLVM MinGW, and Java 17.

Changes

Native build and CI modernization

Layer / File(s) Summary
Target and toolchain setup
build.gradle, toolchains/*, gradle/wrapper/gradle-wrapper.properties
Gradle selects Linux AArch64 targets and requires Java 17. New CMake toolchains support Linux AArch64 and Windows ARM64. Existing toolchains require CMake 3.5.
Native make execution
build.gradle
Native builds use ProcessBuilder, stream combined make output, wait for completion, and throw GradleException on failure.
CI platform and dependency integration
.github/workflows/allInOne.yml
SWIG and build jobs use updated Ubuntu and macOS runners. Jobs install PCRE headers, configure Java 17, and provision LLVM MinGW for Linux x64 builds. Publishing uses Ubuntu 24.04.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant Gradle
  participant ProcessBuilder
  participant make
  GitHubActions->>Gradle: run native build
  Gradle->>ProcessBuilder: start make
  ProcessBuilder->>make: execute selected target build
  make-->>ProcessBuilder: combined output and exit code
  ProcessBuilder-->>Gradle: completion status
  Gradle-->>GitHubActions: build result
Loading

Poem

I’m a rabbit building fast,
ARM and Windows paths are cast.
Gradle guides each native run,
Make reports when work is done.
New runners help the checks hold fast.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main additions: Windows ARM64 and Linux AArch64 native build targets.
Description check ✅ Passed The description explains the Linux AArch64 and Windows ARM64 targets, build changes, CI updates, and test results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch linux-aarch64-natives

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/allInOne.yml:
- Line 18: Replace retired runner labels in the workflow matrices and fixed
publish job: update ubuntu-20.04 to a supported Ubuntu label such as
ubuntu-22.04 or ubuntu-24.04, and macos-12 to macos-14 or macos-15. Apply the
changes to both matrix definitions and the publish job while preserving the
existing runner configuration.

In `@gradle/wrapper/gradle-wrapper.properties`:
- Line 3: Update the Java setup in both Gradle jobs in allInOne.yml to use Java
17 when invoking ./gradlew, while preserving any Java 11 toolchain configuration
required for compilation targets.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 05bfecae-edc0-4f47-a6b8-4403134da2af

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5b7aa and ed763b7.

📒 Files selected for processing (4)
  • .github/workflows/allInOne.yml
  • build.gradle
  • gradle/wrapper/gradle-wrapper.properties
  • toolchains/linux_aarch64_gcc.cmake

Comment thread .github/workflows/allInOne.yml Outdated
Comment thread gradle/wrapper/gradle-wrapper.properties
SWIG's configure needs pcre-config from PCRE1's dev package. The
ubuntu-20.04 runner image happened to have it preinstalled, which is
why this was never explicit; the ubuntu-24.04-arm image added for
aarch64 natives does not, so the swig job failed with:

  configure: error: Cannot find pcre-config script from PCRE
Both are retired/being retired GitHub-hosted runner labels; jobs
using them were stuck indefinitely in the queue rather than picked up.
Move to ubuntu-24.04 and macos-13 (still x86, pairs with macos-14 for
Apple Silicon coverage).
The swig job's dependency-install step (which provides libpcre, the
runtime lib the built swig binary links against) was gated on
`cache-hit != 'true'`. On a warm cache, that step - and with it the
runtime library - was skipped entirely, even though each job still
runs on a fresh VM with nothing preinstalled. The cached swig binary
then failed to even run:

  error while loading shared libraries: libpcre.so.3

There was also a dead macOS-only step meant to cover this
(`if: runner.os == 'macOs'`, note the lowercase 's' - never matches
the real runner.os value 'macOS'), now redundant given the above.

Same gap existed in the build/publish jobs on Linux: they installed
MinGW-w64 but never libpcre3, so a cache-hit run would fail there too.
macos-13/macos-14 are on the deprecation path; move to the current GA
images, keeping one Intel and one Apple Silicon leg.
Gradle 9.6.1 (bumped earlier here) needs JVM 17+; run CI on the
current JDK (25) rather than the old pinned 11, which no longer works.
Bump the library's own source/targetCompatibility from 1.8 to 17 to
match - it was already far behind, and 17 is what Terasology's engine
itself requires.
CMake 4.x (now what CI's runner images ship, same as recent local
installs) dropped support for cmake_minimum_required policies below
3.5 entirely:

  CMake Error: Compatibility with CMake < 3.5 has been removed from
  CMake.

Every toolchain file still declared 2.8.12 except the new
linux_aarch64_gcc.cmake added in this branch, which is why swig/build
suddenly failed across the whole matrix, not just aarch64. Match the
project's own CMakeLists.txt, which already requires 3.5.
Classic mingw-w64 (GCC) has no Windows/ARM64 target at all, so this
platform was never built even though it's one of the four LWJGL/Java
natives Terasology already ships for (natives-windows/-linux/-macos/
-macos-arm64 don't cover Windows on ARM, but the demand is the same
as for Linux aarch64: Windows-on-ARM devices, e.g. Surface Pro X/11,
Parallels/UTM VMs on Apple Silicon, Snapdragon X laptops).

- Add toolchains/linux_windows_arm64_llvm_mingw32.cmake, using the
  LLVM-based llvm-mingw toolchain (https://github.com/mstorsjo/llvm-mingw)
  instead of GCC, since llvm-mingw is the only mingw-w64 toolchain
  with an aarch64-w64-mingw32 target.
- build.gradle: build linux_windows_arm64_llvm_mingw32 alongside the
  existing linux_amd64_gcc/linux_windows_amd64_mingw32 pair on an
  amd64 Linux host (llvm-mingw itself doesn't care about host arch,
  but this keeps "cross-compile everything Windows-related" on the
  one job, same as before).
- CI: download+extract llvm-mingw and put it on PATH for the job that
  needs it (gated to the amd64 Linux leg, since that's the only one
  building this target).

Verified locally on Arch Linux ARM (aarch64) using the llvm-mingw
aarch64 host build: configured and built libbullet-windows-aarch64.dll
cleanly, confirmed as a valid ARM64 PE32+ DLL via `file`.
@soloturn soloturn changed the title Add Linux aarch64 native build target Add Windows arm64, Linux aarch64, native build target Aug 3, 2026

@BenjaminAmos BenjaminAmos left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are targetting Java 17 then we should compile against a Java 17 JDK during CI. That does not prevent using newer JDKs on your own devices.

Compiling the natives on newer versions of Ubuntu will likely force a dependency on a newer Glibc version, which will prevent them from executing on older versions of Ubuntu than the one compiled against. As such, it is preferred when compiling shared libraries in this instance to compile them against the oldest realistic Glibc that you wish to target. I think a reasonable baseline is the Ubuntu 22.04 but 24.04 might still be acceptable. I do not know how this applies to macOS.

Comment thread .github/workflows/allInOne.yml Outdated
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '25'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
java-version: '25'
java-version: '17'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c3359c5.

Comment thread .github/workflows/allInOne.yml Outdated
uses: actions/setup-java@v4
with:
java-version: '11'
java-version: '25'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
java-version: '25'
java-version: '17'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c3359c5.

Comment thread build.gradle
def exitCode = process.waitFor()
if (exitCode != 0) {
throw new GradleException("make failed with exit code ${exitCode}")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is acceptable for now, however, it would be better if you split this into a another task that is finalizedBy the outer task instead, long-term.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI-assisted change. Filed by agent driven by @soloturn via GDD.

Agreed this is the cleaner shape long-term. Leaving the inline ProcessBuilder as-is for now rather than splitting it into a finalizedBy task, since I can't verify a Gradle task-graph change to the Linux-only native build path from this (macOS) environment - no aarch64-linux cmake/gcc toolchain here to actually run native_${module} and confirm the refactor behaves correctly. Happy to pick this up as a follow-up where it can be tested end-to-end.

Gradle 9.6.1 only requires JDK 17-26 to run - 17 is the minimum LTS
that satisfies it. Per BenjaminAmos's review suggestion on PR #23.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PQriAKnoCEqcmFoSAvU39Q
@BenjaminAmos
BenjaminAmos merged commit 1ab4805 into master Aug 5, 2026
11 checks passed
@BenjaminAmos
BenjaminAmos deleted the linux-aarch64-natives branch August 5, 2026 17:57
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.

2 participants