You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[CoreCLR] Build R2R images for SDK assemblies in Debug builds #10760
To improve runtime performance in Debug builds, we could pre-compile R2R images for all the libraries (Mono.Android.dll, ideally also Microsoft.Maui.Controls.dll and other MAUI assemblies) which don't change after they are restored.
The idea is to create the R2R image only during the first Debug build for a given target RID and cache this image in the obj/Debug/<rid>/r2r directory. This step should be skipped on any subsequent builds of the app (requires a build test).
The pre-built native images need to be included in the app alongside the managed assemblies so that CoreCLR will load them and avoid JITting code at startup. I wonder if we should embed the images into the .dll directly instead of creating a separate .ni.dll so that we don't need to make any changes to FastDev.
Open questions:
Can we build a composite image of all .NET for Android and .NET MAUI assemblies?
Does this change require changes to FastDev?
Do we need to make changes to AssemblyStoreBuilder (ClrAddIgnoredNativeImageAssembly), or is it only relevant for Release builds?
An alternative to building R2R images on the first Debug build of every app: we could R2R Mono.Android.dllahead of time at SDK build time and ship the pre-compiled images in the workload itself. This avoids any per-developer / per-app first-build cost.
Rough sketch of how it would fit into our current pack layout (after #10038 / #9606):
SDK build: run crossgen2 over Mono.Android.dll (and likely Java.Interop.dll / Mono.Android.Runtime.dll) once per Android RID (android-arm, android-arm64, android-x86, android-x64) targeting CoreCLR.
Managed pack (Microsoft.Android.Runtime.Managed.*.android) — the architecture-less pack that currently contains the single shared Mono.Android.dll — would no longer be consumed by CoreCLR apps. It remains the source of Mono.Android.dll for MonoVM and NativeAOT, which don't benefit from R2R images.
CoreCLR runtime packs (Microsoft.Android.Runtime.CoreCLR.<api>.<rid>) — which today only contain per-RID native assets (libnet-android.*.so, libpinvoke-override-*.a, etc.) — would also carry the R2R'd, per-RID copy of Mono.Android.dll (and friends). The SDK targets would resolve Mono.Android.dll from this pack when $(_AndroidRuntime) == CoreCLR, in preference to the managed pack.
Trade-offs vs. the build-time approach in this issue:
✅ No first-build penalty; Debug builds are immediately fast.
❌ Doesn't help user libraries or MAUI assemblies — those would still need a build-time / publish-time R2R step (the original proposal here).
The two approaches are complementary: ship pre-R2R'd SDK assemblies via the CoreCLR packs, and use the build-time mechanism described above for user code + MAUI. Related: #10792 (pre-generating the Mono.Android trimmable type map) lines up naturally — if the typemap is generated into a Mono.Android.TrimmableTypeMap.dll at SDK build time, we can crossgen2 it in the same step.
Activity
jonathanpeppers commentedon Jun 9, 2026
An alternative to building R2R images on the first Debug build of every app: we could R2R
Mono.Android.dllahead of time at SDK build time and ship the pre-compiled images in the workload itself. This avoids any per-developer / per-app first-build cost.Rough sketch of how it would fit into our current pack layout (after #10038 / #9606):
crossgen2overMono.Android.dll(and likelyJava.Interop.dll/Mono.Android.Runtime.dll) once per Android RID (android-arm,android-arm64,android-x86,android-x64) targeting CoreCLR.Microsoft.Android.Runtime.Managed.*.android) — the architecture-less pack that currently contains the single sharedMono.Android.dll— would no longer be consumed by CoreCLR apps. It remains the source ofMono.Android.dllfor MonoVM and NativeAOT, which don't benefit from R2R images.Microsoft.Android.Runtime.CoreCLR.<api>.<rid>) — which today only contain per-RID native assets (libnet-android.*.so,libpinvoke-override-*.a, etc.) — would also carry the R2R'd, per-RID copy ofMono.Android.dll(and friends). The SDK targets would resolveMono.Android.dllfrom this pack when$(_AndroidRuntime) == CoreCLR, in preference to the managed pack.Trade-offs vs. the build-time approach in this issue:
obj/Debug/<rid>/r2rcache, no FastDev impact for the SDK assemblies, no app-side crossgen2 invocation, no XALNS7015-style ordering concerns (see Fix XALNS7015: run FixAbstractMethodsStep before R2R in non-trimmed CoreCLR builds #11027).Mono.Android.dllback to 4 per-RID copies for CoreCLR (one of the concerns from [.NET 10] investigate how to ship fewer copies ofMono.Android.dll#9606). The R2R images themselves add additional size on top.The two approaches are complementary: ship pre-R2R'd SDK assemblies via the CoreCLR packs, and use the build-time mechanism described above for user code + MAUI. Related: #10792 (pre-generating the
Mono.Androidtrimmable type map) lines up naturally — if the typemap is generated into aMono.Android.TrimmableTypeMap.dllat SDK build time, we can crossgen2 it in the same step.