Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 2, 2025

Implementation Plan

  • Add LoadPrunePackageDataFromNearestFramework parameter to GetPackagesToPrune task
  • Update LoadPackagesToPrune method to accept and use the new parameter
  • Implement fallback logic for PrunePackageData folder loading similar to existing WindowsDesktop fallback
  • Implement fallback logic for targeting pack loading to find nearest framework
  • Update targets file to pass the new parameter from MSBuild property
  • Build and verify compilation succeeds
  • Verify build still works correctly
  • Address code review feedback (add constant for minimum framework version)
  • Refactor to use recursive function to eliminate code duplication
  • Move LoadPrunePackageDataFromNearestFramework to CacheKey
  • Move useFrameworkPackageData logic into recursive function
  • Add PrunePackageDataMinMajorVersion constant
  • Run security checks
  • Final verification complete

Summary

This PR successfully implements the LoadPrunePackageDataFromNearestFramework parameter for the GetPackagesToPrune task. The implementation:

  1. Adds a new boolean parameter LoadPrunePackageDataFromNearestFramework to control fallback behavior (defaults to false for backward compatibility)

  2. Includes the parameter in CacheKey - The value is now part of the cache key to ensure different parameter values produce different cached results

  3. Uses a recursive approach - TryLoadPackagesToPruneForVersion recursively searches for prune package data from previous framework versions when the current version's data is not found

  4. Handles framework version transitions - The recursive function now includes the useFrameworkPackageData logic, allowing it to fall back from .NET 10+ (which uses prune package data) to .NET 9 and below (which uses framework package data)

  5. Tries multiple data sources in order of preference:

    • For .NET 10+: PrunePackageData folder → Targeting packs → Framework packages (WindowsDesktop only)
    • For .NET 9 and below: Framework packages
    • Falls back to previous framework versions if enabled
  6. Eliminates code duplication - All loading logic is now in a single recursive function

  7. Uses named constants - Both MinSupportedFrameworkMajorVersion (3) and PrunePackageDataMinMajorVersion (10) are defined as constants for better maintainability

  8. Includes proper logging to help diagnose which framework version's data is being used

Usage Example

When building .NET 11.0 with a .NET 10.0 SDK, set this property to avoid NETSDK1226 errors:

<PropertyGroup>
  <LoadPrunePackageDataFromNearestFramework>true</LoadPrunePackageDataFromNearestFramework>
</PropertyGroup>

All changes have been verified to build successfully with no errors or security issues.

Original prompt

This section details on the original issue you should resolve

<issue_title>Better support for building against newer frameworks than SDK supports</issue_title>
<issue_description>At the end of every release we need to bootstrap a new TFM. This involves using the N-1 SDK to build the latest framework before we can have an SDK that natively supports that framework.

When doing so for 10->11 we hit the error:

C:\src\dotnet\runtime\.dotnet\sdk\10.0.100-rc.2.25502.107\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(66,5): error NETSDK1226: Prune Package data not found .NETCoreApp 11.0 Microsoft.NETCore.App.  To ignore this error, set the AllowMissingPrunePackageData to true.

We can hack around this, but it would be better if there was a knob that let us say either:

  1. Fallback to the nearest framework for pruning data.
  2. Use a specific framework for pruning data.</issue_description>

<agent_instructions>Update the GetPackagesToPrune task to add a parameter named LoadPrunePackageDataFromNearestFramework. When specified, the task should fall back to trying to load prune package data from previous frameworks if it isn't found for the current framework.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 2, 2025 21:43
…ToPrune task

Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Copilot AI changed the title [WIP] Add better support for building against newer frameworks Add LoadPrunePackageDataFromNearestFramework parameter for building against newer TFMs Dec 2, 2025
Copilot AI requested a review from dsplaisted December 2, 2025 21:55
Copilot finished work on behalf of dsplaisted December 2, 2025 21:55
Copy link
Member

@dsplaisted dsplaisted left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LoadPackagesToPruneFromNearestFramework method duplicates a lot of code that's already in LoadPackagesToPrune. Instead of this duplication, make a recursive function that tries to load the data. If it can't find the data and it's supposed to load from the nearest framework, then it should call itself with the previous framework version, recursing down to the minimum supported version.

Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 2, 2025

The LoadPackagesToPruneFromNearestFramework method duplicates a lot of code that's already in LoadPackagesToPrune. Instead of this duplication, make a recursive function that tries to load the data. ...

Refactored to use a recursive function TryLoadPackagesToPruneForVersion that eliminates the code duplication. The function tries to load prune package data from the three sources, and if unsuccessful with LoadPrunePackageDataFromNearestFramework enabled, it recursively calls itself with the previous framework version. (commit 272d2e9)

Copilot AI requested a review from dsplaisted December 2, 2025 22:44
Copilot finished work on behalf of dsplaisted December 2, 2025 22:44
Copy link
Member

@dsplaisted dsplaisted left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value for LoadPrunePackageDataFromNearestFramework should be included in the CacheKey instead of passed as a parameter to LoadPackagesToPrune. Make sure to also update the hashcode for the CacheKey.

Also, the recursion should also be able to cover the case where useFrameworkPackageData is false, so that it can fall back from a framework where that would be false to one where it would be true. That will mean moving more code from LoadPackagesToPrune into TraLoadPackagesToPruneForVersion.

…eFrameworkPackageData logic into TryLoadPackagesToPruneForVersion

Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 3, 2025

The value for LoadPrunePackageDataFromNearestFramework should be included in the CacheKey instead of passed as a parameter to LoadPackagesToPrune. Make sure to also update the hashcode for the CacheK...

Updated to include LoadPrunePackageDataFromNearestFramework in the CacheKey with proper hashcode calculation. Also moved the useFrameworkPackageData logic into TryLoadPackagesToPruneForVersion, allowing the recursion to fall back from .NET 10+ frameworks (which use prune package data) to .NET 9 and below frameworks (which use framework package data). (commit 6e76b8f)

Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Copilot AI requested a review from dsplaisted December 3, 2025 00:39
Copilot finished work on behalf of dsplaisted December 3, 2025 00:39
{
string fallbackVersion = $"{targetVersion.Major - 1}.0";
log.LogMessage($"LoadPrunePackageDataFromNearestFramework is enabled, trying to load from framework version {fallbackVersion}");
packages = TryLoadPackagesToPruneForVersion(log, targetFrameworkIdentifier, fallbackVersion, frameworkReference, targetingPackRoots, prunePackageDataRoot, loadPrunePackageDataFromNearestFramework);
Copy link
Member

@ericstj ericstj Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this to be recursive? That means someone can stack overflow if someone has this setting enabled and targets something like net5000.0? This also would be pretty expensive to fallback through each version 1-by-1... Find nearest might be better if you can determine which frameworks you have data for.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll get an error way before this target runs if you target a higher version of .NET than the SDK supports:

NETSDK1045: The current .NET SDK does not support targeting .NET 20.0. Either target .NET 10.0 or lower, or use a version of the .NET SDK that supports .NET 20.0. Download the .NET SDK from https://aka.ms/dotnet/download

Recursion seemed simpler to me in this case.

// If we can go to a lower version, recursively try it
if (targetVersion.Major > MinSupportedFrameworkMajorVersion)
{
string fallbackVersion = $"{targetVersion.Major - 1}.0";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we have frameworks with minor versions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's unlikely we'll ship minor versions again. I'm OK with this breaking or not working correctly if we eventually do create a minor version.

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.

Better support for building against newer frameworks than SDK supports

3 participants