Skip to content

[WIP] Drop libc++ from Android NativeAOT linking#11311

Draft
simonrozsival wants to merge 7 commits into
mainfrom
dev/simonrozsival/nativeaot-drop-libcpp
Draft

[WIP] Drop libc++ from Android NativeAOT linking#11311
simonrozsival wants to merge 7 commits into
mainfrom
dev/simonrozsival/nativeaot-drop-libcpp

Conversation

@simonrozsival
Copy link
Copy Markdown
Member

@simonrozsival simonrozsival commented May 8, 2026

Summary

This draft explores removing the Android NativeAOT link-time dependency on libc++.

The branch now:

  • removes the explicit NativeAOT libc++_static.a and libc++abi.a link inputs;
  • removes libc++ packaging from the Android native runtime component list;
  • keeps the final NativeAOT app link on the direct ld.lld/NativeLinker path from main;
  • reduces NativeAOT-reachable host code that pulled in C++ runtime/STL symbols;
  • adds NativeAOT-local C++ allocation/nothrow shims for the remaining runtime-pack allocation references;
  • fixes trimmable NativeAOT startup/linking by making generated per-assembly __ArrayMapRank* typemap anchors public, because the root typemap assembly references them across assembly boundaries.

Context

This is related to #9926 and the NDK r29 NativeAOT linking work.

The relevant background is that the NativeAOT Android runtime should avoid depending on libc++ instead of working around duplicate libunwind symbols or switching to shared libc++. Related references:

Size impact

Earlier measurements on this branch used samples/NativeAOT/NativeAOT.csproj built in Release with _AndroidTypeMapImplementation=trimmable.

Artifact Parent libc++ baseline No-libc++ build Difference
arm64 APK 1,575,849 B 1,296,320 B -279,529 B (-17.74%)
x64 APK 1,639,459 B 1,353,661 B -285,798 B (-17.43%)
arm64 libNativeAOT.so 3,481,880 B 2,727,936 B -753,944 B (-21.65%)
x64 libNativeAOT.so 3,404,896 B 2,664,048 B -740,848 B (-21.76%)

libNativeAOT.so is the per-ABI native shared library packaged in the APK, for example lib/arm64-v8a/libNativeAOT.so. It is not the whole Android app package; the APK also contains manifest, resources, Java stubs/classes, signatures, and packaging assets.

Validation

Validated locally during the latest iteration:

  • dotnet test tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj --no-restore — 457 passed.

Previous branch validation:

  • rebuilt src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj;
  • rebuilt NativeAOT runtime archives for android-arm64 and android-x64;
  • built samples/NativeAOT/NativeAOT.csproj with _AndroidTypeMapImplementation=trimmable for android-arm64 and android-x64;
  • verified generated NativeAOT link response files contain no libc++/libc++abi inputs;
  • verified produced APKs contain no libc++ entries;
  • verified llvm-nm -u reports no undefined C++ runtime-looking symbols in the final libNativeAOT.so outputs;
  • smoke-tested the arm64 APK on an arm64 emulator: libNativeAOT.so loaded without libc++, MainApplication and MainActivity native callbacks ran, MainActivity.OnCreate() logged, and the process remained alive.

Current status

The PR is still draft/WIP. A CI follow-up fixed the NativeAOT trimmable typemap build failures caused by private __ArrayMapRank* anchors producing invalid NativeAOT metadata and unresolved link symbols.

The x64 APK builds and packages without libc++, but local x64 runtime validation still needs an x64 emulator host because Android emulator x86_64 system images are not accepted on Apple Silicon/aarch64 hosts.

simonrozsival and others added 3 commits May 7, 2026 11:00
MAUI net11.0 currently generates net11.0-android36.1, but dotnet/android now produces Android 37 packs only. Copy a checked-in Directory.Build.Override.props into the MAUI checkout so the integration leg packs net11.0-android37.0 until dotnet/maui updates net11.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MAUI's Cake script deletes Directory.Build.Override.props when no platform switch is passed, so copying an override file does not survive until dotnet-pack. Apply a checked-in patch directly to the MAUI checkout instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the explicit NativeAOT final-link dependency on libc++/libc++abi and keep the Android NativeAOT link guarded with -nostdlib++.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival
Copy link
Copy Markdown
Member Author

Emulator validation update

I tested the signed NativeAOT + trimmable typemap sample APK on an arm64 emulator after rebuilding/overlaying the local validation packs.

What works:

  • The arm64 APK installs and launches on emulator-5554.
  • lib/arm64-v8a/libNativeAOT.so loads successfully with no libc++ packaged in the APK.
  • Startup reaches managed code: MainApplication and MainActivity native callbacks run, MainActivity.OnCreate() logs, and the process remains alive.

Important caveats:

  • This arm64 smoke currently requires trimmable NativeAOT startup fixes plus two validation-only workarounds:
    • pointing ILC TypeMapEntryAssembly at the app typemap (_NativeAOT.TypeMap) instead of the root _Microsoft.Android.TypeMaps, because scanning _Mono.Android.TypeMap currently fails on Android.Text.IInputType being present in the ref assembly but absent from the runtime assembly;
    • skipping UncaughtExceptionMarshaler setup for trimmable NativeAOT to avoid the IUncaughtExceptionHandler/JavaProxyThrowable startup path.
  • I do not consider those two workarounds shippable as-is; they need separate root-cause fixes before this can be more than a feasibility proof.
  • x64 builds and packages without libc++ (-nostdlib++ is in the link response and no libc++ entries are in the APK), but I could not run the x64 APK locally: the Android emulator rejects x86_64 system images on this Apple Silicon host (Avd's CPU Architecture 'x86_64' is not supported by the QEMU2 emulator on aarch64 host). x64 runtime behavior still needs validation on an x64 emulator host.

simonrozsival and others added 4 commits May 9, 2026 01:16
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…iveaot-drop-libcpp

# Conflicts:
#	external/Java.Interop
#	src/Mono.Android/Mono.Android.csproj
#	src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
The merge of origin/main brought in PR #11256, which switched native
linking from an inline `clang` Exec invocation to the
LinkNativeAotSharedLibrary task driving `ld.lld` directly. Taking
origin/main's version of Microsoft.Android.Sdk.NativeAOT.targets
re-introduced the explicit `libc++_static.a` and `libc++abi.a` includes
in @(_NdkLibs), reversing the branch's purpose.

Drop those includes. With ld.lld invoked directly, no C++ stdlib is
linked unless we list it explicitly, so `-nostdlib++` (a clang driver
flag) is not needed. cxx-shims.cc continues to provide the minimal C++
runtime shims required by NativeAOT.

Also update the now-stale `LinkStandardCPlusPlusLibrary>false` and
`libstdc++compat.a` removal comments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT roots array typemap dictionaries from the root typemap
assembly, which references the per-assembly __ArrayMapRank* anchor
types. Keep those anchors public so the generated metadata is valid
across assembly boundaries.

Add test coverage for the emitted visibility.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival changed the title [WIP] Explore dropping libc++ from NativeAOT linking [WIP] Drop libc++ from Android NativeAOT linking May 12, 2026
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.

1 participant