dotnet / sdk

Core functionality needed to create .NET Core projects, that is shared between Visual Studio and CLI
https://dot.net/core
MIT License
2.71k stars 1.06k forks source link

When TargetFramework=net5.0-windows, dotnet pack uses net5.0-windows7.0 instead #14553

Open augustoproiete opened 3 years ago

augustoproiete commented 3 years ago

I can't tell if this is by design or if it's a bug, and I couldn't find any documentation via search engines that would explain this. I also read the Target Framework Names in .NET 5 design spec and didn't see any mention of this behavior there.

When running dotnet build on a .NET 5 WPF app or .NET 5 Windows Forms App with a TargetFramework set to net5.0-windows, all artifacts are correctly written to bin\{Configuration}\net5.0-windows as expected.

However, when running dotnet pack on the same project, the artifacts in the .nupkg are stored in /lib/net5.0-windows7.0 instead of /lib/net5.0-windows which is what one would expect.

image

To reproduce:

mkdir repro
cd repro
dotnet new wpf --framework net5.0
dotnet pack repro.csproj

repro.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

</Project>

Expectation

The expectation is that dotnet pack would honor exactly what has been defined in the .csproj and exactly what is written to the disk... Which leads me to believe that this could be a bug in dotnet pack.

If this is by design, then I'd like to put in a feature request to throw an error that prevents devs from using net5.0-windows in WPF & WinForms projects and force developers to be specific with net5.0-windows7.0 or net5.0-windows10.0.17763.0 instead, because otherwise it is very confusing to have net5.0-windows in the project, net5.0-windows on disk in the build output, but then a different folder in the NuGet package.


C:\Users\augustoproiete>dotnet --info
.NET SDK (reflecting any global.json):
 Version:   5.0.100
 Commit:    5044b93829

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.18363
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\5.0.100\

Host (useful for support):
  Version: 5.0.0
  Commit:  cf258a14b7

.NET SDKs installed:
  2.1.801 [C:\Program Files\dotnet\sdk]
  2.1.802 [C:\Program Files\dotnet\sdk]
  2.2.401 [C:\Program Files\dotnet\sdk]
  3.1.101 [C:\Program Files\dotnet\sdk]
  3.1.102 [C:\Program Files\dotnet\sdk]
  3.1.302 [C:\Program Files\dotnet\sdk]
  3.1.404 [C:\Program Files\dotnet\sdk]
  5.0.100 [C:\Program Files\dotnet\sdk]
Skyppid commented 3 years ago

I had the same phenomenon and when I tried to install these packages in a .NET 5 app, it told me that "net5.0" and "net.5.0-windows7.0" aren't compatible. All my projects where "net5.0-windows" actually, though.

mrbiglari commented 3 years ago

I had the same issue as @Skyppid , in my case it was because I had a project with .net5.0 referencing .net5.0-windows projects.

I got it resolved by just changing the .net5.0 to .net5.0-windows as well.

augustoproiete commented 3 years ago

Confirmed by @zkat on Twitter that this is by design.

image

augustoproiete commented 3 years ago

I'll leave this issue open as a suggestion to add some consistency here between the build output, and the NuGet packaged library, either on the .NET SDK side or on the NuGet side.

When developing libraries that should be consumed by Windows Desktop apps, and given that I defined net5.0-windows in my project, I'd expect NuGet to also store the files under net5.0-windows, but it doesn't:

image

However, if set the TargetFramework in my project to net5.0-windows7.0, then my build output now uses net5.0-windows7.0 and now it matches the NuGet package folder structure.

image


One alternative could be modifying the logic of the warning NETSDK1136 that requires net5.0-windows when the project has <UseWPF>true</UseWPF> or <UseWindowsForms>true</UseWindowsForms>, to require net5.0-windows7.0 instead, when the user specified net5.0-windows as the TFM.

Error NETSDK1136 The target platform must be set to Windows (usually by including '-windows' in the TargetFramework property) when using Windows Forms or WPF, or referencing projects or packages that do so.

Another alternative could be changing NuGet to use net5.0-windows instead of net5.0-windows7.0 and have it understand that it's the same thing.

image

dsplaisted commented 3 years ago

As mentioned, this is by design.

@zkat @nkolev92 is there an explanation to link to about how / why this works?

zkat commented 3 years ago

I looked through https://github.com/dotnet/designs/blob/main/accepted/2020/net5/net5.md but didn't find anywhere where this was actually documented. I don't think we have it documented anywhere but in our heads right now. Did you have anything, @terrajobst ?

nkolev92 commented 3 years ago

The pack behavior described in spec is carries the gist of platform versions are required in packages, but doesn't use the terminology that was implemented.

See

TFM has an OS but no OS version. If the user omits the OS version number from the project's <TargetFramework> property, all usages of the TFM should not contain an OS version number, including the project's output directory, the lib folder in the NuGet package, and other corresponding entries in the .nuspec. However, the effective OS version will be recorded in the .nuspec's <platform> element that corresponds to the TFM.

I think this is ok, because the general spec can't reasonable call out all technical details.

I think it'd be nice to have specific docs describing this behavior.

tripleacoder commented 3 years ago

I had the same phenomenon and when I tried to install these packages in a .NET 5 app, it told me that "net5.0" and "net.5.0-windows7.0" aren't compatible. All my projects where "net5.0-windows" actually, though.

I get the same error, specifically:

NU1202: Package MyControls is not compatible with net50-windows (.NETFramework,Version=v5.0,Profile=windows) / win-x64.

Package MyControls supports:

net50-windows7.0 (.NETFramework,Version=v5.0,Profile=windows7.0) netcoreapp3.1 (.NETCoreApp,Version=v3.1)

Both projects use the TFM "net50-windows".

If I then go in under .nuget/packages and /lib on the build server and copy the folder "net50-windows7.0" to a new folder "net50-windows", the Nuget error goes away.

But then I get this compile error:

errorCS0103: The name 'Windows' does not exist in the current context

nkolev92 commented 3 years ago

I get the same error, specifically:

@tripleacoder

What's your SDK version? If you look at your error more closely, it says, net50-windows7.0 is .NET Framework, which is how SDKs older than 5.0.100 would interpret it.

tripleacoder commented 3 years ago

What's your SDK version? If you look at your error more closely, it says, net50-windows7.0 is .NET Framework, which is how SDKs older than 5.0.100 would interpret it.

I am not sure. Does the MSBuild log show the SDK version?

sam-wheat commented 3 years ago

Please take a look at this issue I raised on Stackoverflow and let me know if it is related. Suggestions on how I might fix it will be greatly appreciated.

Menelion commented 5 months ago

It's .NET 8 and the issue persists. I have:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <!-- NOTE THIS! -->
        <TargetFramework>net8.0-windows</TargetFramework>
        <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
        <Platforms>x64</Platforms>
        <!-- further info not relevant -->
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)' == 'Release'">
        <DebugSymbols>false</DebugSymbols>
        <Optimize>true</Optimize>
    </PropertyGroup>

    <ItemGroup>
        <None Update="LibLouis\**">
            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
            <Pack>true</Pack>
            <Visible>false</Visible>
            <!-- NOTE THIS! -->
            <PackagePath>lib/$(TargetFramework)</PackagePath>
        </None>
        <None Include="../../README.md" Pack="true" Visible="false" PackagePath="/" />
    </ItemGroup>
</Project>

So, In the <TargetFramework> I have net8.0-windows, but when packing, NuGet resolves the $(TargetFramework) to net8.0-windows7.0.
What is the correct way of handling this issue please? Thanks! // CC @nkolev92

nkolev92 commented 4 months ago

@Menelion

That's expected.

net8.0-windows is just sugar around specifying the exact platform version. The platform version is necessary.

I think this issue is really on a documentation issue at this point: https://github.com/dotnet/sdk/issues/14553#issuecomment-737530880.

@dsplaisted should we move this to dotnet/docs?

dsplaisted commented 4 months ago

Yes, this is the way it is supposed to work and it would be good to have that documented, if it isn't already.

As for this:

<None Update="LibLouis\**">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <Pack>true</Pack>
    <Visible>false</Visible>
    <!-- NOTE THIS! -->
    <PackagePath>lib/$(TargetFramework)</PackagePath>
</None>

The PackagePath there won't apply to any output of the project, as the ItemGroup is evaluated before the project is built and those files are written. There may be other ways to customize the package paths of build outputs.