NuGet:两个带有目标文件的包会导致 DLL 被错误地复制 [英] NuGet: Two packages with targets files lead to incorrectly copied DLLs

查看:37
本文介绍了NuGet:两个带有目标文件的包会导致 DLL 被错误地复制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了两个包含本机库的 NuGet 包.第一个有两个子文件夹(amd64 和 x86),第二个包含构建目录下的 DLL flat.第一个包的 NativeLibraries 应该被复制到 OutputPath 的子文件夹中.第二个包中唯一的 DLL 应该被复制到 OutputPath 下.我使用以下 stackoverflow 条目作为创建包的指南:

如果是这样,第一个导入目标文件 flat.targets 文件与您的第一个 nuget 包的目标文件相同:

它将x86amd64 文件夹文件包含在output folder\x86output folder\amd64 文件夹中,正如我们所排除的那样.

但是,在pakckages.config下,由于两个target文件在同一个csproj文件中,所以它们可以互相访问(它们在同样CSProj),当msbuild在flat.targets文件之后读取faltt.targets文件时,你也没有改变NativeLibs> 第二个目标文件的项目,它本身有文件:

C:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\amd64\Dll1.dllC:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\amd64\Dll2.dllC:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\x86\Dll1.dllC:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\x86\Dll1.dll

读取flatt.targets文件时,它还包含C:\Users\xxx\source\repos\flat\packages\flatt.1.0.0\build\x86\Dll1.dll,

所以它在NativeLibs项下有五个文件.

然后执行%(FileName)%(Extension),第一个nuget包的dll会在第二个nuget包的节点下执行,输出到输出根文件夹.

由于Packages.config 导入目标文件的特殊性,它们是交错的.

你应该注意

PackageReference nuget管理格式下,导入目标文件存放在obj\xxx.csproj.nuget.g.targets文件下,如下:

 

由于内容不在csproj文件中以及xxx.csproj.nuget.g.targets文件的特殊性,分别读取每个 nuget 包中的目标文件.每个文件都是一个独立的生命周期,所以不会相互影响.这也是最新PackagesReference nuget 管理格式的优势之一.

抱歉一开始没有告诉你我使用的是packagesReference,我没有注意到packages.config.

所以如果您想通过正确的行为将它们分开,请尝试以下两种方法:

1)不要改变两个nuget包,在安装两个nuget包的主工程的packages.config文件上右键-->点击将packages.config迁移到PackageReference选项

之后,点击重建选项来获得它.

2) 修改 nuget 包-->将 NativeLibs 项的名称更改为第二个 nuget 包目标文件的另一个名称:

<项目组><NativeLibs1 Include="$(MSBuildThisFileDirectory)*.dll";/><None Include="@(NativeLibs1)"><Link>%(FileName)%(Extension)</Link><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></无></项目组></项目>

重新打包项目时,先卸载,删除C:\Users\xxx\.nuget\packages下的所有缓存文件.然后再次重新安装软件包.

I have created two NuGet packages that contain Native Libraries. The first one has two subfolders (amd64 and x86) the second one includes the DLL flat under the build directory. The NativeLibraries of the the first package are supposed to be copied into subfolders of the OutputPath. The only DLL in the second package should be copied flat under the OutputPath. I used the following stackoverflow entry as a guide for creating the package: https://stackoverflow.com/a/30316946/4496150

The first NuGet package folder structure looks like this (amd64 and x86 subfolder under build):

  • build
    • amd64
      • DLL1.dll
      • DLL2.dll
    • x86
      • DLL1.dll
      • DLL2.dll
    • packagename.targets

First targets file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)**\*.dll" />
    <None Include="@(NativeLibs)">
      <Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Please notice $(MSBuildThisFileDirectory)** as NativeLibs Include and %(RecursiveDir) as part of Link attribute.

The second NuGet package structure looks like this (no subfolders under build):

  • build
    • DLL1.dll
    • packagename.targets

Second targets file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)\*.dll" />
    <None Include="@(NativeLibs)">
      <Link>%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Please notice $(MSBuildThisFileDirectory) (without **) as NativeLibs Include and missing %(RecursiveDir) in Link attribute.

If you reference both packages, the DLLs from the first package are additionally copied flat into the output folder, which is not desired. I suspect this is because the second include step also reads the DLLs from the first package, but then does not use %(RecursiveDir).

A workaround is to also include in the second package both. and NativeLibs Include="$(MSBuildThisFileDirectory)***.dll" /> exactly as in the first package.

However, I would prefer to understand why the second package ensures that the DLLs from the first are copied flat.

If I read https://docs.microsoft.com/de-de/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2019 correctly, $(MSBuildThisFileDirectory) points to the folder in my NuGet cache where the targets file of the NuGet package is located. So actually everything would be correct. But still (probably) wrong DLLs are copied.

Edit

I added the following snippet in both targets files to get some output:

<Target Name="OutputPackage1NativeLibs" BeforeTargets="Build">
    <Message Text="Package1 %(NativeLibs.Identity)" Importance="high"/>
</Target>

For the seconds targets file I changed the target name to OutputPackage2NativeLibs and started the text Output with Packag2.

When I clean my NuGet Package Cache and rebuild the solution everything is fine. But after the third or forth rebuild operation the DLLs of the first package are copied flat under the Output path and I get the following output:

Package1 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\amd64\DLL1.dll
Package1 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\amd64\DLL2.dll
Package1 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\x86\DLL1.dll
Package1 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\x86\DLL2.dll
Package1 C:\Users\USERNAME\.nuget\packages\PACKAGENAME2\1.0.0.0\build\DLL1.dll

Package2 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\amd64\DLL1.dll
Package2 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\amd64\DLL2.dll
Package2 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\x86\DLL1.dll
Package2 C:\Users\USERNAME\.nuget\packages\PACKAGENAME1\1.2.3.4\build\x86\DLL2.dll
Package2 C:\Users\USERNAME\.nuget\packages\PACKAGENAME2\1.0.0.0\build\DLL1.dll

So NativeLibs are added from the other NuGet package apparently after the third or fourth rebuild.

解决方案

I think you are using Packages.config nuget package format with non-sdk net framework projects. If so, that could be explained.

For packages.config nuget management format, it imports the target files directly under csproj file. In my side, I created two nuget packages called flat 1.0.0 and faltt 1.0.0 nuget packages.

You can check my csproj file:

If so, the first import targets file flat.targets file is the same as your first nuget package's targets file:

It includes the x86 and amd64 folder files into output folder\x86 and output folder\amd64 folder, that is right as we excepted.

However, under pakckages.config, since the two targets file are in the same csproj file, they can access each other(they have the same life cycle in the same CSProj), when msbuild reads faltt.targets file after flat.targets file, also you did not change NativeLibs item for the second targets file, itself has the file:

C:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\amd64\Dll1.dll
C:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\amd64\Dll2.dll
C:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\x86\Dll1.dll
C:\Users\xxx\source\repos\flat\packages\flat.1.0.0\build\x86\Dll1.dll

When reads the flatt.targets file, it also includes C:\Users\xxx\source\repos\flat\packages\flatt.1.0.0\build\x86\Dll1.dll,

So it has five files under NativeLibs item.

And then it executes <Link>%(FileName)%(Extension)</Link>, the first nuget package's dlls will be executed under the second nuget packages's node, output to the output root folder.

Because of the special nature of Packages.config import targets files, they are interlaced.

You should note that

Under PackageReference nuget management format, the import targets files are stored under obj\xxx.csproj.nuget.g.targets file, like this:

 <ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
    <Import Project="$(NuGetPackageRoot)flatt\1.0.0\build\flatt.targets" Condition="Exists('$(NuGetPackageRoot)flatt\1.0.0\build\flatt.targets')" />
    <Import Project="$(NuGetPackageRoot)flat\1.0.0\build\flat.targets" Condition="Exists('$(NuGetPackageRoot)flat\1.0.0\build\flat.targets')" />
  </ImportGroup>

Since the content is not in csproj file and the particularity of the file xxx.csproj.nuget.g.targets, it will read the targets files in each nuget package separately. Each file is a separate life cycle, so it does not Will affect each other. This is also one of the advantages of the latest PackagesReference nuget management format.

Sorry for not telling you at the beginning that I was using packagesReference and I didn't notice packages.config.

So if you want to get the right behavior to separate them, try the two approaches:

1) do not change the two nuget packages, right-click on the packages.config file of the main project which installs the two nuget packages-->click Migrate packages.config to PackageReference option

After that, click Rebuild option to get that.

2) modify the nuget packages--> change the NativeLibs item's name to another for the second nuget package targets file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs1 Include="$(MSBuildThisFileDirectory)*.dll" />
    <None Include="@(NativeLibs1)">
      <Link>%(FileName)%(Extension)</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

When re-pack your project, uninstall them first, delete all cache files under C:\Users\xxx\.nuget\packages. And then re-install the packages again.

这篇关于NuGet:两个带有目标文件的包会导致 DLL 被错误地复制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆