支持多个 .NET 版本
许多库以 .NET Framework 的特定版本为目标。 例如,你可能拥有特定于 UWP 的一个库版本,而拥有的另一版本利用 .NET Framework 4.6 中的功能。 为了适应这种情况,NuGet 支持将同一个库的多个版本放在单个包中。
本文介绍 NuGet 包的布局,但不考虑包或程序集的生成方式(也就是说,无论是使用多个非 SDK 样式的 .csproj 文件、自定义 .nuspec 文件,还是单个多目标 SDK 样式的 .csproj,布局都相同)。 对于 SDK 样式的项目,NuGet pack 目标知道如何设计包的布局,并自动将程序集放在正确的 lib 文件夹中,并为每个目标框架 (TFM) 创建依赖项组。 有关详细说明,请参阅在项目文件中支持多个 .NET Framework 版本。
使用创建包中介绍的基于约定的工作目录方法时,必须按照本文所述手动设计包的布局。 对于 SDK 样式的项目,建议使用自动方法,但也可以选择按照本文所述手动设计包的布局。
框架版本的文件夹结构
生成仅包含一个库版本或面向多个框架的包时,始终根据以下约定使用区分大小写的不同框架名称在 lib
下创建子文件夹:
lib\{framework name}[{version}]
有关支持的名称的完整列表,请参阅目标框架引用。
所具有的库版本必须特定于某框架,且不应直接放置在根 lib
文件夹中。 (此功能仅受 packages.config
支持。) 此操作会导致库与任何目标框架兼容,并允许在任何位置上进行安装,很可能造成意外的运行时错误。 已弃用在根文件夹(如 lib\abc.dll
)或子文件夹(如 lib\abc\abc.dll
)中添加程序集的操作,且在使用 PackagesReference 格式时忽略了此操作。
例如,以下文件夹结构支持特定于框架的程序集的四种版本:
\lib
\net46
\MyAssembly.dll
\net461
\MyAssembly.dll
\uap
\MyAssembly.dll
\netcore
\MyAssembly.dll
若要在生成包时轻松包括所有这些文件,请在 .nuspec
的 <files>
部分中使用递归 **
通配符:
<files>
<file src="lib\**" target="lib/{framework name}[{version}]" />
</files>
特定于体系结构的文件夹
如果具有特定于体系结构的程序集,即面向 ARM、x86 和 x64 的单独程序集,必须将它们放置在名为 {platform}-{architecture}\lib\{framework}
或 {platform}-{architecture}\native
的子文件夹内名为 runtimes
的文件夹中。 例如,以下文件夹结构可以容纳面向 Windows 10 的本机和托管 DLL 以及 uap10.0
框架:
\runtimes
\win10-arm
\native
\lib\uap10.0
\win10-x86
\native
\lib\uap10.0
\win10-x64
\native
\lib\uap10.0
这些程序集将仅在运行时可用,因此,如果你也想要提供相应的编译时程序集,则在 /ref/{tfm}
文件夹中设置 AnyCPU
程序集。
请注意,NuGet 始终从一个文件夹选取这些编译或运行时资产,因此,如果在 /ref
中存在某些兼容资产,则将忽略 /lib
以添加编译时程序集。 同样,如果在 /runtimes
中有某些兼容资产,则也将为运行时忽略 /lib
。
有关在 .nuspec
清单中引用这些文件的示例,请参阅创建 UWP 包。
此外,请参阅使用 NuGet 打包 Windows 存储应用组件
将程序集版本与项目中的目标框架匹配
NuGet 在安装具有多个程序集版本的包时,会尝试将程序集的框架名称与项目的目标框架匹配。
如果未找到匹配项,NuGet 将复制小于或等于项目的目标框架的最高版本的程序集(如果可用)。 如果未找到任何兼容的程序集,NuGet 将返回相应的错误消息。
例如,假设包中具有以下文件夹结构:
\lib
\net45
\MyAssembly.dll
\net461
\MyAssembly.dll
当在面向 .NET Framework 4.6 的项目中安装此包时,NuGet 将在 net45
文件夹中安装程序集,因为它是小于或等于 4.6 的最高可用版本。
但是,如果项目面向 .NET Framework 4.6.1,NuGet 将在 net461
文件夹中安装程序集。
如果项目面向 .NET Framework 4.0 和更早版本,NuGet 会发出相应的错误消息,因为找不到兼容的程序集。
通过框架版本对程序集进行分组
NuGet 仅从包中的单个库文件夹中复制程序集。 例如,假设包具有以下文件夹结构:
\lib
\net40
\MyAssembly.dll (v1.0)
\MyAssembly.Core.dll (v1.0)
\net45
\MyAssembly.dll (v2.0)
当在面向 .NET Framework 4.5 的项目中安装包时,将仅安装 MyAssembly.dll
(v2.0) 程序集。 不会安装 MyAssembly.Core.dll
(v1.0),因为它未在 net45
文件夹中列出。 NuGet 执行此操作的原因是 MyAssembly.Core.dll
可能已合并到 MyAssembly.dll
的 2.0 版本中。
如果要为 .NET Framework 4.5 安装 MyAssembly.Core.dll
,请在 net45
文件夹中放置副本。
通过框架配置文件对程序集进行分组
NuGet 还通过向文件夹末尾追加短划线和配置文件名称,支持以特定的框架配置文件为目标。
lib{framework name}-{profile}
以下是支持的配置文件:
client
:客户端配置文件full
:完整配置文件wp
:Windows Phonecf
:Compact Framework
声明依赖项(高级)
打程序包项目文件时,NuGet 尝试从项目自动生成依赖项。 此部分中的信息介绍了如何使用 .nuspec 文件声明依赖项,通常仅高级方案需要使用此信息。
(版本 2.0+) 可以使用 <dependencies>
元素中的 <group>
元素在目标项目的目标框架对应的 .nuspec 中声明程序包依赖项。 有关详细信息,请参阅依赖项元素。
每个组都有一个名为 targetFramework
的特性,并包含零个或多个 <dependency>
元素。 当目标框架与项目的框架配置文件兼容时,将会一起安装这些依赖项。 有关确切的框架标识符,请参阅目标框架。
建议每个目标框架名字对象 (TFM) 将一个组用于 lib/ 和 ref/ 文件夹中的文件。
以下示例显示了 <group>
元素的不同变体:
<dependencies>
<group targetFramework="net472">
<dependency id="jQuery" version="1.10.2" />
<dependency id="WebActivatorEx" version="2.2.0" />
</group>
<group targetFramework="net20">
</group>
</dependencies>
确定要使用的 NuGet 目标
当打包面向可移植类库的库时,不容易确定应在文件夹名称和 .nuspec
文件中使用的 NuGet 目标,尤其当仅面向 PCL 的子集时。 以下外部资源有助于解决此问题:
- .NET 中的框架配置文件 (stephenclearly.com)
- 可移植类库的配置文件 (plnkr.co):枚举 PCL 配置文件及其等效 NuGet 目标的表
- 可移植类库的配置文件工具 (github.com):用于确定系统上可用的 PCL 配置文件的命令行工具
内容文件和 PowerShell 脚本
警告
仅可通过 packages.config
格式使用可变的内容文件和脚本执行;这些内容在使用所有其他格式时已弃用,且不应用于任何新的包。
对于 packages.config
,可以使用 content
和 tools
文件夹中的相同文件夹约定,通过目标框架对内容文件和 PowerShell 脚本进行分组。 例如:
\content
\net46
\MyContent.txt
\net461
\MyContent461.txt
\uap
\MyUWPContent.html
\netcore
\tools
init.ps1
\net46
install.ps1
uninstall.ps1
\uap
install.ps1
uninstall.ps1
如果框架文件夹保留为空,NuGet 不会添加程序集引用或内容文件,也不会运行该框架的 PowerShell 脚本。
注意
因为 init.ps1
在解决方案级别执行,且它不依赖于项目,所以必须将其直接放置在 tools
文件夹下。 如果将其放置在框架文件夹下,它会被忽略。