-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Remove requirement for specifying a RID in desktop exe projects #847
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
Conversation
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 looks good. Congrats on figuring out a reasonable way of improving the user experience here.
|
||
#if USE_NATIVE_CODE | ||
[DllImport("libuv", CallingConvention = CallingConvention.Cdecl)] | ||
static extern int uv_loop_size(); |
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 seems like the test might eventually break if the Libuv and Kestrel packages get updated to support AnyCPU .NET Framework deployments by deploying both x86 and x64 versions of the native library and Kestrel dynamically chooses which one to load.
I'm not suggesting you change this now, just pointing it out.
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.
That would only happen if my libuv package ref was upgraded, which is unexpected and I'd be happy to have tests fail in that case.
|
||
2. Building an x86 or x64 NETFramework application on and for | ||
Windows with native NuGet dependencies that do not require | ||
greater thanwin7. |
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.
Missing space: thanwin7
@@ -60,9 +114,19 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
<OutputPath>$(OutputPath)$(RuntimeIdentifier)\</OutputPath> | |||
</PropertyGroup> | |||
|
|||
<Target Name="_CheckRuntimeIdentifier" BeforeTargets="_CheckForInvalidConfigurationAndPlatform"> | |||
<NetSdkError Condition="'$(RuntimeIdentifier)' == '' and '$(TargetFrameworkIdentifier)' == '.NETFramework' and '$(OutputType)' == 'Exe'" | |||
ResourceName="RuntimeIdentifierMustBeSetForNETFramework" /> |
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.
Should we remove this resource (RuntimeIdentifierMustBeSetForNETFramework
)? Or is that even something we can do?
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.
Removed.
Switch our default .NETFramework CPU architecture choice back to AnyCPU before | ||
compiling the exe if no copy-local native dependencies were resolved from NuGet | ||
--> | ||
<Target Name="AdjustDefaultPlatformTargetForNetFrameworkExeWithNoNativeCopyLocalItems" |
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.
How likely is it that there could be something else that consumes the PlatformTarget
property between when we set it to x86 or x64 based on the defaulted RuntimeIdentifier and when we set it back to AnyCPU because we didn't resolve any native assets?
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.
Hmm, I'm reviewing the uses of PlatformTarget in msbuild /pp output. There's quite a bit more than I'd hoped.
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 moved it to run soon after the assets are resolved.
|
||
static ProcessorArchitecture GetProcessorArchitecture() | ||
{ | ||
return AssemblyName.GetAssemblyName(Assembly.GetExecutingAssembly().Location).ProcessorArchitecture; |
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'd suggest typeof(Program).Assembly.Location
. I don't know that it matters at all, but Assembly.GetExecutingAssembly()
is one of the methods that we originally removed from .NET Core because it doesn't play well with optimizations we might want to do (inlining across assembly boundaries).
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.
Naming suggestion: The name GetProcessorArchitecture
makes me think it will return the architecture of the physical CPU or the OS. Something like GetCurrentAssemblyProcessorArchitecture
would be clearer to me, if more verbose.
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'll make the change to avoid any question, but Assembly.GetExecutingAssembly() doesn't suffer from these problems intrinsically. Assembly.GetCallingAssembly is the evil one. GetExecutingAssembly was guilty only by association and that we never bothered to make it intrinsic with identical code gen to typeof(CurrentType).Assembly.Location.
@mlorbetske @vijayrkn Once this is merged, I believe you should be able to remove the @piotrpMSFT @livarcocc Same thing for |
|
Thanks for the heads up @nguerrera. I have filled https://github.com/dotnet/cli/issues/5668 to track this on the CLI side. |
@MattGertz for approval |
@MattGertz @natidea @srivatsn Approved to merge or pending ship room? |
Approved at shiproom. However @rrelyea wanted to understand if the RID that we infer is similar to what's done in NuGet.targets. |
@nguerrera this exists in the build task: https://github.com/NuGet/NuGet.BuildTasks/blob/dev/src/Microsoft.NuGet.Build.Tasks/Microsoft.NuGet.targets#L94-L96 NuGet.targets/restore does not infer RIDs anymore like it did in preview2. It only reads the RuntimeIdentifier and RuntimeIdentifiers properties. |
Hold on merging this. |
OK. The default RIDs (plural) there are not win7+ whereas we pick win7+ for the implicit RID here. This is a pragmatic choice to make popular packages like libuv work on F5. Ultimately, the design would be to pick as inclusive as possible for current OS, but that is tracked by #840 There is no bad interaction between those and this: restore will just use our RID plus all of the RIDs there and produce an assets file with a superset of what this change needs. |
(But still making adjustments based on other issues.) |
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.
Waiting for test
@natidea @srivatsn @dsplaisted I've got all the changes discussed made and test coverage added to handle it. 411f959 is unfortunate workaround for case where the net4x app is one target of many. In that case, nuget restore doesn't see the inferred RID of inner build. The fix is a hammer to include win7-x86 and win7-x64 RIDs (plural) in all multi-targeting builds on Windows. |
var ns = project.Root.Name.Namespace; | ||
var propertyGroup = project.Root.Elements(ns + "PropertyGroup").First(); | ||
propertyGroup.Add(new XElement(ns + "RuntimeIdentifier", rid)); | ||
propertyGroup.Add(new XElement(ns + "AppendRuntimeIdentifierToOutputPath", useAppendOption.ToString())); |
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.
Should we be testing the case where AppendRuntimeIdentifierToOutputPath
is not specified in the project, as that will be the common case?
@@ -122,7 +122,7 @@ Copyright (c) .NET Foundation. All rights reserved. | |||
compiling the exe if no copy-local native dependencies were resolved from NuGet | |||
--> | |||
<Target Name="AdjustDefaultPlatformTargetForNetFrameworkExeWithNoNativeCopyLocalItems" | |||
DependsOnTargets="ResolvePackageDependenciesForBuild" | |||
AfterTargets="ResolvePackageDependenciesForBuild" |
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.
Can you explain this change? I haven't entirely grokked the difference between DependsOnTargets and AfterTargets, but I think this means that this target could run before ResolvePackageDependenciesForBuild if something else depended on this target.
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 am trying to make sure that this is done as soon as we know the right PlatformTarget. Somebody could indeed force it to be sooner.
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 not really concerned about someone trying to run this target themselves at some other time and I don't want to reset testing for this.
build, we may implicitly use one of these RIDs and so we must ensure that restore | ||
includes them. | ||
--> | ||
<PropertyGroup Condition="'$(RuntimeIdentifiers)' == '' and '$(OS)' == 'Windows_NT'"> |
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.
Could we check to see whether RuntimeIdentifiers
contains a net*
target framework? Even just checking if the string contains net
would allow us to avoid this in most cases where we don't need it.
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.
It will contain 'net' in most cases: netstandard netcoreapp. I don't want to add regex or other parsing complexity here.
Is this ready to merge now? |
Validating Daniel's question about change to AfterTargets and saw that there's an issue with the final change for the multi-targetng case. It won't kick in in full msbuild/VS because of the other issue where Microsoft.Nuget.targets is imported. The satellite test that's covering that is disabled on full msbuild right now. Working on it. |
Jenkins is down, but validated locally that d1c2fd4 closes desktop msbuild test gap, and 5046d92 turns it green. @dsplaisted, @srivatsn please review those changes. |
@dotnet-bot test this please |
5046d92
to
cc62950
Compare
cc62950
to
efbcaca
Compare
@dsplaisted @natidea @srivatsn I've now fixed the mulitargeting issue in a much more general way that:
Please review efbcaca, which does this and is squashed delta since sign-offs. I've also asked @emgarten to review. I am also going to add some unit tests to check GetAllRuntimeIdentifiers directly and not just in the end-to-end scenario this PR sets out to address. |
</ItemGroup> | ||
|
||
<MSBuild Projects="$(MSBuildProjectFile)" | ||
Condition="'$(TargetFrameworks)' != ''" |
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 condition doesn't seem to be strictly necessary, as this file should only be imported when TargetFrameworks
is defined, right?
buildCommand | ||
.Execute() | ||
.Should() | ||
.Pass(); |
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.
Should this be checking that the output is built using the correct RID, as is the case with It_handles_native_depdencies_and_platform_target?
@emgarten approved here #871 (comment) He noted offline that rids are technically case sensitive, so I'll switch to DistinctWithCase(). I am still adding GetAllRuntimeIdentifiers unit tests and I'll add the coverage @dsplaisted requested above. I have to run to an appointment so I'll merge this later tonight once the extra tests are in. |
Abandoning DistinctWithCase because MSBuild is already deduping case elsewhere. I think we have bigger problems if real RIDs ever differ only by case (e.g. path conflicts, endless confusion), so I think we can ignore it. |
2effe62
to
497b67c
Compare
…805.9 (dotnet#847) - Microsoft.DotNet.Arcade.Sdk - 1.0.0-beta.19405.9
Customer scenario
The approach taken is scoped to address these two common cases:
Both of the above will happen automatically and F5 successfully without any mention of RuntimeIdentifier or PlatformTarget in the project. Other scenarios will still require adjusting the RID and PlatformTarget to resolve the native dependencies correctly and stamp the resulting binary correctly.
Follow-ups to improve the experience outside these cases:
Bugs this fixes:
Fix #396 and its myriad of duplicates/consequences.
Workarounds, if any
Specify dummy runtime identifier for AnyCPU app, and explicitly let PlatformTarget to AnyCPU.
Always pick a RID whenever taking native nuget dependencies from a desktop app.
Risk
Low. We address two common cases with new defaults. Specifying PlatformTarget and RuntimeIdentifier explicitly shuts off these defaults and gives the user the same control they had before. We simply make it so that this control needn't be used for the most common cases.
Performance impact
Minimal. A few extra checks are needed in msbuild evaluation.
Is this a regression from a previous update?
No.
Root cause analysis
N/A since we are amending a deliberate design decision in response to significant customer and partner feedback.
How was the bug found
Customer and partner reported.
@srivatsn @dsplaisted @eerhardt @dotnet/project-system