本文适用于: ✔️.NET SDK 10 及更高版本
打包适用于特定平台和体系结构的 .NET 工具,以便分发原生、快速且优化的应用程序。 借助此功能,可以更轻松地为命令行工具(如 MCP 服务器或其他特定于平台的实用程序)分发优化的应用程序。
概述
从 .NET SDK 10 开始,可以创建面向特定作系统环境的 .NET 工具(由运行时标识符 (RID)表示)。 这些工具可以是:
- RID 特定:针对特定操作系统和体系结构进行编译。
- 自包含:包括 .NET 运行时,不需要单独的 .NET 安装。
- 本机 AOT:使用提前编译来加快启动速度,减少内存占用。
安装该工具时,用户不会注意到差异。 .NET CLI 会自动为其平台选择并安装最佳包。
选择加入特定于 RID 的打包
若要创建特定于 RID 的工具,请使用以下 MSBuild 属性之一配置项目:
RuntimeIdentifiers 属性
用于 RuntimeIdentifiers 指定工具支持的平台:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>mytool</ToolCommandName>
<RuntimeIdentifiers>win-x64;linux-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
</Project>
ToolPackageRuntimeIdentifiers 属性
或者,可以使用 ToolPackageRuntimeIdentifiers 来进行特定于工具的 RID 配置:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<PublishAot>true</PublishAot>
<ToolCommandName>mytool</ToolCommandName>
<ToolPackageRuntimeIdentifiers>win-x64;linux-x64;osx-arm64</ToolPackageRuntimeIdentifiers>
</PropertyGroup>
</Project>
使用以分号分隔的 RID 值列表。 有关运行时标识符的列表,请参阅 RID 目录。
提供依赖于框架的版本
选择启用特定于 RID 的工具打包时,.NET SDK 会为每个指定的 RID 创建自包含包。 但是,你丢失了依赖于框架的默认打包功能,这些功能可在任何安装了 .NET 运行时的平台上使用。
若要提供框架依赖版本以及 RID 特定的包,请将其添加到anyToolPackageRuntimeIdentifiers列表:
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<ToolPackageRuntimeIdentifiers>win-x64;osx-arm64;linux-x64;any</ToolPackageRuntimeIdentifiers>
</PropertyGroup>
此配置创建五个包:
- 一个包含所有可用子包的顶级指针包。
- 三个特定于 RID 的包(
win-x64、osx-arm64、linux-x64)是独立且精简的。 - 一个与 RID 无关的包(
any)依赖于框架,需要安装 .NET 运行时。
用户安装工具时:
- 在
win-x64、osx-arm64或linux-x64系统上,自包含的裁剪包会被下载并执行。 - 在其他任何操作系统或体系结构上,将使用依赖
any框架的程序包。
此方法为通用平台提供优化的自包含二进制文件,同时通过依赖于框架的回退保持与不太常见的平台的兼容性。
何时使用 RuntimeIdentifiers 与 ToolPackageRuntimeIdentifiers
同时RuntimeIdentifiers和ToolPackageRuntimeIdentifiers使工具参与 RID 特定的打包,但它们的作用略有不同:
在以下情况下使用 RuntimeIdentifiers:
- 希望项目不仅仅作为工具,而是从整体上生成和发布特定于 RID 的应用。
- 你主要针对 CoreCLR(非 AOT),或者希望标准 SDK 的行为,即使用单个
dotnet pack会生成多个特定于 RID 的包。 - 可以为部分 RID 条件化
PublishAot,但您仍然需要为RuntimeIdentifiers中的每个 RID 提供基于 CoreCLR 的包。
在以下情况下使用 ToolPackageRuntimeIdentifiers:
- 你 只想为工具打包定义特定于 RID 的行为,而无需更改项目为其他部署方案生成的方式。
- 你正在使用本机 AOT 并计划为每个 RID
dotnet pack -r <RID>AOT 二进制文件。 - 你需要一个 混合模型 ,其中一些 RID 获得本地 AOT,而另一些则退回到可移植的 CoreCLR 实现。
Notes:
- 顶级指针包指定可用的 RID 特定包。 如果指定
ToolPackageRuntimeIdentifiers,它将确定工具的 RID,否则将使用RuntimeIdentifiers。 -
ToolPackageRuntimeIdentifiers应等于RuntimeIdentifiers中的某个 RID 或它们的子集 - 当
PublishAot=true,仅当为特定 RID 打包时,才会生成特定于 RID 的包(例如,dotnet pack -r linux-x64)。 - 仅当生成 OS 和目标 OS 匹配时,才支持原生 AOT 生成(
PublishAot=true)。
将您的工具打包成软件包
打包过程因是否使用 AOT 编译而异。 若要从项目生成 NuGet 包或 .nupkg 文件,请运行 dotnet pack 命令。
特定于 RID 的自包含工具
运行 dotnet pack 一次:
dotnet pack
此命令创建多个 NuGet 包:
- 一个包对应每个 RID:
<packageName>.<RID>.<packageVersion>.nupkg- 示例:
mytool.win-x64.1.0.0.nupkg - 示例:
mytool.linux-x64.1.0.0.nupkg - 示例:
mytool.osx-arm64.1.0.0.nupkg
- 示例:
- 一个与 RID 无关的指针包:
<packageName>.<packageVersion>.nupkg- 示例:
mytool.1.0.0.nupkg
- 示例:
AOT 工具
对于具有 AOT 编译的工具(<PublishAot>true</PublishAot>),必须为每个平台单独打包。
本机 AOT 的平台要求
本机 AOT 编译要求 SDK RID 的操作系统(OS)部分与目标 RID 的操作系统(OS)匹配。 SDK 可以跨编译不同的体系结构(例如 x64 到 ARM64),但不能跨作系统(例如 Windows 到 Linux)。
这意味着你有多个用于构建本机 AOT 包的选项:
- 仅针对开发计算机生成:仅支持您所用开发操作系统的本机 AOT。
-
使用适用于 Linux 版本的容器:如果使用的是 macOS 或 Windows,请使用容器为 Linux 进行交叉编译。 例如,使用
mcr.microsoft.com/dotnet/sdk:10.0-noble-aot容器映像。 - 跨计算机协调构建:使用 GitHub Actions 或 Azure DevOps Pipelines 等 CI/CD 系统在不同的操作系统上构建。
无需在同一台计算机或同时构建所有 RID 特定的包。 只需在发布顶级包之前生成并发布它们。
打包本地 AOT(提前编译)工具
在任何平台上一次性打包顶层包:
dotnet pack
在相应平台上为每个特定的 RID 打包,例如:
dotnet pack -r linux-x64
必须在操作系统与目标 RID 的操作系统相匹配的平台上运行每个特定于 RID 的 pack 命令。 有关本机 AOT 编译所需的先决条件的更多信息,请参阅 本机 AOT 部署。
如果设置为PublishAottrue,打包行为将发生更改:
-
dotnet pack生成 顶级指针包 (包类型DotnetTool)。 - 仅当显式传递
-r <RID>(例如,dotnet pack -r linux-x64或dotnet pack -r osx-arm64) 时,才会生成特定于 RID 的 AOT 包。
混合 AOT + CoreCLR 打包模式(示例)
某些工具需要两个世界的最佳功能:
- 高优先级平台子集的本机 AOT(取决于工具)。
- 可移植的 CoreCLR 回退,适用于本机 AOT 构建未覆盖的平台。
可以使用以下模式实现此“混合”模型:
为本机 AOT 和特定于工具的 RID 配置工具。
在项目文件中,使用
ToolPackageRuntimeIdentifiers并启用PublishAot。例如:
<ToolPackageRuntimeIdentifiers>osx-arm64;linux-arm64;linux-x64;any</ToolPackageRuntimeIdentifiers> <PublishAot>true</PublishAot>创建指针包。
运行
dotnet pack一次(在任何平台上)以构建指向与 RID 相关特定包的顶级包。dotnet pack构建为所选 RID 的本机 AOT 包。
原生 AOT 编译需要在目标平台上构建。 使用
dotnet pack -r <RID>在匹配的平台上构建每个启用了 AOT 的 RID 包。
例如:
dotnet pack -r linux-x64
创建 CoreCLR 回退包。
若要提供通用回退,请在打包
anyRID 时不使用 AOT:dotnet pack -r any -p:PublishAot=false这会生成可在没有专用 AOT 生成的平台上运行的可移植 CoreCLR 包(例如
yourtool.any.<version>.nupkg)。
注释
还可以使用 .NET SDK 10.0-noble-aot 容器映像从支持 Linux 容器的任何主机生成和打包 Linux 本机 AOT 工具。 例如:
mcr.microsoft.com/dotnet/sdk:10.0-noble-aot
当开发计算机不本地运行 Linux 时,这很有用。
在此混合配置中:
- 指针包 (
yourtool.<version>.nupkg) 引用两者:- 特定于 RID 的本机 AOT 包(例如,
yourtool.osx-arm64和yourtool.linux-x64)。 - 作为备用的 CoreCLR 包
any。
- 特定于 RID 的本机 AOT 包(例如,
- .NET CLI 在用户运行
dotnet tool install或dnx命令时,会自动为其平台选择最合适的包。
示例: dotnet10-hybrid-tool
存储库dotnet10-hybrid-tool演示了这种混合打包模式,其中包含针对osx-arm64、linux-arm64和linux-x64的本机 AOT 包,以及用于any RID 的 CoreCLR 回退包(例如,当没有可用的 AOT 版本时在 Windows 上使用)。
可以自行安装和试用该工具:
dotnet tool install -g dotnet10-hybrid-tool
dotnet10-hybrid-tool
该工具报告其运行时框架说明、运行时标识符(RID)和编译模式(本机 AOT 或 CoreCLR)。
本机 AOT 平台上的示例输出:
Hi, I'm a 'DotNetCliTool v2' tool!
Yes, I'm quite fancy.
Version: .NET 10.0.2
RID: osx-arm64
Mode: Native AOT
在一个使用 CoreCLR 回退的平台上的示例输出:
Hi, I'm a 'DotNetCliTool v2' tool!
Yes, I'm quite fancy.
Version: .NET 10.0.2
RID: win-x64
Mode: CoreCLR
这使其成为一种有用的方法,用于实验特定于 RID 的 AOT 编译工具以及 CoreCLR 的回退行为。
发布您的工具
发布特定于 RID 的工具包时,.NET CLI 使用顶级包的版本号来选择匹配的 RID 特定包。 这意味着:
- 所有特定于 RID 的包必须具有与顶级包完全相同的版本。
- 在顶级包可用之前,所有包必须发布到包源。
若要确保发布过程顺利,请确保:
首先发布所有RID专用包:
dotnet nuget push yourtool.win-x64.1.0.0.nupkg dotnet nuget push yourtool.linux-x64.1.0.0.nupkg dotnet nuget push yourtool.osx-arm64.1.0.0.nupkg dotnet nuget push yourtool.any.1.0.0.nupkg最后发布顶级包:
dotnet nuget push yourtool.1.0.0.nupkg
最后发布顶级包可确保当用户安装工具时,所有引用的 RID 特定包都可用。 如果用户在发布所有 RID 包之前安装工具,安装将失败。
安装和运行工具
是否使用特定于 RID 的打包工具,对于用户而言是透明的实现细节。 无论工具开发人员是否选择采用特定于 RID 的打包,都以相同的方式安装和运行工具。
要全局安装一个工具:
dotnet tool install -g mytool
安装后,可以直接调用它:
mytool
还可以使用 dnx 助手,该助手在 Node.js 生态系统中的行为与 npx 类似:如果工具尚未存在,它会通过单次操作下载并启动工具。
dnx mytool
当工具使用特定于 RID 的打包时,.NET CLI 会自动为平台选择正确的包。 无需指定 RID - CLI 会从系统推断它并下载相应的 RID 特定包。