Repository navigation
Conversation
NDKs older than r28 align the LOAD segments of shared libraries on 4 KB, while Google Play requires the 64 bit libraries of apps targeting Android 15 or later to support 16 KB page sizes. The Flutter tool can hand such an NDK to the build hook (for example via ANDROID_NDK_HOME). aarch64-linux-android and x86_64-linux-android are now linked through a small wrapper around the NDK's clang that adds -Wl,-z,max-page-size=16384, the flag NDK r28's clang passes on its own. Nothing goes through rustflags, so the user's RUSTFLAGS and Cargo config are left as they are, and a max-page-size set by the user still takes precedence. With NDK r28 and later the output is unchanged, and armv7-linux-androideabi is not affected. The Android integration test job now also checks the alignment of the example's library. Fixes GregoryConrad#116
|
|
||
| ## Android 16 KB page sizes | ||
| On the 64 bit Android targets (`aarch64-linux-android` and `x86_64-linux-android`), | ||
| your library is linked with `-Wl,-z,max-page-size=16384` | ||
| so that it supports 16 KB page sizes, which | ||
| [Google Play requires](https://developer.android.com/guide/practices/page-sizes) | ||
| for apps targeting Android 15 or later. | ||
| NDK r28 and newer already do this by default, but older NDKs align on 4 KB. | ||
| The flag is added by a small wrapper around the NDK's `clang`, | ||
| so your own `rustflags` are left untouched; | ||
| if you need a different page size, pass it yourself | ||
| (e.g., `-C link-arg=-Wl,-z,max-page-size=4096`) and yours will take precedence. |
There was a problem hiding this comment.
can probably just leave this out for simplicity's sake
There was a problem hiding this comment.
I personally would prefer to keep this in the README. This is going to be a hot topic in the new year when they are forced to switch.
There was a problem hiding this comment.
understandable--I normally just like to leave impl details out of public-facing docs like this. a nod to the 16kb page sizes would be fine tho
| /// The contents of a script that invokes [linker] with [flags] | ||
| /// followed by all of the arguments the script itself was given. | ||
| @visibleForTesting | ||
| static String linkerWrapperScript({ |
There was a problem hiding this comment.
is it possible to do this without a script? i.e., can we just inject an env variable to cargo by default (on the appropriate targets) if the user doesn't already set it (or a conflicting variable) themselves? making a wrapper script for this hurts my soul a bit
Google Play requires the 64 bit native libraries of apps targeting Android 15 or later to support 16 KB page sizes, and from 1 February 2027 it will no longer accept updates that do not (Support 16 KB page sizes). NDK r28 and later align on 16 KB by default, but older NDKs align on 4 KB, and the Flutter tool hands the build hook whichever NDK it finds first (for example
ANDROID_NDK_HOME, which is r27d on GitHub's Ubuntu runners).What this changes:
aarch64-linux-androidandx86_64-linux-android,CARGO_TARGET_<TRIPLE>_LINKERnow points to a small wrapper script in the hook's output directory. It runs the NDK's clang with-Wl,-z,max-page-size=16384before rustc's own arguments. That is the flag NDK r28's clang already passes on its own (checked withclang -###), so with NDK r28c the built library is byte for byte the same as before.target.<triple>.rustflagswould make Cargo ignore the user'sbuild.rustflags, andRUSTFLAGSreplaces everything. Since the flag comes first, amax-page-sizeset by the user still wins (LLD keeps the last one).armv7-linux-androideabiand the other platforms are unchanged, as Play's rule only covers 64 bit libraries..cmdthat hands over to the NDK's own.cmd.About older devices: a library aligned on 16 KB also loads on devices with 4 KB pages, and it is what NDK r28 already produces by default.
I did not add an option to turn it off, since a user's own
-C link-arg=-Wl,-z,max-page-size=...takes precedence, but I can add one if you prefer.How I checked it, on Linux x86_64 with NDK r27d and r28c and the examples' Rust 1.90.0:
flutter test test(7 new tests: the flags per target, the wrapper scripts, and running the wrapper), the examples' tests,flutter analyze --fatal-infos --fatal-warningsanddart formatpass.testCodeBuildHook) for the three Android targets, LOAD alignment fromreadelf -lW:[build] rustflags = ["-C", "link-arg=-Wl,-z,max-page-size=65536"]in a Cargo config, the result is 0x10000, so the user's flags are kept and win. WithRUSTFLAGS="-C link-arg=-Wl,-soname,from_rustflags.so", the soname is set and the alignment is still 0x4000.flutter build apk --debugof the Flutter example withANDROID_NDK_HOMEset to r27d:libflutter_example.sogoes from 0x1000 to 0x4000 inarm64-v8aandx86_64. The new CI step fails on the APK from main and passes on this branch..cmdagainst the realaarch64-linux-android35-clang.cmdof NDK r27d with a stubclang.exe, spawned with Rust'sstd::process::Commandlike rustc does: the arguments, including paths with spaces, arrive unchanged after the flag, and a failing link still exits with 1.readelf -lW, dart_only example, aarch64, NDK r27d
Fixes #116