[TrimmableTypeMap] Generate the typemap before the NativeAOT inner build so the IDE Compile→Sign flow works#11789
Merged
simonrozsival merged 2 commits intoJun 29, 2026
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>
…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>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a NativeAOT + trimmable typemap build-order problem that occurs in the IDE “Compile → SignAndroidPackage” split invocation flow. It ensures the outer build generates the typemap (and its typemap-assemblies.txt list) before _ResolveAssemblies spawns the inner per-RID NativeAOT/ILC build that consumes that list, preventing inner-build failures when CoreCompile is skipped as up-to-date.
Changes:
- Add an outer-build-only target that runs
_GenerateTrimmableTypeMapbefore_ResolveAssembliesfor NativeAOT builds, ensuring the typemap assembly list exists for the inner 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 _EnsureTrimmableTypeMapGeneratedForNativeAotInnerBuild to force typemap generation in the outer build prior to _ResolveAssemblies spawning the inner per-RID build. |
Copilot's findings
- Files reviewed: 1/1 changed files
- Comments generated: 0
Member
Author
|
/review |
jonathanpeppers
approved these changes
Jun 29, 2026
simonrozsival
deleted the
dev/simonrozsival/fix-nativeaot-typemap-ide-sign
branch
June 29, 2026 14:47
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.
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.