Fix darwin-aarch64 (Apple Silicon Mac) native loading#15
Open
foontinz wants to merge 1 commit intoburningwave:mainfrom
Open
Fix darwin-aarch64 (Apple Silicon Mac) native loading#15foontinz wants to merge 1 commit intoburningwave:mainfrom
foontinz wants to merge 1 commit intoburningwave:mainfrom
Conversation
Apple Silicon Macs running native arm64 Java crash at JVM init when
loading NativeExecutor with NoClassDefFoundError on
StaticComponentContainer, caused by dlopen rejecting a Linux ELF named .so:
Files$NotLoadedException: Unable to load file
org/burningwave/jvm/libNativeExecutor-aarch64.so
UnsatisfiedLinkError: ... slice is not valid mach-o file
Two-part fix:
1. Libraries.java: when osArch=aarch64 AND os is macOS, use the
.dylib extension. The previous aarch64 branch hardcoded "so" for
ALL aarch64 platforms — correct on Linux but wrong on macOS,
where it was reached *before* the macOS branch that would have
set extension="dylib".
2. native/pom.xml: introduce a linker.arch.suffix property
(default x${sun.arch.data.model}, overridden to "aarch64" in a
new mac-aarch64 profile activated on os.family=mac AND
os.arch=aarch64). This makes a native build on a native arm64
macOS runner produce libNativeExecutor-aarch64.dylib instead of
libNativeExecutor-x64.dylib.
3. Pre-built native/bin/libNativeExecutor-aarch64.dylib compiled
with Apple clang++ 21.0 against OpenJDK 17.0.18 ARM headers,
targeting arm64-apple-darwin. CI can regenerate this once a
macos-latest aarch64 workflow entry is added (left as a
follow-up PR to keep this one focused on the actual fix).
The C++ source is purely portable JNI (zero #ifdef __APPLE__) so it
compiles cleanly with no source changes; verified by exact symbol-set
match against the existing libNativeExecutor-aarch64.so (40 JNI exports).
Tested end-to-end on Apple M5 Pro / OpenJDK 17.0.18 ARM Homebrew with
the smoke test:
Class.forName("org.burningwave.jvm.NativeExecutor");
Class.forName("org.burningwave.core.assembler.StaticComponentContainer");
Both classes load and statically initialize successfully. Also
reproducible inside a real Forge 1.20.1 modpack (Biohazard: Project
Genesis) that bundles jvm-driver via TheImpossibleLibrary.
Refs: TheComputerizer/The-Impossible-Library#35
Author
|
@Roberto-Gentili , let me know if you have any issues with this patch. Happy to change as needed! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Apple Silicon Macs running native arm64 Java, loading
NativeExecutorcrashes JVM init withNoClassDefFoundErroronStaticComponentContainer.dlopenrejects a Linux ELF named.so:Two-part bug:
Libraries.javapicksextension = "so"for allaarch64platforms, even macOS. Theaarch64branch runs before the macOS branch that would have setdylib.darwin-aarch64build target innative/pom.xmland no Mach-O ARM64 binary innative/bin/. Even with the loader fixed there's nothing to load.Affects downstream libraries that bundle jvm-driver on Apple Silicon. Reported via TheComputerizer/The-Impossible-Library#35.
Fix (3 files)
Libraries.java— whenosArch=aarch64AND macOS, usedylib. Five lines, no behavior change on Linux/Windows.native/pom.xml— extract the artifact suffix into alinker.arch.suffixproperty (defaultx${sun.arch.data.model}); add amac-aarch64profile activated onos.family=mac+os.arch=aarch64that overrides it toaarch64. Inherits the existingmacprofile compile flags. Appleclang++targetsarm64-apple-darwinnatively on a native arm64 JVM, so no-archflag needed.native/bin/libNativeExecutor-aarch64.dylib— pre-built (44864 bytes, 40 JNI exports, identical symbol set to the existing Linux ARM64.so). Compiled with Apple clang++ 21.0 against OpenJDK 17.0.18 ARM headers from this commit's source.Verified
Functional test (real workload)
Class.forName("org.burningwave.jvm.NativeExecutor")andClass.forName("org.burningwave.core.assembler.StaticComponentContainer")both succeed on Apple M5 Pro / OpenJDK 17.0.18 ARM Homebrew. Also reproduced inside a real Forge 1.20.1 modpack (Biohazard: Project Genesis): game launches and connects to a Forge server with full mod parity.Full test suite across JDK versions (Apple Silicon aarch64)
Ran the upstream
AllTestsSuite(60 tests — DefaultDriver, HybridDriver, NativeDriver, DynamicDriver) on every ARM64 macOS JDK available from the three distributions the CI uses. Removing the dylib causes all 15 NativeDriverTest cases to error out, confirming the binary is exercised.DefaultDriverTestalso crashes (no JNI involved)The Semeru 22/26 crashes are an OpenJ9 bug on aarch64 macOS, unrelated to this PR — the pure-Java
DefaultDriverTest(which never touches JNI) crashes identically. The upstream CI only runs Semeru on x64, so this is not a regression.Intermediate Java versions (9, 12–16, 18–20) have no ARM64 macOS builds from any vendor (they predate Apple Silicon). The upstream CI tests those only on x64.
Out of scope
CI workflow doesn't yet have a
macos-latest aarch64matrix entry to auto-regenerate this binary. Can send a separate workflow PR if you'd rather have CI regenerate the binary.