Skip to content

[net11.0] Enable R2R for System.Private.CoreLib only (Debug)#25567

Closed
davidnguyen-tech wants to merge 5 commits into
dotnet:net11.0from
davidnguyen-tech:feature/corelib-only-r2r-debug
Closed

[net11.0] Enable R2R for System.Private.CoreLib only (Debug)#25567
davidnguyen-tech wants to merge 5 commits into
dotnet:net11.0from
davidnguyen-tech:feature/corelib-only-r2r-debug

Conversation

@davidnguyen-tech
Copy link
Copy Markdown
Member

@davidnguyen-tech davidnguyen-tech commented May 28, 2026

Restrict the Debug iOS / tvOS / Mac Catalyst CoreCLR R2R composite to root only on
System.Private.CoreLib.dll. Every other R2R-eligible BCL / framework assembly becomes
an unrooted composite input — crossgen2 re-headers it to point at the per-app
<App>.r2r.dylib and skips codegen for it.

Net Debug-bundle change: a single <App>.r2r.framework replaces the upstream
Microsoft.NETCore.App.r2r.framework plus the per-module BCL frameworks.

Release, NativeAOT, Mono, and macOS are unchanged.

@davidnguyen-tech davidnguyen-tech changed the title [dotnet] Default Debug iOS/tvOS/MacCatalyst CoreCLR R2R to a CoreLib-only composite [net11.0] Enable R2R for System.Private.CoreLib only (Debug) May 28, 2026
Copilot AI and others added 3 commits May 28, 2026 17:52
…acCatalyst

Port the CoreLib-only R2R composite mechanism into the macios SDK targets as the
default behavior for Debug iOS/tvOS/MacCatalyst CoreCLR builds.

The two new targets:

- _ConfigureCoreLibOnlyCompositeRoots adds System.Private.CoreLib.dll as the sole
  root of @(PublishReadyToRunCompositeRoots), so every other framework assembly
  selected by _SelectR2RAssemblies becomes an unrooted composite input. crossgen2
  rewrites the unrooted inputs' component R2R header owner pointer to the local
  <App>.r2r.dylib (no codegen). Gated on Debug + CoreCLR + iOS/tvOS/MacCatalyst +
  composite-macho R2R + inner build.

- _DedupUnrootedReadyToRunPublish works around an asymmetry in
  Microsoft.NET.CrossGen.targets where _ReadyToRunCompositeUnrootedBuildInput is
  not removed from ResolvedFileToPublish (rooted inputs are), causing NETSDK1152
  'multiple publish output files with the same relative path'. Gated structurally
  on any user (or this SDK) having set composite roots.

Effect on a Debug iOS bundle: one <App>.r2r.dylib in place of
Microsoft.NETCore.App.r2r.dylib + per-module BCL dylibs. Smaller bundle, faster
cold startup, faster incremental build.

The default can be overridden per-project by declaring
PublishReadyToRunCompositeRoots statically in the csproj (or any imported
props/targets file) — see the build-properties.md docs and the follow-up commit
that enforces this opt-out gate.

Release builds and macOS/Mono/NativeAOT targets are not affected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mposite roots

Add '@(PublishReadyToRunCompositeRoots->Count())' == '0' to the
_ConfigureCoreLibOnlyCompositeRoots target condition so any user-provided
set in csproj/imported props takes precedence over the macios default.

The previously documented opt-out idiom (Remove="System.Private.CoreLib.dll")
was incorrect: at static evaluation the item group is empty, so the Remove is
a no-op, and the target subsequently Includes CoreLib regardless. Replace the
comment with the working opt-out pattern (static Include of any roots).

Verified locally with two builds:
  * Default Debug build: target fires, restricts roots to CoreLib only.
  * Build with Directory.Build.props that statically Includes
    PublishReadyToRunCompositeRoots: target does NOT fire (no 'Restricting'
    message), user's roots win. _DedupUnrootedReadyToRunPublish still fires
    because its gate stays decoupled from this policy decision.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…efault

Three tests covering the new _ConfigureCoreLibOnlyCompositeRoots and
_DedupUnrootedReadyToRunPublish targets in dotnet/targets/Microsoft.Sdk.R2R.targets:

1. Debug_DefaultsToCoreLibOnlyCompositeRoot — builds MySimpleApp Debug for
   iOS / tvOS / MacCatalyst CoreCLR, asserts both targets ran, and verifies the
   bundle contains exactly one <App>.r2r.framework with no upstream
   Microsoft.NETCore.App.r2r.framework or per-module *.r2r.dylib files.

2. Debug_UserSetCompositeRoots_OptsOutOfDefault — builds an inline csproj that
   statically declares PublishReadyToRunCompositeRoots (Include CoreLib + Linq),
   asserts _ConfigureCoreLibOnlyCompositeRoots did NOT run (the opt-out gate
   trips) and _DedupUnrootedReadyToRunPublish DID run (decoupled, fires whenever
   anyone sets composite roots).

3. Release_DoesNotRestrictCompositeRoots — builds MySimpleApp Release for the
   same three platforms and asserts the CoreLib-only policy target stays inert
   (the Configuration=Debug gate keeps the full per-module composite in Release).

Single-RID test cases throughout, mirroring the RuntimeIdentifiers == '' clause
on _SelectR2RAssemblies that the policy target intentionally shadows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidnguyen-tech davidnguyen-tech force-pushed the feature/corelib-only-r2r-debug branch from 9e607c2 to 7d7c63b Compare May 28, 2026 15:52
Add a BreakingChanges.md note for the Debug iOS/tvOS/MacCatalyst CoreCLR
bundle composition change: the bundle now contains a single per-app
.r2r.framework instead of the upstream Microsoft.NETCore.App.r2r.framework
plus per-module BCL .r2r.framework bundles.

Include the Include-based opt-out recipe for users who need to restore the
previous all-rooted composite, and call out that macOS / NativeAOT / Mono /
Release builds are unaffected.

PublishReadyToRunCompositeRoots itself is defined by the .NET SDK in
Microsoft.NET.CrossGen.targets; this commit only documents the macios-side
behavior change, not the SDK item group.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidnguyen-tech davidnguyen-tech force-pushed the feature/corelib-only-r2r-debug branch from 7d7c63b to 72e0405 Compare May 29, 2026 11:01
…ompositeTest

The Debug_DefaultsToCoreLibOnlyCompositeRoot test ran for iOS, tvOS and Mac
Catalyst but AssertCoreLibOnlyBundleComposition only understood the iOS/tvOS
shape (a <App>.r2r.framework under Frameworks/). Mac Catalyst packages the
composite as a <App>.r2r.dylib under Contents/MonoBundle/ instead (see
_CreateR2RModuleDylibs and the MacCatalyst-CoreCLR-R2R-size.txt baseline), so
the Mac Catalyst case would have failed both the "exactly one .r2r.framework"
and the "no *.r2r.dylib anywhere" assertions.

Make the helper platform-aware: assert the framework shape for iOS/tvOS and the
MonoBundle dylib shape for Mac Catalyst, and in both cases assert the upstream
Microsoft.NETCore.App.r2r.* image is not carried into the bundle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidnguyen-tech
Copy link
Copy Markdown
Member Author

Closing in favor of #25583

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants