mcpField
D
dotnet-cli-distribution

dotnet-cli-distribution

github.com/wshaddix开发8674 次安装35 周前更新
代码仓库

关于 dotnet-cli-distribution

为 .NET CLI 开发者提供分发策略指南,帮助选择 Native AOT、依赖框架部署或 dotnet tool,并规划跨平台 RID 与单文件发布。还介绍二进制体积优化和发布产物校验。

主要功能

  1. 01比较 CLI 分发方式
  2. 02规划跨平台 RID 目标
  3. 03配置单文件发布
  4. 04优化发布二进制体积
  5. 05生成发布产物校验和

适用场景

  1. 01为 CLI 工具选择部署方式
  2. 02确定跨平台构建目标
  3. 03缩减自包含发布的体积
  4. 04准备可校验的发布文件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wshaddix/dotnet-skills --skill dotnet-cli-distribution

安装后在 Claude Code 中输入/dotnet-cli-distribution确认已加载。

详细介绍

dotnet-cli-distribution

.NET 工具的 CLI 分发策略:在 Native AOT 单文件发布、依赖框架的部署和 dotnet tool 打包之间做出选择。针对跨平台目标(linux-x64、osx-arm64、win-x64、linux-arm64)规划运行时标识符(RID)矩阵、配置单文件发布,以及优化 CLI 应用二进制文件大小的技巧。

**版本假设:**以 .NET 8.0+ 为基线。自 .NET 8 起,控制台应用已全面支持 Native AOT。自 .NET 6 起,单文件发布已相当成熟。

**范围之外:**Native AOT MSBuild 配置(PublishAot、ILLink 描述符、EnableAotAnalyzer、裁剪)——请参阅 [skill:dotnet-native-aot]。以 AOT 为先的应用设计模式(优先使用源生成而非反射、DI 选择)——请参阅 [skill:dotnet-aot-architecture]。多平台打包格式(Homebrew、apt/deb、winget、Scoop)——请参阅 [skill:dotnet-cli-packaging]。发布 CI/CD 流水线——请参阅 [skill:dotnet-cli-release-pipeline]。基于容器的分发——请参阅 [skill:dotnet-containers]。通用 CI/CD 模式——请参阅 [skill:dotnet-gha-patterns] 和 [skill:dotnet-ado-patterns]。

交叉引用:[skill:dotnet-native-aot] 介绍 AOT 编译流水线,[skill:dotnet-aot-architecture] 介绍 AOT 安全的设计模式,[skill:dotnet-cli-architecture] 介绍 CLI 分层架构,[skill:dotnet-cli-packaging] 介绍特定平台的打包格式,[skill:dotnet-cli-release-pipeline] 介绍自动化发布工作流,[skill:dotnet-containers] 介绍基于容器的分发,[skill:dotnet-tool-management] 介绍面向使用者的工具安装和清单管理。


分发策略决策矩阵

根据目标受众和部署限制选择分发模型。

策略启动时间二进制文件大小是否需要运行时最适用于
Native AOT 单文件~10ms10-30 MB无对性能要求高的 CLI 工具、广泛分发
依赖框架的单文件~100ms1-5 MB.NET 运行时可确保有运行时的内部工具
独立单文件~100ms60-80 MB无无需 AOT 复杂性的简单分发
dotnet tool(全局/本地)~200ms< 1 MB(NuGet).NET SDK开发者工具、.NET 生态系统用户
如何选择策略

Native AOT 单文件——CLI 分发的黄金标准:

  • 目标计算机上零依赖(无需 .NET 运行时)
  • 启动最快(~10ms,相比 JIT 的 ~100ms+)
  • 与裁剪结合时,二进制文件最小
  • 权衡:构建时间更长,除非保留反射功能,否则无法使用反射
  • PublishAot MSBuild 配置请参阅 [skill:dotnet-native-aot]

依赖框架的部署:

  • 产物大小最小(仅包含应用代码,不含运行时)
  • 用户必须安装 .NET 运行时
  • 最适用于运行时由内部/企业统一管理的工具
  • 仍可使用单文件发布,提升便利性

独立部署(非 AOT):

  • 产物中包含 .NET 运行时
  • 二进制文件比 AOT 更大,但构建流程更简单
  • 完整支持反射和动态代码
  • AOT 兼容性难以实现时,是不错的折中方案

dotnet tool 打包:

  • 通过 NuGet 分发——发布工作流最简单
  • 用户使用 dotnet tool install -g mytool 安装
  • 目标设备需要 .NET SDK(不只是运行时)
  • 最适用于 .NET 生态系统中面向开发者的工具
  • NuGet 分发详情请参阅 [skill:dotnet-cli-packaging]

运行时标识符(RID)矩阵

CLI 的标准 RID 目标

针对四个主要 RID,以实现广泛覆盖:

RID平台备注
linux-x64Linux x86_64大多数 Linux 服务器、CI 运行器、WSL
linux-arm64Linux ARM64AWS Graviton、Raspberry Pi 4+、Apple Silicon 虚拟机
osx-arm64macOS Apple SiliconM1/M2/M3+ Mac(主要 macOS 目标)
win-x64Windows x86_64Windows 10+、Windows Server
可选的扩展目标
RID包含时机
osx-x64支持旧款 Intel Mac(市场份额持续下降)
linux-musl-x64Alpine Linux / Docker scratch 镜像
linux-musl-arm64ARM64 上的 Alpine
win-arm64Windows on ARM(Surface Pro X、Snapdragon 笔记本电脑)
在 .csproj 中配置 RID




<PropertyGroup Condition="'$(RuntimeIdentifier)' == ''">
  <RuntimeIdentifier>osx-arm64</RuntimeIdentifier>
</PropertyGroup>

从命令行按 RID 发布:

# Publish for each target RID
dotnet publish -c Release -r linux-x64
dotnet publish -c Release -r linux-arm64
dotnet publish -c Release -r osx-arm64
dotnet publish -c Release -r win-x64

单文件发布

单文件发布会将应用及其依赖项打包到一个可执行文件中。

配置
<PropertyGroup>
  <PublishSingleFile>true</PublishSingleFile>
  
  <SelfContained>true</SelfContained>
  
  <DebugType>embedded</DebugType>
  
  <IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
配合 Native AOT 使用单文件发布

与 Native AOT 结合时,单文件发布是隐式的——AOT 始终会生成一个原生二进制文件:

<PropertyGroup>
  <PublishAot>true</PublishAot>
  
  
</PropertyGroup>

请参阅 [skill:dotnet-native-aot],了解完整的 AOT 发布配置,包括 ILLink、类型保留和分析器设置。

发布命令
# Framework-dependent single-file (requires .NET runtime on target)
dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true --self-contained false

# Self-contained single-file (includes runtime, no AOT)
dotnet publish -c Release -r linux-x64 /p:PublishSingleFile=true --self-contained true

# Native AOT (inherently single-file, smallest and fastest)
dotnet publish -c Release -r linux-x64
# (when PublishAot=true is in csproj)

优化 CLI 二进制文件的大小

裁剪(非 AOT)

裁剪会从发布输出中移除未使用的代码。对于自包含的非 AOT 构建:

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
  <TrimMode>link</TrimMode>
  
  <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>
AOT 大小优化

对于 Native AOT 构建,可通过 AOT 专用 MSBuild 属性控制大小。完整配置请参阅 [skill:dotnet-native-aot]。与 CLI 相关的关键属性包括 StripSymbols、OptimizationPreference、InvariantGlobalization 和 StackTraceSupport。

大小对比(典型 CLI 工具)
配置大致大小
自包含(不裁剪)60-80 MB
自包含 + 裁剪15-30 MB
Native AOT(默认)15-25 MB
Native AOT + 大小优化8-15 MB
Native AOT + 不变全球化 + 剥离符号5-10 MB
依赖框架1-5 MB
实用的大小缩减清单
  1. 启用不变全球化,前提是工具不需要特定区域设置的格式化(InvariantGlobalization=true)
  2. 在 Linux/macOS 上剥离符号(StripSymbols=true)——保留单独的符号文件用于崩溃分析
  3. 针对大小进行优化(OptimizationPreference=Size)——对 I/O 密集型 CLI 工具的运行时性能影响极小
  4. 尽可能禁用反射——使用源生成器进行 JSON 序列化([skill:dotnet-aot-architecture])
  5. 审查 NuGet 依赖项——每个依赖项都会增大二进制文件;移除未使用的包

依赖框架与自包含的权衡

依赖框架
dotnet publish -c Release -r linux-x64 --self-contained false

优点:

  • 产物最小(1-5 MB)
  • 由运行时更新提供维护(安全补丁由运行时应用,无需重新构建应用)
  • 发布速度更快

缺点:

  • 目标环境必须安装匹配的 .NET 运行时
  • 运行时版本不匹配会导致启动失败
  • 用户必须自行管理运行时安装
自包含
dotnet publish -c Release -r linux-x64 --self-contained true

优点:

  • 目标环境无需依赖运行时
  • 应用可控制确切的运行时版本
  • 支持并行部署(多个应用使用不同运行时)

缺点:

  • 产物较大(不裁剪时为 60-80 MB)
  • 必须为运行时安全补丁重新构建并分发
  • 每个目标 RID 都需要一个产物

发布工作流

本地开发
# Quick local publish for testing
dotnet publish -c Release -r osx-arm64

# Verify the binary
./bin/Release/net8.0/osx-arm64/publish/mytool --version
生成发布产物
#!/bin/bash
# build-all.sh -- Produce artifacts for all target RIDs
set -euo pipefail

VERSION="${1:?Usage: build-all.sh <version>}"
PROJECT="src/MyCli/MyCli.csproj"
OUTPUT_DIR="artifacts"

RIDS=("linux-x64" "linux-arm64" "osx-arm64" "win-x64")
# Note: Native AOT cross-compilation for ARM64 on x64 requires platform toolchain
# See [skill:dotnet-cli-release-pipeline] for CI-based cross-compilation setup

for rid in "${RIDS[@]}"; do
  echo "Publishing for $rid..."
  dotnet publish "$PROJECT" \
    -c Release \
    -r "$rid" \
    -o "$OUTPUT_DIR/$rid" \
    /p:Version="$VERSION"
done

# Create archives
for rid in "${RIDS[@]}"; do
  if [[ "$rid" == win-* ]]; then
    (cd "$OUTPUT_DIR/$rid" && zip -q "../mytool-$VERSION-$rid.zip" *)
  else
    tar -czf "$OUTPUT_DIR/mytool-$VERSION-$rid.tar.gz" -C "$OUTPUT_DIR/$rid" .
  fi
done

echo "Artifacts in $OUTPUT_DIR/"
生成校验和

始终为发布产物生成校验和:

# Generate SHA-256 checksums
cd artifacts
shasum -a 256 *.tar.gz *.zip > checksums-sha256.txt

请参阅 [skill:dotnet-cli-release-pipeline],了解如何在 GitHub Actions 中自动执行此操作。


Agent 注意事项

  1. **不要在多平台 CLI 工具的 .csproj 中设置 RuntimeIdentifier。**在项目文件中硬编码 RID 会导致无法为其他平台构建。应在发布时传入 -r <rid>。
  2. **不要同时使用 PublishSingleFile 和 PublishAot。**Native AOT 输出本身就是单文件。两者同时设置是多余的,还可能导致令人困惑的构建警告。
  3. **对于对体积敏感的 CLI 工具,不要忽略 InvariantGlobalization。**全球化数据会使 AOT 二进制文件增加约 25 MB。大多数不格式化特定区域设置的日期或货币的 CLI 工具都应启用 InvariantGlobalization=true。
  4. **不要分发未修剪的独立部署二进制文件。**对于终端用户来说,60-80 MB 的 CLI 工具无法接受。应进行修剪(PublishTrimmed)、使用 AOT,或采用依赖框架的方式分发。
  5. **不要忘记为发布产物生成校验和。**用户和包管理器需要 SHA-256 校验和来验证下载完整性。请参阅 [skill:dotnet-cli-release-pipeline],了解如何自动生成校验和。
  6. **不要在发布脚本中硬编码密钥。**对于任何签名或上传凭据,都应使用环境变量占位符(${SIGNING_KEY}),并注释说明 CI 密钥的存储位置。

参考资料

评论

支持 Markdown