Uh oh!
There was an error while loading. Please reload this page.
[TrimmableTypeMap] Generate the typemap before the NativeAOT inner build so the IDE Compile→Sign flow works - #11781
Conversation
The NativeAOT trimmable typemap is consumed only in the inner per-RID ILC build (via _AddTrimmableTypeMapAssembliesToIlc -> _ReadGeneratedTrimmableTypeMapAssemblies), which cannot generate it: _GenerateTrimmableTypeMap is gated to the outer build (_OuterIntermediateOutputPath == ''). Its only trigger is AfterTargets="CoreCompile", which does not fire when compilation is up-to-date - e.g. the IDE's separate "Compile" then "SignAndroidPackage" invocations (BuildingInsideVisualStudio=true). The outer build therefore never generated obj/.../typemap/typemap-assemblies.txt and the inner build failed with "Trimmable typemap assembly list ... was not found". Force _GenerateTrimmableTypeMap to run in the outer build before _ResolveAssemblies spawns the inner per-RID build. _ResolveAssemblies runs after compilation (it consumes @(IntermediateAssembly)), so the generator still observes the compiled app assembly. Mirrors the CoreCLR _AddTrimmableTypeMapToLinker target, which forces generation before the (outer) ILLink. Verified locally: DesignTimeBuildSignAndroidPackage(NativeAOT) now passes (was failing); DesignTimeBuildSignAndroidPackage(CoreCLR) continues to pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Ensures the NativeAOT trimmable typemap is generated early enough in the outer build so that IDE “Compile → SignAndroidPackage” (separate MSBuild invocations) doesn’t fail when CoreCompile is skipped and the typemap assembly list hasn’t been produced yet.
Changes:
- Adds a NativeAOT-specific target to force
_GenerateTrimmableTypeMapto run before_ResolveAssembliestriggers inner per-RID work. - Documents why the new ordering is needed (IDE split build vs single-invocation CLI build).
Show a summary per file
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.NativeAOT.targets | Adds a pre-_ResolveAssemblies “ensure typemap generated” target for NativeAOT builds. |
Copilot's findings
- Files reviewed: 1/1 changed files
- Comments generated: 2
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…tifier The "outer build" is the build that is not an inner per-RID build, which is determined by '$(_OuterIntermediateOutputPath)' == '' — the same discriminator _GenerateTrimmableTypeMap itself uses. The previous 'RuntimeIdentifier == '' condition missed the single-RID outer build (e.g. -p:RuntimeIdentifier=android-arm64), where RuntimeIdentifier is non-empty but the build is still the outer one, leaving the typemap ungenerated and reproducing the same failure this change fixes. The inner build receives _OuterIntermediateOutputPath via _ResolveAssemblies AdditionalProperties, so the target is still correctly skipped there. Verified locally: DesignTimeBuildSignAndroidPackage(NativeAOT) and (CoreCLR) both pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival
commented
Jun 28, 2026
Good catch — fixed in e68ee2c. The target now gates on |
simonrozsival
commented
Jun 29, 2026
Superseded by #11789, which uses a branch on dotnet/android directly (same commits). |
Summary
The NativeAOT trimmable typemap (the generated Java ↔ .NET type map) is consumed by the inner per-RID ILC build — via
_AddTrimmableTypeMapAssembliesToIlc→_ReadGeneratedTrimmableTypeMapAssemblies— which reads the generated assembly list atobj/.../typemap/typemap-assemblies.txt. The inner build cannot generate that list:_GenerateTrimmableTypeMapis gated to the outer build ('$(_OuterIntermediateOutputPath)' == '')._GenerateTrimmableTypeMap's only trigger isAfterTargets="CoreCompile". That hook does not fire when compilation is already up-to-date — which is exactly what happens in the IDE's split build, where Visual Studio (BuildingInsideVisualStudio=true) runsCompileandSignAndroidPackageas two separate MSBuild invocations. During theSignAndroidPackagecall the C# is already compiled, soCoreCompileis skipped, the typemap is never generated, and the inner ILC build fails with:A regular command-line
Buildworks because all targets run in one continuous invocation; only the IDE Compile→Sign sequence hits this. Reproduced by theDesignTimeBuildSignAndroidPackage(NativeAOT)test.Fixes#11775.
Fix
Add a target that forces the typemap to be generated in the outer build before
_ResolveAssembliesspawns the inner per-RID ILC build:Instead of relying on the fragile
AfterTargets="CoreCompile"hook, generation is anchored to_ResolveAssemblies, which always runs before the inner build and runs after compilation (it consumes@(IntermediateAssembly)), so the generator still observes the compiled app assembly. This mirrors the CoreCLR_AddTrimmableTypeMapToLinkertarget, which forces generation before the (outer) ILLink.Risk
Low and well-scoped: the new target is conditioned to the outer build (
RuntimeIdentifier == '') and lives in the NativeAOT trimmable targets file; it only ensures an already-required step has run. No effect on CoreCLR, managed, or MonoVM paths.Testing
Verified locally:
DesignTimeBuildSignAndroidPackage(NativeAOT)now passes (was failing);DesignTimeBuildSignAndroidPackage(CoreCLR)continues to pass.Sliced out of #11617 for focused review.