dotnet-cli-distribution について
.NET CLI 開発者向けに、Native AOT、フレームワーク依存のデプロイ、dotnet tool の配布方式を選ぶためのガイドです。クロスプラットフォームの RID 計画、単一ファイル発行、バイナリサイズの最適化、リリース用チェックサムも扱います。
主な機能
- 01CLI の配布方式を比較
- 02クロスプラットフォームの RID を計画
- 03単一ファイル発行を設定
- 04発行バイナリのサイズを削減
- 05リリース用チェックサムを生成
活用シーン
- 01CLI のデプロイ方式を選択
- 02クロスプラットフォームのビルド対象を決定
- 03自己完結型リリースのサイズを削減
- 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 以降を基準とします。コンソールアプリの Native AOT は、.NET 8 以降で完全にサポートされています。単一ファイル発行は .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 単一ファイル | ~10ms | 10-30 MB | 不要 | パフォーマンスが重要な CLI ツール、幅広い配布 |
| フレームワーク依存の単一ファイル | ~100ms | 1-5 MB | .NET ランタイム | ランタイムが確実に用意される内部ツール |
| 自己完結型の単一ファイル | ~100ms | 60-80 MB | 不要 | AOT の複雑さを避けたシンプルな配布 |
dotnet tool(グローバル/ローカル) | ~200ms | < 1 MB(NuGet) | .NET SDK | 開発者向けツール、.NET エコシステムのユーザー |
各戦略を選択する場合
Native AOT 単一ファイル -- CLI 配布の最高水準:
- ターゲットマシン上の依存関係がゼロ(.NET ランタイムは不要)
- 最速の起動時間(JIT の ~100ms 以上に対して ~10ms)
- トリミングと組み合わせることで最小のバイナリサイズ
- トレードオフ:ビルド時間が長くなり、保持しない限りリフレクションを使用できません
- 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 ターゲット
幅広くカバーするには、主要な 4 つの RID をターゲットにします。
| RID | プラットフォーム | 備考 |
|---|---|---|
linux-x64 | Linux x86_64 | ほとんどの Linux サーバー、CI ランナー、WSL |
linux-arm64 | Linux ARM64 | AWS Graviton、Raspberry Pi 4 以降、Apple Silicon VM |
osx-arm64 | macOS Apple Silicon | M1/M2/M3 以降の Mac(macOS の主要ターゲット) |
win-x64 | Windows x86_64 | Windows 10 以降、Windows Server |
オプションの拡張ターゲット
| RID | 含める場合 |
|---|---|
osx-x64 | 旧型の Intel Mac をサポートする場合(市場シェアは減少傾向) |
linux-musl-x64 | Alpine Linux/Docker の scratch イメージを使用する場合 |
linux-musl-arm64 | ARM64 上の Alpine を使用する場合 |
win-arm64 | ARM 搭載の Windows(Surface Pro X、Snapdragon 搭載ノート PC)をサポートする場合 |
.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
単一ファイルの発行
単一ファイルの発行では、アプリケーションとその依存関係を 1 つの実行可能ファイルにまとめます。
設定
<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<DebugType>embedded</DebugType>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
Native AOT での単一ファイル発行
Native AOT と組み合わせると、単一ファイルは暗黙的に有効になります。AOT では常に単一のネイティブバイナリが生成されます。
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
ILLink、型の保持、アナライザーの設定を含む AOT 発行設定の全容については、[skill:dotnet-native-aot] を参照してください。
発行コマンド
# 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 |
実用的なサイズ削減チェックリスト
- ツールでロケール固有の書式設定が不要な場合は、不変のグローバリゼーションを有効にします(
InvariantGlobalization=true) - Linux/macOS ではシンボルを削除します(
StripSymbols=true)。クラッシュ解析用にシンボルファイルは別途保持してください - サイズを優先して最適化します(
OptimizationPreference=Size)。I/O 待ちが中心の CLI ツールでは、ランタイムのパフォーマンスへの影響は最小限です - 可能な場合はリフレクションを無効にします。JSON シリアル化にはソースジェネレーターを使用してください([skill:dotnet-aot-architecture])
- 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 ごとに成果物が 1 つ必要です
発行ワークフロー
ローカル開発
# 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
GitHub Actions でこれを自動化する方法については、[skill:dotnet-cli-release-pipeline] を参照してください。
エージェントに関する注意点
- マルチプラットフォーム対応の CLI ツールでは、.csproj に RuntimeIdentifier を設定しないでください。 プロジェクトファイルで RID をハードコードすると、他のプラットフォーム向けにビルドできなくなります。代わりに、発行時に
-r <rid>を渡してください。 - PublishAot と PublishSingleFile を併用しないでください。 Native AOT の出力は本質的に単一ファイルです。両方を設定しても冗長であり、ビルド時にわかりにくい警告が発生することがあります。
- サイズが重要な CLI ツールでは、InvariantGlobalization を省略しないでください。 グローバリゼーションデータによって、AOT バイナリのサイズは約 25 MB 増加します。ロケール固有の日付や通貨をフォーマットしない CLI ツールの多くでは、
InvariantGlobalization=trueを有効にしてください。 - トリミングされていない自己完結型バイナリを配布しないでください。 60~80 MB の CLI ツールは、エンドユーザーにとって許容できません。トリミング(PublishTrimmed)するか、AOT を使用するか、フレームワーク依存型として配布してください。
- リリース成果物のチェックサムを忘れずに生成してください。 ユーザーやパッケージマネージャーがダウンロードの整合性を検証できるよう、SHA-256 チェックサムが必要です。チェックサムを自動生成する方法については、[skill:dotnet-cli-release-pipeline] を参照してください。
- 発行スクリプトにシークレットをハードコードしないでください。 署名やアップロードの認証情報には、環境変数のプレースホルダー(
${SIGNING_KEY})を使用し、CI でのシークレットの保存場所についてコメントを添えてください。