Align the Android library to 16 KB pages - #25
Merged
Conversation
Google Play requires 64-bit native libraries to support 16 KB memory pages, and from 1 February 2027 it refuses updates that do not. The shipped libCesiumNativeC.so does not: reading its program headers back gives p_align 0x1000 on every LOAD segment. Nothing in this repository asked for 4 KB. The alignment came from the runner: the android-arm64 leg links with whatever NDK ubuntu-latest happens to carry, the last green run used 27.3.13750724, and 16 KB alignment only became the default in r28. So the flag has to be explicit rather than inherited. In CMake rather than in the workflow's extra-cmake, for two reasons beyond taste. Anyone building this locally gets the same binary CI does, which is not true of a flag that lives in a matrix row. And -DCMAKE_SHARED_LINKER_FLAGS= replaces the variable rather than appending to it, so the first other link flag anyone needed would silently drop this one. Not a triplets/arm64-android-release.cmake overlay either. build.yml already records why Android has no overlay: one replaces the community triplet instead of extending it, and would drop VCPKG_MAKE_BUILD_TRIPLET, VCPKG_CMAKE_SYSTEM_VERSION and VCPKG_CMAKE_CONFIGURE_OPTIONS. It would not reach this link anyway -- a triplet governs how vcpkg builds ports, not how the project consuming them is linked. Only the final link needs it. arm64-android-release sets VCPKG_LIBRARY_LINKAGE static, so the thirty dependencies are archives, and an archive carries no program headers to align.
This was referenced Sep 1, 2026
Member
Author
Verified on the binary this PR producesAll nine legs green. Downloaded this run's Against |
jcant0n
added a commit
to EvergineTeam/Evergine.Bindings
that referenced
this pull request
Sep 1, 2026
#67) Google Play requires 64-bit native libraries to support 16 KB memory pages and refuses updates that do not from 1 February 2027. Cesium.NET has been shipping a 4 KB-aligned arm64 library for as long as it has shipped Android, and every check this fleet has was satisfied by it. That is the part worth fixing here rather than in the wrapper. The property lives in the ELF program headers: each PT_LOAD segment carries a p_align, and a linker writes 0x1000 unless asked for 0x4000. Nothing else looks. The architecture check reads the machine field and is happy. The symbol check finds every symbol present. The smoke test installs the package and runs it on a runner whose pages are 4 KB, where a 4 KB-aligned library is perfectly loadable. So the build goes green, the package publishes, and the rejection arrives months later at whoever tries to put an application built on it into the store. The new checker is the architecture check's neighbour in every sense: same manifest, same shipped_natives() from native_paths.py, same file, three fields further into it. Two decisions in it worth stating. A 32-bit library is skipped and said so, not failed -- the requirement is 64-bit only and armeabi-v7a is excluded by name, so failing there would be noise that teaches people to ignore the check. And a library that parses but declares no PT_LOAD segments is a failure rather than a pass, for the reason native_paths.py already records elsewhere: a platform nobody could look at should be named out loud instead of counted as verified. A package that ships no Android binary prints one line and exits zero, which is most of the fleet. Run against the four repositories that could answer: Cesium.NET exit=1 android-arm64 aligned to 0x1000 JoltPhysics.NET exit=0 android-arm64 0x4000, android-arm skipped as 32-bit Vuforia.NET exit=0 android-arm64 0x4000 Vulkan.NET exit=0 ships no Android binaries The one failure is real and is fixed in EvergineTeam/CesiumC#25; it reaches this package once that release flows downstream. Nothing here takes effect until the v1 tag moves, so the order is: land the wrapper fix, publish it, then move the tag.
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.
The problem, measured
Google Play requires 64-bit native libraries to support 16 KB memory pages, and from
1 February 2027 it refuses updates that do not
(docs). The requirement is
64-bit only —
armeabi-v7ais explicitly out of scope, which is moot here since this repobuilds
arm64-v8aalone.Reading the program headers of the
libCesiumNativeC.socurrently committed inCesium.NET@main:For contrast, the other two packages in the fleet that ship Android binaries:
min LOAD alignandroid-arm640x4000android-arm640x4000android-arm640x1000So today an app that consumes
Evergine.Bindings.CesiumNativecannot be published to Playonce the deadline lands.
Why it is 4 KB
Nothing in this repository asked for it.
max-page-size,common-page-sizeand16384appear in no blob on
main. The alignment came from the toolchain: theandroid-arm64leglinks with whatever NDK
ubuntu-latesthappens to carry, the last green run used27.3.13750724, and 16 KB alignment only became the default in r28. One runner imagebump either way and the answer changes silently — which is the actual defect, more than the
flag being absent.
The fix
Same flag the draco fork uses, and guarded the same way — its first attempt applied it
unconditionally and
9f675442moved it behindif(ANDROID)the same day.In CMake rather than the workflow's
extra-cmake, for two reasons beyond taste. Anyonebuilding this locally gets the same binary CI does, which is not true of a flag living in a
matrix row. And
-DCMAKE_SHARED_LINKER_FLAGS=replaces the variable rather thanappending, so the first other link flag anyone needed would quietly drop this one.
Not a
triplets/arm64-android-release.cmakeoverlay.build.yml:130-136alreadyrecords why Android has no overlay: one replaces the community triplet instead of
extending it, and would drop
VCPKG_MAKE_BUILD_TRIPLET,VCPKG_CMAKE_SYSTEM_VERSIONandVCPKG_CMAKE_CONFIGURE_OPTIONS. It would not reach this link anyway — a triplet governshow vcpkg builds ports, not how the project consuming them is linked.
Only the final link needs it.
arm64-android-releasesetsVCPKG_LIBRARY_LINKAGE static, so the thirty dependencies are archives, and an archive carries no program headersto align. There is exactly one ELF in the output.
Verified
The guard was checked against a minimal project reproducing the construct: the flag reaches
the link line with
-DANDROID=1and is absent without it, so the other eight legs areuntouched.
The real check is this PR's own
android-arm64artifact — itsLOADalignment should read0x4000. Worth confirming before merge, since the whole point is a property of the outputrather than of the source.
After merge
The flag alone changes nothing that ships. The
.solives inCesium.NETand only moveswhen a release here flows into it:
workflow_dispatchwithrelease-tag: v0.63.0-cesiumc.5;notify-downstreamfires and Cesium.NET's CD commits the new.soon its own — butwill not publish, because it decides on generated-code changes and release assets
are deliberately excluded from that (
fetch_upstream.py:768-773: "a rebuilt nativelibrary would read as a changed API and publish a package whose managed surface is
identical"). Correct in general; here the binary is the point;
workflow_dispatchof Cesium.NET's CD withpublish-only: true,which ships the reviewed tree and refuses if regenerating would change it.