从 Nuget 包中提取自动本机和托管 DLL
Automatic native and managed DLLs extracting from Nuget Package
这让我发疯了好几个月了,但我仍然无法实现。我的托管库是从 Nuget 包中提取的,而不是本地的。
我们有一堆由另一家公司提供的托管库和本机库。
我们有 x86
和 x64
版本。为了在 ASP.NET 核心项目中使用它们,我必须创建一个 Nuget 包。
我的架构是:
- 一个 ASP.NET 核心 class 库,我将其更改为仅针对完整的 .NET Framework。这个项目引用了我的 Nuget 包
- ASP.NET 核心网站也针对完整的 .NET Framework 并引用 class 库
当然,最后,我需要将我的本机库提取到网站的正确运行时文件夹中(例如:\bin\Debug\net461\win7-x64
)。
目前我的解决方案是:
- 将本机库放入
build
文件夹
- 创建一个
targets
文件,将它们复制到 $(OutputPath)
(甚至不是运行时文件夹)
- 将一些 MsBuild 命令添加到我网站的
xproj
以获取我的 $(USERPROFILE)\.nuget\packages\
文件夹中的目标文件并执行它
- 手动复制现在在
bin
文件夹中提取的本机DLL到runtime
一个
我尝试使用 project.json
中的一些配置将它们直接复制到运行时文件夹(老实说,我不记得我为这部分尝试过的所有事情)但这总是失败。此外,即使我在我的目标文件中指定了 SkipUnchangedFiles="true"
,它也会被忽略,并且我的 DLL 在每次构建期间都会被复制到我的 bin 文件夹中。
为了实现 DLL 提取,这是一个繁重的过程,现在我真的想摆脱所有 MsBuild 并获得更简单的解决方案。
我知道使用较新版本的 Nuget,它现在能够在不添加自定义 MsBuild 命令的情况下本地提取它们。正如所写 here,C# 项目甚至不需要 targets
文件
Next, C++ and JavaScript projects that might consume your NuGet package need a .targets file to identify the necessary assembly and winmd files. (C# and Visual Basic projects do this automatically.)
几个月来我一直在浏览器中打开一个选项卡(original link) and realize this resource has been recently removed from Nuget website. It was explaining how to use the runtimes
folder to automatically extract natives DLLs. However I've never been able to get a successful result as it was explained. Now this page has been deleted and replaced by this one,解释很少,根本没有谈论这个 runtimes
文件夹。
我的猜测是我应该为本机 DLL 使用 runtimes
文件夹,为托管 DLL 使用 lib
文件夹,但我不是 100% 确定。 (我还应该使用 build
文件夹吗?)
我已经尝试了几件事(我不记得尝试了多少次,因为我说了几个月的头痛......)比如this architecture(我不明白这里有什么意义build/native
以及 runtimes
下的 natives 文件夹)
我还尝试将 here 描述的 .NET Framework 版本结构用于我的托管库。
This好像也是解决的一部分
The architecture is ignored by the compiler when creating an assembly reference. It's a load time concept. The loader will prefer an architecture specific reference if it exists.
One trick you can use to produce an AnyCPU assembly is to use corflags to remove the architecture from your x86 assembly. EG: corflags /32BITREQ- MySDK.dll. Corflags is part of the .NET SDK and can be found in VS's developer command prompt.
这就是我所做的,将 x86 和 x64 DLL 都转换为 AnyCPU
(不知道它是否对 x64 DLL 有所帮助,但我没有遇到错误)然后在我的系统中尝试了几种不同的架构Nuget 包但仍然无法正常工作。
project.json中没有任何条目的默认运行时是win7-x64
,所以我决定明确指定它以防万一
"runtimes": {
"win7-x64": {}
},
所以这是我在 Nuget 包中进行的所有尝试所使用的运行时标识符。但是我不关心 windows 版本。我实际上更喜欢 win-x86 或 win-x64 但根据 this page
它似乎是一个无效值
Windows RIDs
Windows 7 / Windows Server 2008 R2
- win7-x64
- win7-x86
Windows 8 / Windows Server 2012
- win8-x64
- win8-x86
- win8-arm
Windows 8.1 / Windows Server 2012 R2
- win81-x64
- win81-x86
- win81-arm
Windows 10 / Windows Server 2016
- win10-x64
- win10-x86
- win10-arm
- win10-arm64
但是这个 Github source 描述了更多的 RID 那么哪个来源是正确的?
正如你所看到的,这里有很多谜团,主要是因为缺乏文档,甚至不同文档之间存在矛盾。
如果至少我可以有一个工作示例,那么我可以执行我的测试来回答其他问题,例如尝试通用 win-x64
RID,或者看看我是否可以包含一次我的托管库,无论 .NET Framework 版本如何.
请注意我的特殊背景:我有一个 ASP.NET 核心项目,目标是完整的 .NET Framework
感谢您的回答,我迫切希望让这个简单的东西发挥作用。
我将尝试尽可能详细地解释我所经历的所有痛苦和解决方案。在我的示例中,我使用简单的文本文件 AAA86.txt
、AAA64.txt
和 AAAany.txt
而不是本机 DLL 来简单地演示提取过程。
首先你需要知道的是:
如果您尝试将 native
NuGet 架构与包含一些托管库的 lib
文件夹混合使用,它将无法工作
在这种情况下,您的托管 DLL 将被复制到您项目的输出目录,而不是您的本地目录。
感谢 Jon Skeet 为我指出了正确的方向,并建议我看一下 Grpc.Core package。诀窍是创建一个 targets
文件来处理 DLL 提取。
你的目标文件应该包含这样的东西
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x64\native\AAA64.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA64.txt</Link>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x86\native\AAA86.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA86.txt</Link>
</Content>
</ItemGroup>
</Project>
还要确保您的 .targets
文件的名称与您的 AssemblyName 相同。因此,如果您的程序集名称为 DemoPackage
,您的目标文件应命名为 DemoPackage.targets
。否则,在另一个项目中引用包时,可能不会应用 .targets
文件。
现在您还需要知道一些其他事情:
1) Visual Studio 根本不关心你选择的设置,它总是使用虚拟摆脱。 (在我的例子中,我总是以一个 win7-x64
文件夹结束,即使我在 Windows 10...)
2)你project.json
里面的platform setting也完全没用
{
"buildOptions": {
"platform": "x64"
}
}
3)在runtimes settings如果只设置win
and/orwin-x64
"runtimes": {
"win": {},
"win-x64": {}
}
Visual Studio 将改为使用 win7-x64
。但是如果你在 Windows 10 机器上添加 win10-x64
那么这将被使用
4) 如果您使用这样的通用 RID 编译您的应用程序
dotnet build -c debug -r win
然后你的 targets
文件将收到你机器的架构(在我的例子中是 x64)而不是我期望的 AnyCPU
5) 只有本机库而没有任何托管库,如果您遵循架构 runtimes/RID/native
,提取将在没有目标文件的情况下工作
6) 我的包中只有本机库,选择的 RID 将始终 win-x64
使用 Visual Studio 构建,正如我告诉你的运行时文件夹始终创建的是 win7-x64
,无论我的配置如何 select。如果我的包裹中只有一个 win
RID,那么它就会被成功提取。
编辑:
作为最后一个有用的说明,在执行此类任务时,您可能会发现像这样打印出正在执行 .targets
文件的当前目录很方便
<Target Name="TestMessage" AfterTargets="Build" >
<Message Text="***********************************************************" Importance="high"/>
<Message Text="$(MSBuildThisFileDirectory)" Importance="high"/>
<Message Text="***********************************************************" Importance="high"/>
</Target>
你的目录会在Visual Studio
的Build
输出中打印出来
当您使用 dotnet restore
而不是 nuget.exe restore
时,本机 DLL 未被复制到输出目录的问题现在已经消失了。
我的问题在专门使用 dotnet restore --runtime win-x64 <path_to_the_solution.sln>
.
时得到解决
这让我发疯了好几个月了,但我仍然无法实现。我的托管库是从 Nuget 包中提取的,而不是本地的。
我们有一堆由另一家公司提供的托管库和本机库。
我们有 x86
和 x64
版本。为了在 ASP.NET 核心项目中使用它们,我必须创建一个 Nuget 包。
我的架构是:
- 一个 ASP.NET 核心 class 库,我将其更改为仅针对完整的 .NET Framework。这个项目引用了我的 Nuget 包
- ASP.NET 核心网站也针对完整的 .NET Framework 并引用 class 库
当然,最后,我需要将我的本机库提取到网站的正确运行时文件夹中(例如:\bin\Debug\net461\win7-x64
)。
目前我的解决方案是:
- 将本机库放入
build
文件夹 - 创建一个
targets
文件,将它们复制到$(OutputPath)
(甚至不是运行时文件夹) - 将一些 MsBuild 命令添加到我网站的
xproj
以获取我的$(USERPROFILE)\.nuget\packages\
文件夹中的目标文件并执行它 - 手动复制现在在
bin
文件夹中提取的本机DLL到runtime
一个
我尝试使用 project.json
中的一些配置将它们直接复制到运行时文件夹(老实说,我不记得我为这部分尝试过的所有事情)但这总是失败。此外,即使我在我的目标文件中指定了 SkipUnchangedFiles="true"
,它也会被忽略,并且我的 DLL 在每次构建期间都会被复制到我的 bin 文件夹中。
为了实现 DLL 提取,这是一个繁重的过程,现在我真的想摆脱所有 MsBuild 并获得更简单的解决方案。
我知道使用较新版本的 Nuget,它现在能够在不添加自定义 MsBuild 命令的情况下本地提取它们。正如所写 here,C# 项目甚至不需要 targets
文件
Next, C++ and JavaScript projects that might consume your NuGet package need a .targets file to identify the necessary assembly and winmd files. (C# and Visual Basic projects do this automatically.)
几个月来我一直在浏览器中打开一个选项卡(original link) and realize this resource has been recently removed from Nuget website. It was explaining how to use the runtimes
folder to automatically extract natives DLLs. However I've never been able to get a successful result as it was explained. Now this page has been deleted and replaced by this one,解释很少,根本没有谈论这个 runtimes
文件夹。
我的猜测是我应该为本机 DLL 使用 runtimes
文件夹,为托管 DLL 使用 lib
文件夹,但我不是 100% 确定。 (我还应该使用 build
文件夹吗?)
我已经尝试了几件事(我不记得尝试了多少次,因为我说了几个月的头痛......)比如this architecture(我不明白这里有什么意义build/native
以及 runtimes
下的 natives 文件夹)
我还尝试将 here 描述的 .NET Framework 版本结构用于我的托管库。
This好像也是解决的一部分
The architecture is ignored by the compiler when creating an assembly reference. It's a load time concept. The loader will prefer an architecture specific reference if it exists.
One trick you can use to produce an AnyCPU assembly is to use corflags to remove the architecture from your x86 assembly. EG: corflags /32BITREQ- MySDK.dll. Corflags is part of the .NET SDK and can be found in VS's developer command prompt.
这就是我所做的,将 x86 和 x64 DLL 都转换为 AnyCPU
(不知道它是否对 x64 DLL 有所帮助,但我没有遇到错误)然后在我的系统中尝试了几种不同的架构Nuget 包但仍然无法正常工作。
project.json中没有任何条目的默认运行时是win7-x64
,所以我决定明确指定它以防万一
"runtimes": {
"win7-x64": {}
},
所以这是我在 Nuget 包中进行的所有尝试所使用的运行时标识符。但是我不关心 windows 版本。我实际上更喜欢 win-x86 或 win-x64 但根据 this page
它似乎是一个无效值Windows RIDs
Windows 7 / Windows Server 2008 R2
- win7-x64
- win7-x86
Windows 8 / Windows Server 2012
- win8-x64
- win8-x86
- win8-arm
Windows 8.1 / Windows Server 2012 R2
- win81-x64
- win81-x86
- win81-arm
Windows 10 / Windows Server 2016
- win10-x64
- win10-x86
- win10-arm
- win10-arm64
但是这个 Github source 描述了更多的 RID 那么哪个来源是正确的?
正如你所看到的,这里有很多谜团,主要是因为缺乏文档,甚至不同文档之间存在矛盾。
如果至少我可以有一个工作示例,那么我可以执行我的测试来回答其他问题,例如尝试通用 win-x64
RID,或者看看我是否可以包含一次我的托管库,无论 .NET Framework 版本如何.
请注意我的特殊背景:我有一个 ASP.NET 核心项目,目标是完整的 .NET Framework
感谢您的回答,我迫切希望让这个简单的东西发挥作用。
我将尝试尽可能详细地解释我所经历的所有痛苦和解决方案。在我的示例中,我使用简单的文本文件 AAA86.txt
、AAA64.txt
和 AAAany.txt
而不是本机 DLL 来简单地演示提取过程。
首先你需要知道的是:
如果您尝试将 native
NuGet 架构与包含一些托管库的 lib
文件夹混合使用,它将无法工作
在这种情况下,您的托管 DLL 将被复制到您项目的输出目录,而不是您的本地目录。
感谢 Jon Skeet 为我指出了正确的方向,并建议我看一下 Grpc.Core package。诀窍是创建一个 targets
文件来处理 DLL 提取。
你的目标文件应该包含这样的东西
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x64\native\AAA64.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA64.txt</Link>
</Content>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'x86' OR '$(Platform)' == 'AnyCPU' ">
<Content Include="$(MSBuildThisFileDirectory)..\runtimes\win-x86\native\AAA86.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Link>AAA86.txt</Link>
</Content>
</ItemGroup>
</Project>
还要确保您的 .targets
文件的名称与您的 AssemblyName 相同。因此,如果您的程序集名称为 DemoPackage
,您的目标文件应命名为 DemoPackage.targets
。否则,在另一个项目中引用包时,可能不会应用 .targets
文件。
现在您还需要知道一些其他事情:
1) Visual Studio 根本不关心你选择的设置,它总是使用虚拟摆脱。 (在我的例子中,我总是以一个 win7-x64
文件夹结束,即使我在 Windows 10...)
2)你project.json
里面的platform setting也完全没用
{
"buildOptions": {
"platform": "x64"
}
}
3)在runtimes settings如果只设置win
and/orwin-x64
"runtimes": {
"win": {},
"win-x64": {}
}
Visual Studio 将改为使用 win7-x64
。但是如果你在 Windows 10 机器上添加 win10-x64
那么这将被使用
4) 如果您使用这样的通用 RID 编译您的应用程序
dotnet build -c debug -r win
然后你的 targets
文件将收到你机器的架构(在我的例子中是 x64)而不是我期望的 AnyCPU
5) 只有本机库而没有任何托管库,如果您遵循架构 runtimes/RID/native
6) 我的包中只有本机库,选择的 RID 将始终 win-x64
使用 Visual Studio 构建,正如我告诉你的运行时文件夹始终创建的是 win7-x64
,无论我的配置如何 select。如果我的包裹中只有一个 win
RID,那么它就会被成功提取。
编辑:
作为最后一个有用的说明,在执行此类任务时,您可能会发现像这样打印出正在执行 .targets
文件的当前目录很方便
<Target Name="TestMessage" AfterTargets="Build" >
<Message Text="***********************************************************" Importance="high"/>
<Message Text="$(MSBuildThisFileDirectory)" Importance="high"/>
<Message Text="***********************************************************" Importance="high"/>
</Target>
你的目录会在Visual Studio
的Build
输出中打印出来
当您使用 dotnet restore
而不是 nuget.exe restore
时,本机 DLL 未被复制到输出目录的问题现在已经消失了。
我的问题在专门使用 dotnet restore --runtime win-x64 <path_to_the_solution.sln>
.