Commit 4f35eef
[TrimmableTypeMap] Add GenerateTrimmableTypeMap MSBuild task and targets (#10924)
* [TrimmableTypeMap] Add GenerateTrimmableTypeMap MSBuild task and targets
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 <223556219+Copilot@users.noreply.github.com>
* Add unit tests for GenerateTrimmableTypeMap task
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 <223556219+Copilot@users.noreply.github.com>
* Add integration tests for trimmable TypeMap build pipeline
Full build integration tests:
- Build with _AndroidTypeMapImplementation=trimmable succeeds on CoreCLR
- Incremental build skips _GenerateJavaStubs when nothing changed
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Improve GenerateTrimmableTypeMap: extract methods, filter BCL, fail on 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 <223556219+Copilot@users.noreply.github.com>
* Fix task return types, Java output dir, remove TrimmerRootAssembly
- 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 <223556219+Copilot@users.noreply.github.com>
* Add per-assembly timestamp check to skip up-to-date typemaps
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 <223556219+Copilot@users.noreply.github.com>
* Add thorough incrementality tests for GenerateTrimmableTypeMap
- 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 <223556219+Copilot@users.noreply.github.com>
* Document future scan optimization path in task
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Move TypeMappingEntryAssembly config to shared targets
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 <223556219+Copilot@users.noreply.github.com>
* Make scanner/generator types public, fix invalid TFV test
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 <223556219+Copilot@users.noreply.github.com>
* Skip writing unchanged JCW Java files for faster incremental builds
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 <223556219+Copilot@users.noreply.github.com>
* Revert "Skip writing unchanged JCW Java files for faster incremental builds"
This reverts commit ac4227b.
* Move UsingTask to Trimmable.targets — only needed in trimmable path
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Sign TrimmableTypeMap assembly with product.snk
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 <223556219+Copilot@users.noreply.github.com>
* Address review: FileWrites, ->Count(), #nullable enable
- 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 <223556219+Copilot@users.noreply.github.com>
* Fix malformed <Touch> element in Trimmable.targets
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add test: no peers found with non-empty assembly input
Exercises the early-return path in RunTask() when the scanner finds
no [Register] types in the provided assemblies.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix FindMonoAndroidDll to use TestEnvironment.MonoAndroidFrameworkDirectory
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 <223556219+Copilot@users.noreply.github.com>
* Address review: use MonoAndroidHelper, leave outputs null, drop LINQ
- 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 <223556219+Copilot@users.noreply.github.com>
* Fix UsingTask to use $(_XamarinAndroidBuildTasksAssembly)
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 <223556219+Copilot@users.noreply.github.com>
* Fix CI: package TrimmableTypeMap DLL and add metadata to test TaskItems
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 <223556219+Copilot@users.noreply.github.com>
* Make JavaFieldInfo record public for MSBuild task consumption
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 <223556219+Copilot@users.noreply.github.com>
* Fix integration tests: target _GenerateJavaStubs only
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 <223556219+Copilot@users.noreply.github.com>
* Fix CI: ensure stamp directory exists for trimmable _GenerateJavaStubs
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 <223556219+Copilot@users.noreply.github.com>
* Fix CI: use full Build for trimmable typemap integration tests
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 <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>1 parent e0d2614 commit 4f35eef
File tree
15 files changed
+546
-19
lines changed- build-tools/installers
- src
- Microsoft.Android.Sdk.TrimmableTypeMap
- Generator
- Scanner
- Xamarin.Android.Build.Tasks
- Microsoft.Android.Sdk/targets
- Tasks
- Tests/Xamarin.Android.Build.Tests
- Tasks
- tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests
15 files changed
+546
-19
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
153 | 153 | | |
154 | 154 | | |
155 | 155 | | |
| 156 | + | |
| 157 | + | |
156 | 158 | | |
157 | 159 | | |
158 | 160 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
| 42 | + | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
12 | 14 | | |
13 | 15 | | |
14 | | - | |
| 16 | + | |
15 | 17 | | |
16 | 18 | | |
17 | 19 | | |
| |||
Lines changed: 7 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
| 127 | + | |
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| |||
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
211 | | - | |
| 211 | + | |
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| |||
224 | 224 | | |
225 | 225 | | |
226 | 226 | | |
227 | | - | |
| 227 | + | |
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
| |||
247 | 247 | | |
248 | 248 | | |
249 | 249 | | |
250 | | - | |
| 250 | + | |
251 | 251 | | |
252 | 252 | | |
253 | 253 | | |
| |||
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
281 | | - | |
| 281 | + | |
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
| |||
297 | 297 | | |
298 | 298 | | |
299 | 299 | | |
300 | | - | |
| 300 | + | |
301 | 301 | | |
302 | 302 | | |
303 | 303 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| |||
Lines changed: 13 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
| 1 | + | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
5 | 16 | | |
Lines changed: 15 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
| 1 | + | |
| 2 | + | |
3 | 3 | | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
4 | 17 | | |
Lines changed: 33 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
| 6 | + | |
| 7 | + | |
5 | 8 | | |
6 | 9 | | |
7 | 10 | | |
8 | 11 | | |
9 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
10 | 25 | | |
11 | 26 | | |
12 | 27 | | |
| |||
18 | 33 | | |
19 | 34 | | |
20 | 35 | | |
21 | | - | |
| 36 | + | |
22 | 37 | | |
23 | 38 | | |
24 | | - | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
25 | 55 | | |
26 | 56 | | |
27 | 57 | | |
| |||
0 commit comments