[TrimmableTypeMap] Add GenerateTrimmableTypeMap MSBuild task and targets#10924
Conversation
d28814e to
04e0b2e
Compare
2d666a1 to
5bf8492
Compare
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict: ✅ LGTM
Found 0 issues.
Reviewed against all 14 rule categories:
- ✅ MSBuild tasks: Extends
AndroidTask,TaskPrefixdefined, returns!Log.HasLoggedErrors,[Required]properties have defaults,[Output]properties nullable - ✅ MSBuild targets: Internal names prefixed with
_,Inputs/Outputswith stamp file for incrementality,AfterTargetsused appropriately (noDependsOnavailable), noTrimmerRootAssembly(correct — trimmer must process TypeMapAttributes) - ✅ Nullable: No null-forgiving
!, no#nullable enable(project-level) - ✅ Error handling:
ParseTargetFrameworkVersionthrows on bad input, no empty catch blocks - ✅ Performance: BCL assemblies filtered via
FrameworkAssembly/HasMonoAndroidReferencemetadata, per-assembly timestamp check skips unchanged typemaps, LINQ used cleanly - ✅ Code organization: Types made
publicfor cross-assembly consumption (build-time only, not shipped in apps),UsingTaskscoped to trimmable targets only - ✅ Formatting: Tabs, Mono style throughout
👍 Clean task design with good incrementality (per-assembly timestamp skipping). Benchmark data in the PR description validates the approach. RuntimeHostConfigurationOption correctly shared between CoreCLR and NativeAOT. AfterTargets usage is justified since there's no DependsOn property to hook into.
Review generated by android-reviewer from review guidelines.
81102b5 to
791bd4d
Compare
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict:
Found 4 issues (0 errors, 2 warnings, 2 suggestions).
⚠️ MSBuild targets: Generated typemap assemblies and Java files under$(IntermediateOutputPath)typemap\are not registered in@(FileWrites).IncrementalCleanmay delete them while the stamp file remains, breaking subsequent builds. (Trimmable.targets:47)⚠️ MSBuild targets: Item group empty check'@(_GeneratedTypeMapAssemblies)' != ''should use->Count()to avoid joining all paths into a string. (CoreCLR.targets:10,NativeAOT.targets:10)- 💡 API design: Several types were changed from
internaltopublicbut are only consumed by theGenerateTrimmableTypeMapMSBuild task. Consider adding[InternalsVisibleTo]forXamarin.Android.Build.Tasksinstead to keep the API surface minimal. (JavaPeerScanner.cs:17,JavaPeerInfo.cs:11, and 5 more files) - 💡 Nullable:
GenerateTrimmableTypeMap.csuses nullable annotations (ITaskItem[]?) but lacks#nullable enable— nullable flow analysis isn't active for this file. Other new task files in this project use per-file#nullable enable. (GenerateTrimmableTypeMap.cs:1)
👍 Positive callouts:
- Clean
AndroidTaskimplementation with correctreturn !Log.HasLoggedErrorspattern and proper[Required]/[Output]property declarations. - Good per-assembly incremental check via
IsUpToDatetimestamp comparison. - Thorough test coverage including empty inputs, real assembly scanning, incrementality, touched-source regeneration, and TFV parsing.
- The
FileWritespattern fromLlvmIr.targets(the existing typemap path) is a good reference for how to fix the FileWrites concern.
CI status: Pending — strong-name signing fix was just pushed. Previous run failed with CS8002 (unsigned assembly).
Review generated by android-reviewer from review guidelines.
...id.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets
Show resolved
Hide resolved
....Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.CoreCLR.targets
Outdated
Show resolved
Hide resolved
| /// Phase 2: Analyze types using cached indices | ||
| /// </summary> | ||
| sealed class JavaPeerScanner : IDisposable | ||
| public sealed class JavaPeerScanner : IDisposable |
There was a problem hiding this comment.
🤖 💡 API design — This type (and JavaPeerInfo, MarshalMethodInfo, JniParameterInfo, JavaConstructorInfo, ActivationCtorInfo, ActivationCtorStyle, JcwJavaSourceGenerator, RootTypeMapAssemblyGenerator, TypeMapAssemblyGenerator) were changed from internal to public. These are only consumed by the GenerateTrimmableTypeMap MSBuild task in Xamarin.Android.Build.Tasks. Making them public exposes them as API surface that customers could depend on.
Consider keeping them internal and adding [InternalsVisibleTo("Xamarin.Android.Build.Tasks")] in the TrimmableTypeMap csproj instead. This is consistent with the existing InternalsVisibleTo entries for test projects.
Rule: New helpers default to internal (Code Organization #4)
There was a problem hiding this comment.
Intentionally keeping these public. The benchmark script in the PR description consumes them directly, and they'll also be useful for the pre-generation step in #10760 which runs outside of Xamarin.Android.Build.Tasks. This assembly isn't part of the public SDK surface shipped to customers — it's an internal build-time dependency.
src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs
Outdated
Show resolved
Hide resolved
| static bool IsUpToDate (string outputPath, string assemblyName, Dictionary<string, string> sourcePathByName) | ||
| { | ||
| if (!File.Exists (outputPath)) { | ||
| return false; | ||
| } | ||
| if (!sourcePathByName.TryGetValue (assemblyName, out var sourcePath)) { | ||
| return false; | ||
| } | ||
| return File.GetLastWriteTimeUtc (outputPath) >= File.GetLastWriteTimeUtc (sourcePath); | ||
| } |
There was a problem hiding this comment.
I think this is ok for a first pass, but I think we could let MSBuild natively do the timestamp checking & run the target partially.
If you had:
<Target
Inputs="a.in;b.in;c.in"
Outputs="a.out;b.out;c.out"
<!-- ... -->
<MyTask InFiles="a.in;b.in;c.in" />If only b.in changes during an incremental build, MSBuild can run the target "partially", and it would automatically only pass in b.in to the task.
The Inputs/Outputs need to be 1-1, and then you can have additional Inputs files at the end of the list -- so you'd have to make sure the files coming are ordered that way.
If we did this, we'd get rid of _GenerateJavaStubs.stamp.
There is a AssertTargetIsPartiallyBuilt, we have in a few tests.
There was a problem hiding this comment.
Agreed — MSBuild partial builds with 1-1 Inputs/Outputs would be the right approach here. We iterated on the incremental build story during this PR and it was getting out of hand, so I'd like to tackle it in a dedicated follow-up PR once the trimmable typemap path is functionally complete. The current timestamp check inside the task is a reasonable first pass.
src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs
Outdated
Show resolved
Hide resolved
src/Xamarin.Android.Build.Tasks/Tasks/GenerateTrimmableTypeMap.cs
Outdated
Show resolved
Hide resolved
Xamarin.Android-PR CI Failure Summary (build 13546162)1.
|
...Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GenerateTrimmableTypeMapTests.cs
Show resolved
Hide resolved
| ITaskItem [] GenerateJcwJavaSources (List<JavaPeerInfo> allPeers) | ||
| { | ||
| var jcwGenerator = new JcwJavaSourceGenerator (); | ||
| var files = jcwGenerator.Generate (allPeers, JavaSourceOutputDirectory); |
There was a problem hiding this comment.
Is it worth seeing how/if having the JcwJavaSourceGenerator generate source for each type in parallel affects the build times? From what I can tell from #10917, each generation should be pretty independent.
There was a problem hiding this comment.
Same question for scanning.
There was a problem hiding this comment.
I will open an issue so we revisit this later and improve build time if possible.
There was a problem hiding this comment.
Filed #10958 to track this and other build-time optimization opportunities.
Add the MSBuild task that wires the TrimmableTypeMap scanner and generators into the build pipeline, replacing the stub _GenerateJavaStubs target. ### Task (GenerateTrimmableTypeMap) - Extends AndroidTask, TaskPrefix 'GTT' - Scans resolved assemblies for Java peer types - Generates per-assembly TypeMap .dll assemblies - Generates root _Microsoft.Android.TypeMaps.dll - Generates JCW .java source files for ACW types ### Targets - Microsoft.Android.Sdk.TypeMap.Trimmable.targets: replaces stub with real GenerateTrimmableTypeMap task call - CoreCLR.targets: adds generated assemblies as TrimmerRootAssembly, configures RuntimeHostConfigurationOption for TypeMappingEntryAssembly - NativeAOT.targets: adds to IlcReference, UnmanagedEntryPointsAssembly, and TrimmerRootAssembly Co-authored-by: Copilot <[email protected]>
Tests using MockBuildEngine: - Empty assembly list succeeds with no outputs - Real Mono.Android.dll produces per-assembly + root typemap assemblies - Different TargetFrameworkVersion formats all parse correctly Co-authored-by: Copilot <[email protected]>
Full build integration tests: - Build with _AndroidTypeMapImplementation=trimmable succeeds on CoreCLR - Incremental build skips _GenerateJavaStubs when nothing changed Co-authored-by: Copilot <[email protected]>
…n bad version - Extract Phase 1-5 into named methods (ScanAssemblies, GenerateTypeMapAssemblies, GenerateJcwJavaSources) — no more // Phase N comments - Filter BCL assemblies: skip FrameworkAssembly=true unless HasMonoAndroidReference - Throw on unparseable TargetFrameworkVersion instead of silent fallback - Use LINQ for grouping peers by assembly and filtering paths - Deterministic output ordering via OrderBy on assembly name Co-authored-by: Copilot <[email protected]>
- Both GenerateTypeMapAssemblies and GenerateJcwJavaSources now return ITaskItem[] directly — no intermediate conversion in RunTask - Move Java output under typemap dir (typemap/java instead of android/src) - Remove TrimmerRootAssembly from generated assemblies — the trimmer must process TypeMapAttributes and trim entries whose trimTarget types were removed. TrimmerRootAssembly would prevent this, defeating the purpose. - NativeAOT: keep IlcReference + UnmanagedEntryPointsAssembly but remove TrimmerRootAssembly for the same reason. Co-authored-by: Copilot <[email protected]>
Compare source assembly timestamp against generated typemap .dll — skip emission when the output is newer. Root assembly only regenerated when any per-assembly typemap changed. Typical incremental build: only app assembly changed → scan all (for cross-assembly resolution) but only emit _MyApp.TypeMap.dll + root. Mono.Android scan is unavoidable (xref resolution) but its typemap emission is skipped. Co-authored-by: Copilot <[email protected]>
- SecondRun_SkipsUpToDateAssemblies: run twice with same inputs, verify typemap file timestamp unchanged and 'up to date' logged - SourceTouched_RegeneratesOnlyChangedAssembly: touch source assembly, verify typemap is regenerated with newer timestamp - InvalidTargetFrameworkVersion_Throws: verify ArgumentException - Extracted CreateTask helper to reduce test boilerplate - ParsesTargetFrameworkVersion converted to [TestCase] parameterized test Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Both CoreCLR and NativeAOT need to know the TypeMap entry assembly. RuntimeHostConfigurationOption works for both (runtimeconfig.json for CoreCLR, ILC feature switch for NativeAOT). Co-authored-by: Copilot <[email protected]>
Make types consumed by the MSBuild task public (they're build-time only, not shipped in apps): JavaPeerInfo, MarshalMethodInfo, JniParameterInfo, JavaConstructorInfo, ActivationCtorInfo, ActivationCtorStyle, JavaPeerScanner, TypeMapAssemblyGenerator, RootTypeMapAssemblyGenerator, JcwJavaSourceGenerator. Fix Execute_InvalidTargetFrameworkVersion test: AndroidTask catches exceptions and logs them as errors, so Assert.Throws doesn't work. Check task.Execute() returns false and errors are logged instead. Co-authored-by: Copilot <[email protected]>
Generate Java content to StringWriter first, compare with existing file. Only write to disk if content changed. This avoids unnecessary javac recompilation on incremental builds where types haven't changed. Benchmark showed JCW file writing was the biggest bottleneck (~511ms p50 for 315 files). With this change, incremental builds that don't change any types skip all disk writes. Co-authored-by: Copilot <[email protected]>
…builds" This reverts commit ac4227b.
Co-authored-by: Copilot <[email protected]>
The Xamarin.Android.Build.Tasks project is strong-name signed and references Microsoft.Android.Sdk.TrimmableTypeMap, which was not signed. This caused CS8002 on all CI platforms. Add SignAssembly + AssemblyOriginatorKeyFile to both the library and its unit test project, and add the public key to the InternalsVisibleTo entry. Co-authored-by: Copilot <[email protected]>
- Add @(FileWrites) for generated typemap assemblies and Java files to prevent IncrementalClean from deleting them. - Use ->Count() instead of != '' for item group empty checks in CoreCLR and NativeAOT targets. - Add #nullable enable to GenerateTrimmableTypeMap.cs. Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Exercises the early-return path in RunTask() when the scanner finds no [Register] types in the provided assemblies. Co-authored-by: Copilot <[email protected]>
…ectory Remove hardcoded Microsoft.Android.Ref.35 path that would break when the API level changes. MonoAndroidFrameworkDirectory already resolves the correct version dynamically via XABuildConfig. Co-authored-by: Copilot <[email protected]>
- Leave GeneratedAssemblies/GeneratedJavaFiles null when no peers found instead of assigning empty arrays (review: jonathanpeppers) - Use MonoAndroidHelper.IsMonoAndroidAssembly() instead of custom FrameworkAssembly/HasMonoAndroidReference logic (review: jonathanpeppers) - Replace LINQ Select+ToArray with simple loop in GenerateJcwJavaSources to avoid unnecessary ITaskItem cloning (review: jonathanpeppers) Co-authored-by: Copilot <[email protected]>
The bare filename 'Xamarin.Android.Build.Tasks.dll' doesn't resolve at runtime. All other shipped UsingTask elements use the $(_XamarinAndroidBuildTasksAssembly) property which contains the full path to the task assembly. Co-authored-by: Copilot <[email protected]>
Two fixes for CI test failures: 1. Integration tests (BuildWithTrimmableTypeMap*): Add Microsoft.Android.Sdk.TrimmableTypeMap.dll/pdb to _MSBuildFiles in create-installers.targets so the dependency is packaged into the SDK tools directory. Without this, GenerateTrimmableTypeMap task fails at runtime with a missing assembly error. 2. Unit tests (Execute*): FindMonoAndroidDll now returns ITaskItem with HasMonoAndroidReference=True metadata. The review change in 64725e6 switched GetJavaInteropAssemblyPaths to use MonoAndroidHelper.IsMonoAndroidAssembly which requires metadata on TaskItems. Bare TaskItem(path) was rejected, causing 0 assemblies to be scanned. Co-authored-by: Copilot <[email protected]>
e2c8868 to
3e0d62f
Compare
JavaFieldInfo is exposed through the public JavaPeerInfo.JavaFields property but was not itself marked public, causing CS0050 accessibility errors when building Xamarin.Android.Build.Tasks which references the assembly. Co-authored-by: Copilot <[email protected]>
…ults Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) Co-authored-by: Copilot <[email protected]>
…ults Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) Co-authored-by: Copilot <[email protected]>
…ults Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) Co-authored-by: Copilot <[email protected]>
Full Build,SignAndroidPackage cannot succeed yet because manifest generation (GenerateMainAndroidManifest) is not implemented for the trimmable typemap path. Scope tests to _GenerateJavaStubs target which validates the typemap + JCW generation that is implemented. Co-authored-by: Copilot <[email protected]>
When _GenerateJavaStubs is invoked directly (e.g., via /t:_GenerateJavaStubs in tests), the Build target does not run, so _CleanIntermediateIfNeeded never creates the stamp directory. The Touch task then fails because the stamp/ directory doesn't exist. Fix by: 1. Adding _CleanIntermediateIfNeeded to DependsOnTargets so the stamp directory and properties cache are created (needed for incremental builds). 2. Adding a defensive MakeDir before Touch as a safety net. Co-authored-by: Copilot <[email protected]>
Running _GenerateJavaStubs directly fails because _ResolveAssemblies needs the compiled project DLL and Resource.Designer.dll which only exist after a full Build. Instead, run the full Build,SignAndroidPackage target with ThrowOnBuildFailure=false (the build fails downstream at manifest generation, which is not yet implemented for the trimmable path) and verify _GenerateJavaStubs ran by checking typemap outputs. Co-authored-by: Copilot <[email protected]>
…mmable-typemap-05-msbuild-task
…ults Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) Co-authored-by: Copilot <[email protected]>
…ults Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) Co-authored-by: Copilot <[email protected]>
…ults (#10959) Part of #10807. Stacked on #10924. The trimmable typemap path needs acw-map.txt for _ConvertCustomView to fix up custom view names in layout XMLs. This adds acw-map generation as a side-output of GenerateTrimmableTypeMap — the task already has all JavaPeerInfo records from scanning, so no extra scan is needed. Changes: - AcwMapWriter: converts JavaPeerInfo → acw-map.txt format (3 lines per type: partial-asm-qualified, managed, compat-jni — matching legacy format) - GenerateTrimmableTypeMap: new AcwMapDirectory input + PerAssemblyAcwMapFiles output, writes per-assembly acw-map.{AssemblyName}.txt during generation - Trimmable.targets: _MergeAcwMaps target concatenates per-assembly files into the single acw-map.txt consumed by _ConvertCustomView and R8 - 8 unit tests for AcwMapWriter (263 total tests pass) ## Fix duplicate _PerAssemblyAcwMapFiles and AfterTargets chain Clear @(_PerAssemblyAcwMapFiles) before re-globbing in _CollectPerAssemblyAcwMaps to avoid duplicate items when _GenerateJavaStubs runs (task Output + glob both populate the group). Replace chained AfterTargets with DependsOnTargets for internal ordering, keeping a single AfterTargets hook on _MergeAcwMaps. ## Address review: fix line endings in tests, update docs, add AcwMapDirectory to test call sites - Normalize line endings in AcwMapWriterTests (Split on \n after replacing \r\n) so tests pass on Windows - Fix PerAssemblyAcwMapFiles XML doc to describe actual 3-line format - Add AcwMapDirectory to GenerateTrimmableTypeMap test call sites - Clarify AcwMapWriter comment: no conflict detection, LoadMapFile uses first-entry-wins for duplicate keys ## Use MemoryStreamPool and Files.CopyIfStreamChanged for acw-map writes Move file I/O from AcwMapWriter.WriteToFile to GenerateTrimmableTypeMap where MemoryStreamPool.Shared.CreateStreamWriter() and Files.CopyIfStreamChanged() are available, matching the RtxtWriter pattern. AcwMapWriter is now a pure formatting utility (Write to TextWriter only). Co-authored-by: Copilot <[email protected]>
Part of #10800
Stacked on #10917.
Summary
Adds the
GenerateTrimmableTypeMapMSBuild task and wires it into the trimmable targets files, replacing the stub_GenerateJavaStubstarget with real typemap + JCW generation.Visibility & signing changes
JavaPeerScanner,JavaPeerInfo,JcwJavaSourceGenerator,TypeMapAssemblyGenerator,RootTypeMapAssemblyGenerator, etc.)publicso they can be consumed by the MSBuild task inXamarin.Android.Build.Tasks.product.snk) toMicrosoft.Android.Sdk.TrimmableTypeMapand its unit test project — required becauseXamarin.Android.Build.Tasksis strong-name signed.Task (
GenerateTrimmableTypeMap)AndroidTask(TaskPrefixGTT).dllassemblies → generates root_Microsoft.Android.TypeMaps.dll→ generates JCW.javasource filesFrameworkAssembly=truewithoutHasMonoAndroidReference) to skip unnecessary scanning.TypeMap.dllis newer than source.dllTargets
Microsoft.Android.Sdk.TypeMap.Trimmable.targets: Replaces stub with realGenerateTrimmableTypeMaptask call. Defines_TypeMapOutputDirectoryand_TypeMapJavaOutputDirectory(co-located undertypemap/). ConfiguresRuntimeHostConfigurationOptionforTypeMappingEntryAssembly.Trimmable.CoreCLR.targets: Adds generated assemblies to_ResolvedAssembliesfor the linker (withoutTrimmerRootAssembly— the trimmer must processTypeMapAttributeentries and trim ones whose target types were removed).Trimmable.NativeAOT.targets: Adds toIlcReference+UnmanagedEntryPointsAssembly(withoutTrimmerRootAssembly).Performance
Benchmark on MacBook M1, scanning
Mono.Android.dll(~8870 types), 169 iterations over 5 minutes:Cold build cost is dominated by JCW file I/O (high p95 variance from disk contention). Incremental builds (unchanged assemblies) skip emit entirely — only the scan runs (~215ms).
Note: scanning currently rescans all assemblies on every build (needed for cross-assembly type resolution). This is a known limitation — future optimization could cache scan results or add a two-list scan overload that only produces
JavaPeerInfofor changed assemblies while still indexing all for cross-references. Profiling is needed before optimizing.Benchmark script
Tests
Unit tests (8 tests with
MockBuildEngine):Integration tests (full
dotnet build):_AndroidTypeMapImplementation=trimmableon CoreCLR succeeds_GenerateJavaStubsFollow-up work
Scanoverload or cached indices)_Mono.Android.TypeMap.dllduring SDK build ([CoreCLR] Build R2R images for SDK assemblies in Debug builds #10760)