[TrimmableTypeMap] Add trimmable DotNetRun cases#11486
Conversation
Add Release and Debug trimmable typemap coverage to the DotNetRun device integration test using CoreCLR. Fixes #11019 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds trimmable typemap coverage to the DotNetRun device integration test matrix, ensuring the trimmable typemap path is exercised under CoreCLR (UseMonoRuntime=false) in both Debug and Release configurations.
Changes:
- Add Release
trimmableDotNetRun test case usingAndroidRuntime.CoreCLR. - Add Debug
trimmableDotNetRun test case usingAndroidRuntime.CoreCLR.
Add Release NativeAOT coverage for the trimmable typemap DotNetRun device integration test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/android/sessions/9552bfeb-121e-4610-bd28-49396c6295a7 Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dotnet/android/sessions/9552bfeb-121e-4610-bd28-49396c6295a7 Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
The dependabot bump (#11562) committed banned-apis.targets with CRLF bytes stored directly in the git blob. Since .gitattributes declares `*.targets eol=crlf`, the blob must be stored normalized (LF) and only converted to CRLF on checkout. The un-normalized blob caused the CI 'Ensure no modified/untracked files' check to fail because git's renormalization detection flagged the file as modified. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
…-build failure) The Debug CoreCLR trimmable DotNetRun case fails identically to the already-ignored Release case: `dotnet run --no-build` re-runs GenerateNativeApplicationConfigSources, which throws XAGCA7023 because obj/Debug/android/assets/<rid>/Mono.Android.dll is missing in the no-build incremental state. Broaden the existing ignore to cover both Debug and Release CoreCLR trimmable until the underlying no-build issue is fixed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
The trimmable _GenerateJavaStubs target listed _CleanIntermediateIfNeeded in its DependsOnTargets. On a full build that is redundant (the target already runs early via _AndroidBuildDependsOn in BuildOrder.targets). But during an incremental deploy that does not rebuild (the Install/DeployToDevice chain used by `dotnet run` without a build), the early Build chain never executes, so this was the only invocation of _CleanIntermediateIfNeeded -- and it ran late, *after* _PrepareAssemblies had already populated obj/<config>/android/assets/<abi>/*.dll. It then deleted obj/<config>/android, and because _PrepareAssemblies had already executed it was skipped and did not recreate the assemblies. _GeneratePackageManagerJava then failed with XAGCA7023 (DirectoryNotFoundException on assets/<abi>/Mono.Android.dll). Remove _CleanIntermediateIfNeeded from the trimmable _GenerateJavaStubs DependsOnTargets so it matches the llvm-ir sibling target, which already omits it. Cleaning still happens early for full builds via BuildOrder.targets. With this fix, the trimmable DotNetRun scenarios (Debug CoreCLR, Release CoreCLR, NativeAOT) build, deploy, and launch on device, so remove the Assert.Ignore guard that skipped the CoreCLR trimmable cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
GenerateTrimmableTypeMap cleans the post-trim Java source output directory before copying the Java sources that remain after trimming. On CI this cleanup can fail transiently with Directory not empty while recursively deleting nested source directories, which surfaces as XAGTT7024 and fails otherwise valid CoreCLR trimmable builds. Use the same retry policy and transient error handling as RemoveDirFixed for this internal cleanup path, including access denied, sharing violation, and directory-not-empty retries. The cleanup remains strict: non-transient delete errors still fail the build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
CoreCLR trimmable builds with multiple RuntimeIdentifiers run per-RID inner builds in parallel. Those inner builds used the outer intermediate directory for post-trim Java sources so the packaging phase could compile the shared Java output, but every RID inner build generated and cleaned the same obj/<configuration>/typemap/linked-java directory. That made the post-trim Java source generation race with itself. CI observed this as XAGTT7024 / Directory not empty while one inner build deleted the shared linked-java directory as another inner build was also using it. Retrying the recursive delete masks the symptom but leaves the shared-output race. Pass the outer RuntimeIdentifiers list into inner builds and let only the first RID inner build generate the shared post-trim Java sources. The output remains in the outer intermediate directory where _GenerateJavaStubs expects it, while parallel inner builds no longer clean or write the same directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
The trimmable Java sources are RID-independent, even though the linked assembly inputs are produced by per-RID inner builds. Generating those Java sources from inside the parallel RuntimeIdentifier inner builds made multiple inner builds clean and write the same outer intermediate linked-java directory. Move post-trim Java source generation to the outer build after _ResolveAssemblies has collected the per-RID ResolvedFileToPublish items. The target now runs once, uses a representative RID's linked assemblies as input for the RID-independent Java sources, and leaves the output in the outer intermediate directory where _GenerateJavaStubs expects it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Code Review — ✅ LGTM (2 optional 💡 suggestions)
Solid, well-iterated change. Public CI is green, and the test-matrix additions are correct: trimmable is exercised for Release/Debug CoreCLR and Release NativeAOT, with Debug NativeAOT correctly omitted (NativeAOT is Release-only per IgnoreUnsupportedConfiguration).
Severity counts: ❌ 0 ·
Worth flagging for reviewers (not a defect)
Despite the "add DotNetRun cases" framing, this PR also ships production build-logic changes that affect all trimmable CoreCLR builds, not just tests:
_GeneratePostTrimTrimmableTypeMapJavaSourcesmoves fromAfterTargets="ILLink"→AfterTargets="_ResolveAssemblies", keys off@(ResolvedFileToPublish), and is gated on_ComputeFilesToPublishForRuntimeIdentifiers != 'true'so it runs once in the outer build (avoiding the per-RID race fixed in the de245ba/e400d73 commits).- New
_PostTrimTypeMapFirstRuntimeIdentifier+ a first-RID filter to dedup multi-RID publishes. _CleanIntermediateIfNeededdropped from the_GenerateJavaStubsoverride. I verified this is safe — it still runs early via$(_AndroidBuildDependsOn), and the override is now consistent with theMicrosoft.Android.Sdk.TypeMap.LlvmIr.targets_GenerateJavaStubs, which also omits it.
These look correct and deliberate (they match the #11499 follow-up work), but the PR description doesn't mention them. A line in the description/changelog would help future archaeology.
Validation caveat
The new DotNetRun cases run on the device-integration pipeline, which isn't part of the green public CI checks visible here — so green public CI doesn't by itself prove the new cases pass on-device. The earlier resolved review thread confirms an on-device DotNetRun(True,"trimmable",CoreCLR) failure was the original motivation, so please confirm the on-device run is green before merge.
Nice work 👍
- Good incremental device coverage for the trimmable typemap.
- Correct handling of NativeAOT's Release-only constraint.
- Reuses the existing
$([System.String]::Copy(...).Split(';')[0])idiom already used for_TypeMapFirstAbiin the same file.
Two inline 💡 suggestions below — both are documentation-only and entirely optional.
Generated by Android PR Reviewer for issue #11486 · 1.1K AIC · ⌖ 29.7 AIC · ⊞ 37.6K
Comment /review to run again
jonathanpeppers
left a comment
There was a problem hiding this comment.
I updated PR desc with copilot, merging.
Adds
trimmabletypemap coverage to theDotNetRundevice integration test, and fixes two issues in the trimmable typemap targets that were uncovered while bringing those scenarios up.New test cases
Added to
InstallAndRunTests.Get_DotNetRun_Data:UseMonoRuntime=false)UseMonoRuntime=false)Fixes
dotnet run --no-buildfor trimmable CoreCLRThe trimmable
_GenerateJavaStubstarget listed_CleanIntermediateIfNeededin itsDependsOnTargets. On a full build that is redundant — the target already runs early via_AndroidBuildDependsOninBuildOrder.targets. But during an incremental deploy that does not rebuild (theInstall/DeployToDevicechain used bydotnet runwithout a build), the earlyBuildchain never executes, so this was the only invocation of_CleanIntermediateIfNeeded— and it ran late, after_PrepareAssemblieshad already populatedobj/<config>/android/assets/<abi>/*.dll. It then deletedobj/<config>/android, and because_PrepareAssemblieshad already executed it was skipped on the second pass and did not recreate the assemblies._GeneratePackageManagerJavathen failed withXAGCA7023(DirectoryNotFoundExceptiononassets/<abi>/Mono.Android.dll).Removed
_CleanIntermediateIfNeededfrom the trimmable_GenerateJavaStubsDependsOnTargetsso it matches thellvm-irsibling target, which already omits it. Cleaning still happens early for full builds viaBuildOrder.targets.Parallel multi-RID race in post-trim Java source generation
CoreCLR trimmable builds with multiple
RuntimeIdentifiersrun per-RID inner builds in parallel._GeneratePostTrimTrimmableTypeMapJavaSourcespreviously ran inside each inner build and wrote to the same outer intermediateobj/<config>/typemap/linked-javadirectory, so inner builds raced cleaning and writing the same shared output. CI observed this asXAGTT7024/ "Directory not empty" while one inner build deleted the sharedlinked-javadirectory as another was using it.The trimmed Java sources are RID-independent, so:
_GeneratePostTrimTrimmableTypeMapJavaSourcesto run once in the outer build, after_ResolveAssemblieshas collected the per-RIDResolvedFileToPublishitems, and before_GenerateJavaStubs/_CompileJava/_CompileToDalvik.@(ResolvedFileToPublish)to a single representative RID (_PostTrimTypeMapFirstRuntimeIdentifier, the first entry in$(RuntimeIdentifiers)), so the target only consumes one RID's linked assemblies as input._ComputeFilesToPublishForRuntimeIdentifiers != true).Output remains in the outer intermediate directory where
_GenerateJavaStubsexpects it.Fixes #11019
Related to #11604