Add Windows arm64, Linux aarch64, native build target - #23
Conversation
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.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe 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. ChangesNative build and CI modernization
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
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
.github/workflows/allInOne.ymlbuild.gradlegradle/wrapper/gradle-wrapper.propertiestoolchains/linux_aarch64_gcc.cmake
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`.
BenjaminAmos
left a comment
There was a problem hiding this comment.
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.
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '11' | ||
| java-version: '25' |
There was a problem hiding this comment.
| java-version: '25' | |
| java-version: '17' |
| uses: actions/setup-java@v4 | ||
| with: | ||
| java-version: '11' | ||
| java-version: '25' |
There was a problem hiding this comment.
| java-version: '25' | |
| java-version: '17' |
| def exitCode = process.waitFor() | ||
| if (exitCode != 0) { | ||
| throw new GradleException("make failed with exit code ${exitCode}") | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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).
NativeSupportalready resolves the expected filename (libbullet-linux-aarch64.so) for that platform — it just was never built.toolchains/linux_aarch64_gcc.cmake, matching the existinglinux_amd64_gcc.cmakebut targeting aarch64.build.gradle: on a Linux aarch64 host, build only thelinux_aarch64_gcctarget (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 thedoLast { exec { ... } }call formakewith a plainProcessBuilderinvocation —Project.exec(Closure)was removed in Gradle 9, this now works on both Gradle 8 and 9+.ubuntu-24.04-armto the swig/build matrices so aarch64 natives get built and published going forward.Test plan
libbullet-linux-aarch64.solocally on Arch Linux ARM (aarch64) via./gradlew build buildNatives1.0.5-SNAPSHOTtomavenLocal