在NuGet包中包含非托管的DLL文件,使用csproj

8
我正在开发一个依赖于非托管DLL的.NET Core 2.1库。我希望在NuGet包中也包含这个非托管DLL。但问题是,如果我尝试在.csproj文件中指定所有信息,dotnet build进程会抛出以下警告:
warning NU5100: The assembly 'content\lib\subdir\somedll.dll' is not 
    inside the 'lib' folder and hence it won't be added as a reference 
    when the package is installed into a project. Move it into the 
    'lib' folder if it needs to be referenced.

我知道可以通过编写.nuspec文件来嵌入未管理的DLL(实际上,我已经这样做了)。但是,最新的.csproj文件格式似乎不需要编写这样的文件。

问题: 我该如何使用.csproj文件将未管理的DLL嵌入NuGet包中?

  • .csproj文件中指定<ItemGroup><None>似乎会将文件包含在输出目录中,但它们不会进入NuGet包。
  • .csproj文件中指定<ItemGroup><Content>将它们添加到NuGet包中,但是放在Content目录而不是Lib目录中。
如果我必须同时拥有一个.csproj文件和一个.nuspec文件,最佳实践是将元数据放在哪里?在.csproj文件中?在.nuspec文件中?维护和同步两个文件?是否有工具链可以为我完成这项工作?
我正在使用Visual Studio Code V1.24和.NET Core/dotnet V2.1。
2个回答

16

您需要在元素上指定显式的包路径元数据,以便将dll/so/dylib文件放置在软件包的正确位置,从而被识别为特定于运行时的本地DLL:

<ItemGroup>
  <None Include="unmanaged.dll" Pack="true" PackagePath="runtimes\win-x64\native" />
</ItemGroup>

1
这正是我一直在寻找的。我已经成功摆脱了.nuspec文件,现在只需要使用一次dotnet build命令就可以生成构建和NuGet包。 - Steve Kalemkiewicz
@martin-ullrich 我尝试了这个精确的代码片段,并成功打包了我想要的dll。https://i.imgur.com/SiF3sZU.png(在截图中,我将它们放在托管.dll相同的文件夹中,实际上会自动提取和使用)然而,无论是安装NuGet包还是编译使用NuGet包的程序,都没有提取这些文件。`runtimes\win-x64\native`仍然为空。我做错了什么? - FrostKiwi
没事了,我想通了^^ 在另一个回答中添加涉及的细节。 - FrostKiwi

0

为了补充@martin-ullrich提供的答案,所提供的示例对我的用例来说是不完整的。我需要在安装NuGet包时自动提取未管理的.dlls。这需要设置PackageCopyToOutput="true"。关于这种类型的包含还有一些更恶心的细节,我在这里记录了下来:https://github.com/Ruslan-B/FFmpeg.AutoGen/pull/240

将ffmpeg *.dlls打包到nuget包中以进行自动提取

您可以将运行代码所需的ffmpeg .dll文件打包到NuGet包中。当用户安装您的NuGet包时,ffmpeg .dll文件将自动提取到二进制/程序集目录中,无需用户手动粘贴。这为小型占用空间、项目特定的ffmpeg库打开了大门,例如没有不必要的10多MB网络代码等附加内容。由于ffmpeg .dll文件不是托管的C#代码,因此在将库构建为NuGet包之后,需要手动编辑Visual Studio的.csproj文件进行打包。据我所知,在其他操作系统上,nuget pack也会遵循这些设置。

.csproj设置

自从Visual Studio 2017以来,不再需要生成.nuspec文件。将.dll文件放在项目的子文件夹(这里是ffmpeg\)中。在<ItemGroup>标记中创建一个<None><Content>标记。通过Include属性指定要包含的文件。(所有内容区分大小写,因此include是无效的。)将Pack设置为true,将PackagePath设置为NuGet包中的目标路径。lib\$(TargetFramework)会将其放置在与二进制文件相同的位置(除非未定义TargetFramework)。您可以使用NuGetPackageExplorer验证所有内容是否正确打包到生成的*.nupkg文件中。最重要的是,将PackageCopyToOutput设置为true,这将在构建时执行提取和复制操作。

<ItemGroup>
  <PackageReference Include="FFmpeg.AutoGen.Bindings.DynamicallyLoaded" Version="5.1.1.1" />
  <None Include="ffmpeg\*.dll" Pack="true" PackagePath="lib\$(TargetFramework)" PackageCopyToOutput="true" />
</ItemGroup>

启用NuGet包复制到输出时未执行提取操作

Visual Studio 2022有一个错误,即在之前未启用的情况下将此打包行为启用并推送为NuGet包更新后,不会执行提取/复制操作。为解决此问题,请右键单击使用此NuGet包的项目,单击清理,然后单击重新生成。现在,使用该应用程序应该能够正常提取.dll文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接