-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add LoadPrunePackageDataFromNearestFramework parameter for building against newer TFMs #51978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ToPrune task Co-authored-by: dsplaisted <[email protected]>
Co-authored-by: dsplaisted <[email protected]>
dsplaisted
left a comment
There was a problem hiding this 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 <[email protected]>
Refactored to use a recursive function |
dsplaisted
left a comment
There was a problem hiding this 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 <[email protected]>
Updated to include |
Co-authored-by: dsplaisted <[email protected]>
| { | ||
| 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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but I can also disable that warning. I'm not sure why someone would, but I try to avoid recursive algorithms where recursion is controlled by user input.
Seems to me like making it iterative wouldn't be all that hard but it's your call. Make sure to document that fallback logic of this is different than that of NuGet.
| // If we can go to a lower version, recursively try it | ||
| if (targetVersion.Major > MinSupportedFrameworkMajorVersion) | ||
| { | ||
| string fallbackVersion = $"{targetVersion.Major - 1}.0"; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might consider at a minimum just decrementing minor if it's non-zero first. That's a small change to handle this possibility. It might also address the 2.2 case Rich mentioned offline.
dsplaisted
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change TryLoadPackagesToPruneForVersion to use a loop instead of recursion.
Also, instead of always decrementing the major version, if the minor version is non-zero, then decrement it instead for the next iteration.
…ecursion and handle minor versions Co-authored-by: dsplaisted <[email protected]>
Changed |
|
This looks ready for review. I don't think there's a good way to add automated test coverage of this, so later on I will try to do some manual testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for building projects against newer target frameworks than the SDK natively supports by introducing a LoadPrunePackageDataFromNearestFramework parameter. This addresses the bootstrapping problem where an N-1 SDK is used to build the latest framework version (e.g., using .NET 10 SDK to build .NET 11).
Key Changes:
- Adds a new MSBuild parameter
LoadPrunePackageDataFromNearestFramework(defaults tofalsefor backward compatibility) that enables fallback to previous framework versions when prune package data isn't found - Refactors package data loading into a single iterative method that handles version fallback, preventing potential stack overflow issues
- Includes the new parameter in the cache key to ensure correct caching behavior
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets |
Adds the new LoadPrunePackageDataFromNearestFramework MSBuild property with a default value of false and passes it to the GetPackagesToPrune task |
src/Tasks/Microsoft.NET.Build.Tasks/GetPackagesToPrune.cs |
Implements the new parameter, adds it to the cache key, introduces two constants for framework version thresholds, and refactors loading logic into an iterative TryLoadPackagesToPruneForVersion method that handles fallback to previous framework versions |
| [Required] | ||
| public bool AllowMissingPrunePackageData { get; set; } | ||
|
|
||
| public bool LoadPrunePackageDataFromNearestFramework { get; set; } |
Copilot
AI
Dec 4, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR introduces a new feature (LoadPrunePackageDataFromNearestFramework parameter) that changes behavior of the package pruning system, but no tests have been added. According to the repository's coding guidelines, large changes should always include test changes.
Consider adding integration tests that verify:
- The new parameter works correctly when enabled (e.g., building .NET 11 with .NET 10 SDK succeeds)
- The parameter is disabled by default (backward compatibility)
- The fallback logic correctly tries previous framework versions
- The parameter is included in the cache key (different parameter values produce different results)
Example test location: test/Microsoft.NET.Build.Tests/ (similar to existing tests in GivenFrameworkReferences.cs or GivenThatWeWantToResolveConflicts.cs)
Implementation Plan
LoadPrunePackageDataFromNearestFrameworkparameter toGetPackagesToPrunetaskLoadPackagesToPrunemethod to accept and use the new parameterSummary
This PR successfully implements the
LoadPrunePackageDataFromNearestFrameworkparameter for theGetPackagesToPrunetask. The implementation:Adds a new boolean parameter
LoadPrunePackageDataFromNearestFrameworkto control fallback behavior (defaults tofalsefor backward compatibility)Includes the parameter in CacheKey - The value is now part of the cache key to ensure different parameter values produce different cached results
Uses an iterative approach -
TryLoadPackagesToPruneForVersionuses a while loop to search for prune package data from previous framework versions when the current version's data is not found. This prevents potential stack overflow issues with user-controlled input.Handles minor versions - If a framework has a non-zero minor version (e.g., 2.2), the fallback logic will decrement the minor version first (2.2 → 2.1 → 2.0) before decrementing the major version (2.0 → 1.0). This properly handles cases like .NET Core 2.2.
Handles framework version transitions - The iterative function includes the
useFrameworkPackageDatalogic, allowing it to fall back from .NET 10+ (which uses prune package data) to .NET 9 and below (which uses framework package data)Tries multiple data sources in order of preference:
Eliminates code duplication - All loading logic is now in a single iterative function
Uses named constants - Both
MinSupportedFrameworkMajorVersion(3) andPrunePackageDataMinMajorVersion(10) are defined as constants for better maintainabilityIncludes 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:
All changes have been verified to build successfully with no errors or security issues.
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.