-
Notifications
You must be signed in to change notification settings - Fork 694
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
Restore: Prefer TargetFramework
over TargetFrameworks
when it is specified as a global property.
#4587
Conversation
@rolfbjarne and @dsplaisted - please take a look. I've made NuGet prefer the global TargetFramework property when set. |
test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs
Outdated
Show resolved
Hide resolved
test/NuGet.Core.FuncTests/Dotnet.Integration.Test/DotnetRestoreTests.cs
Outdated
Show resolved
Hide resolved
Thanks for the review @jonathanpeppers and @rolfbjarne Addressed your feedback. |
@rainersigwald Is there a better way to check whether a property is a global property than to do a separate <PropertyGroup>
<_TargetFrameworkBackup>($TargetFramework)</TargetFrameworkBackup>
<TargetFramework>FakeOverriddenValue</TargetFramework>
<TargetFrameworkIsGlobal Condition="'$(TargetFramework)' == '$(TargetFrameworkBackup)'">true</TargetFrameworkIsGlobal>
<TargetFramework>$(_TargetFrameworkBackup)</TargetFramework>
</PropertyGroup> |
There's now (since 16.5) an API that will allow doing it inside a task: dotnet/msbuild#4939. @nkolev92 would that let you do this inside the NuGet tasks themselves?
This does work in simple evaluation, but beware: if you put the same property settings inside a target, it does not work. |
That API could work. I think we use it in static graph scenarios already. Right now we only use that to decide which frameworks to run inner builds for. I'd probably have to add an extra task to just get the effective TargetFramework(s). |
<MSBuild | ||
BuildInParallel="$(RestoreBuildInParallel)" | ||
Condition=" '$(TargetFrameworks)' != '' " | ||
Projects="$(MSBuildThisFileFullPath)" |
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 would put some comments in here that you're "building" NuGet.targets
just to detect if a global property is set. More explanation of how this target works would be very helpful.
|
||
// Act | ||
var additionalArgs = useStaticGraphEvaluation ? "/p:RestoreUseStaticGraphEvaluation=true" : string.Empty; | ||
var result = _msbuildFixture.RunDotnet(pathContext.SolutionRoot, args: $"restore a.csproj {additionalArgs} /p:TargetFramework=\"net5.0\"", ignoreExitCode: true); |
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 result of this restore will only work for one framework and subsequent builds without a restore would fail right? Is it not possible to just restore a whole project regardless of target framework(s) and just let the build be scoped? We can remove global properties when generating the ProjectSpec items
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.
Yeah, it'd only restore/build for that specific framework.
When a RID is passed, we simply can't know whether we'd need to include for all or only a specific framework, so we only restore for that framework.
2b04ad9
to
6bf125a
Compare
Ready for another look @rolfbjarne @jonathanpeppers @dsplaisted @NuGet/nuget-client |
93ae383
to
8593454
Compare
IReadOnlyDictionary<string, string> msBuildGlobalProperties = null; | ||
|
||
// MSBuild 16.5 added a new interface, IBuildEngine6, which has a GetGlobalProperties() method. However, we compile against | ||
// Microsoft.Build.Framework version 4.0 when targeting .NET Framework, so reflection is required since type checking |
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.
Is there a reason we're building with such an old version of Microsoft.Build.Framework? Does nuget.exe even work without a recent-ish msbuild.exe? Or is it to avoid ilmerging Microsoft.Build.Framework.dll into nuget.exe, since I guess version 4.0 is in the GAC?
IReadOnlyDictionary<string, string> msBuildGlobalProperties = null; | ||
|
||
// MSBuild 16.5 added a new interface, IBuildEngine6, which has a GetGlobalProperties() method. However, we compile against | ||
// Microsoft.Build.Framework version 4.0 when targeting .NET Framework, so reflection is required since type checking |
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.
Is there a reason we're building with such an old version of Microsoft.Build.Framework? Does nuget.exe even work without a recent-ish msbuild.exe? Or is it to avoid ilmerging Microsoft.Build.Framework.dll into nuget.exe, since I guess version 4.0 is in the GAC?
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.
NuGet.exe uses whichever version of msbuild is available on their machine.
We don't/won't merge msbuild because it is used to discover imports and all that.
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.
actually, I misunderstood your question.
Not 100% sure if we can update. I can look into it, but we're doing this in a bunch of different places so I just largely followed that logic.
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.
Yeah, it might be reasonable to rebaseline, since I suspect you don't support running modern nuget.exe against dev11. But I don't think it's urgent.
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 don't support running modern nuget.exe against dev11
NuGet.exe restore help unfortunately lists a lot of msbuild versions.
We don't really explicitly talk about what's supported vs what's not.
It's a ymmv type of thing.
8593454
to
587dd8b
Compare
@NuGet/nuget-client Hoping to get some reviews here so I can merge? :) |
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'm curious if there's a measurable performance degradation with this change? The PR adds a new target, which calls a C# task. But MSBuild is an interpreted scripting language, so calling targets is a lot more expensive than calling methods in a JITed language, and the task uses reflection.
I hope it's too small to be measurable, but we seem to be concerned about the pdb PR's impact.
It registers as 1ms only. #4587 (comment) Note that this is only called on the commandline and not in VS, so the concerns are lesser. |
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.
There was no CI build for this change so I kicked one off
Bug
Fixes: NuGet/Home#11653
Regression? Last working version:
Description
NuGet/Home#11653 contains details about the scenario at hand, but the gist is that:
does not work because nuget prefers TargetFrameworks over TargetFramework, so it essentially "tries" to do a restore for net6.0-android + ios-arm64 which obviously isn't something that works.
This change allows NuGet to detect the user intent in the scenarios like the above, and only restore for the framework passed on the commandline.
The change boils down to NuGet preferring the
TargetFramework
when it is specified on the commandline, as a global property.While working on this I discovered NuGet/Home#11761, which basically means static graph can't support the equivalent at this point.
Given that this change requires multiple teams to validate it's good enough, I've added a means to disable it in case something does go really wrong while we're attempting that validation.
_DisableNuGetRestoreTargetFrameworksOverride
.PR Checklist
PR has a meaningful title
PR has a linked issue.
Described changes
Tests
Documentation