Skip to content
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

.NET framework SDK projects without a RID are incorrectly passing RID specific assets to conflict resolution. #1510

Closed
ericstj opened this issue Aug 17, 2017 · 7 comments

Comments

@ericstj
Copy link
Member

ericstj commented Aug 17, 2017

  1. Create a .net standard 1.4 library.
  2. Create a .net core SDK class library (multi-targeting) and have net461 as one of the targets.
  3. Reference the .net standard 1.4 library from the multi-targeting class library.
  4. Build.

Expect: all netstandard facades appear in bin directory.
Actual: System.Security.Cryptography.Algorithms.dll is missing. Notice the following (among others) in the log:

2>    Encountered conflict between 'Runtime:C:\Users\ericstj\.nuget\packages\system.security.cryptography.algorithms\4.3.0\runtimes\osx\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll' and 'Runtime:C:\Users\ericstj\.nuget\packages\system.security.cryptography.algorithms\4.3.0\runtimes\unix\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll'.  Could not determine winner due to equal file and assembly versions.
2>    Encountered conflict between 'Runtime:C:\Users\ericstj\.nuget\packages\system.security.cryptography.algorithms\4.3.0\runtimes\osx\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll' and 'Runtime:C:\Users\ericstj\.nuget\packages\system.security.cryptography.algorithms\4.3.0\runtimes\win\lib\net461\System.Security.Cryptography.Algorithms.dll'.  Choosing 'Runtime:C:\Users\ericstj\.nuget\packages\system.security.cryptography.algorithms\4.3.0\runtimes\osx\lib\netstandard1.6\System.Security.Cryptography.Algorithms.dll' because AssemblyVersion '4.2.1.0' is greater than '4.1.0.0'.

Bug is here:

<ItemGroup>
<!-- We need to find all the files that will be loaded from deps for conflict resolution.
To do this, we look at the files that would be copied local when CopyLocalLockFileAssemblies is true.
However, if CopyLocalLockFileAssemblies is true, then we don't add these items, as they
will always be included in ReferenceCopyLocalPaths.
-->
<_LockFileAssemblies Include="@(AllCopyLocalItems->WithMetadataValue('Type', 'assembly'))"
Condition="'$(CopyLocalLockFileAssemblies)' != 'true'"
/>
<!-- Also include RuntimeTarget items, which aren't included in AllCopyLocalItems, but need to be considered
for conflict resolution -->
<_RuntimeTargetItems Include="@(_ActiveTFMFileDependencies->WithMetadataValue('FileGroup', 'RuntimeTarget'))" />
<__RuntimeTargetPublishItems Include="@(FileDefinitions)" Exclude="@(_RuntimeTargetItems)" />
<_RuntimeTargetPublishItems Include="@(FileDefinitions)" Exclude="@(__RuntimeTargetPublishItems)" />
<_LockFileAssemblies Include="@(_RuntimeTargetPublishItems->WithMetadataValue('Type', 'assembly')->'%(ResolvedPath)')">
<Private>false</Private>
<NuGetIsFrameworkReference>false</NuGetIsFrameworkReference>
<NuGetSourceType>Package</NuGetSourceType>
<NuGetPackageId>%(PackageName)</NuGetPackageId>
<NuGetPackageVersion>%(PackageVersion)</NuGetPackageVersion>
</_LockFileAssemblies>
</ItemGroup>

.NET Core is the only thing that understands RuntimeTarget items. I suspect that whole item should be conditioned on something (TargetFrameworkIdentifier?) that means "I should get RuntimeTarget items copied".

/cc @dsplaisted

@dsplaisted
Copy link
Member

dsplaisted commented Aug 30, 2017

.NET Core is the only thing that understands RuntimeTarget items

This may not be directly related to this issue, but if .NET Core is the only thing that understands RuntimeTarget items, why does the System.Security.Cryptography.Algorithms package have a runtimeTarget item for net461?

        "runtimeTargets": {
          "runtimes/osx/lib/netstandard1.6/System.Security.Cryptography.Algorithms.dll": {
            "assetType": "runtime",
            "rid": "osx"
          },
          "runtimes/unix/lib/netstandard1.6/System.Security.Cryptography.Algorithms.dll": {
            "assetType": "runtime",
            "rid": "unix"
          },
          "runtimes/win/lib/net461/System.Security.Cryptography.Algorithms.dll": {
            "assetType": "runtime",
            "rid": "win"
          }
        }

@ericstj
Copy link
Member Author

ericstj commented Aug 30, 2017

That's just how nuget lists RID specific assets when restoring without a RID.

The only framework that I am aware of actually uses those is .NETCore since it can do RID-selection at runtime. I suspect that the SDK already has this knowledge since it knows not to copy RID-specific assets (runtime target assets) for desktop. /cc @eerhardt

@eerhardt
Copy link
Member

We've had a few issues with "Desktop without a RID" scenarios. In project.json land, this wasn't really supported/implemented, as the CLI would infer a RID if you were building a Desktop project and didn't specify a RID. In the MSBuild based tools, if you are a Desktop EXE, we also infer a RID if one isn't specified.

Are we expecting the output directory of a Desktop library project to be runnable/executable? What happens if the Desktop library references a NuGet package with native assets in it? ex. LibUV. Would you expect:

  1. No native assets get copied.
  2. A single native asset get copied (somehow pick one?)
  3. All native assets get copied - in which case they are bound to conflict with each other, like in the libuv case.

@ericstj
Copy link
Member Author

ericstj commented Aug 30, 2017

When restoring without a RID on things other than .NETCoreApp the expectation is that no RID specific assets are copied. This is the behavior of packages.config, and project.json. If folks need native assets, take Microsoft.DiaSymReader.Native, they typically will deal with that via targets. I've also seen folks with targets that will error if a RID isn't specified.

@jaredpar
Copy link
Member

Moving the work around @dsplaisted gave me for this issue in a linked bug

  <Target Name="WorkaroundConflictResolution" AfterTargets="_ComputeActiveTFMFileDependencies"
          Condition="'$(PlatformTarget)' == 'AnyCPU' And '$(TargetFrameworkIdentifier)' == '.NETFramework'">
    <ItemGroup>
      <_ActiveTFMFileDependencies Remove="@(_ActiveTFMFileDependencies->WithMetadataValue('FileGroup', 'RuntimeTarget'))" />
    </ItemGroup>
  </Target>

Wanted to emphasize that this is a very painful bug. Even after having a viable work around I've still spent another full day tracking down all the places that it needs to be applied. Currently hitting problems trying to get the assets to deploy inside a VSIX.

Once customers hit this it's going to cause a lot of pain.

@dsplaisted
Copy link
Member

dsplaisted commented Aug 31, 2017 via email

@jaredpar
Copy link
Member

@dsplaisted

I had the impression that you just put the workaround in the common Roslyn targets that would apply to the whole repo. Does that not work

That fixed the majority of our issues. It didn't fix our VSIX projects though and it took me a bit of debugging today to narrow down how to fix that. For those I had to do the following:

  1. Apply this work around. Didn't initially because I try and keep work arounds to the minimal scope possible. There is one VSIX where we embed an EXE which itself needs the facade deployed. Hence this needs to apply to VSIX as well as EXE / unit tests.
  2. Change <RuntimeIdentifier> to explicitly target win7-x86
  3. Explicitly add a PackageReference to System.Security.Cryptography.Algorithms

This commit demos the change I needed to make: dotnet/roslyn@732d5f6

It's quite possible (2) wasn't entirely necessary. Changing that alone didn't fix the issue but the previous value was inaccurate.

Action (3) is definitely needed though. It's likely more a function of our targets / VSIX packaging logic than the logic in this work around. But our VSIX logic has existed for a while now mostly unchanged and I imagine when this bug is fixed it would continue to work as was previously defined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants