共用方式為


建立專為資源識別碼(RID)設計的、自成一體的 AOT .NET 工具

本文適用於: ✔️.NET SDK 10 及更新版本

針對特定平台和架構打包 .NET 工具,這樣你就能分發原生、快速和修剪過的應用程式。 此功能使得更容易分發優化的應用程式給命令列工具,例如 MCP 伺服器或其他平台專用工具。

概觀

從 .NET SDK 10 開始,你可以建立針對特定作業系統環境(以執行時識別碼(RID)表示)的 .NET 工具。 這些工具可以包括:

  • 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 目錄

何時使用 RuntimeIdentifiers vs ToolPackageRuntimeIdentifiers

這兩者RuntimeIdentifiersToolPackageRuntimeIdentifiers 都將工具適配於特定的 RID 包裝,但它們的用途略有不同:

RuntimeIdentifiers 的使用時機:

  • 你希望專案能建立 並發佈專門針對 RID 的應用程式 (而不只是當作工具)。
  • 你主要目標是 CoreCLR (非 AOT),或者你想要標準的 SDK 行為,即一個 dotnet pack 套件能產生多個專門的 RID 套件。
  • 你可以將 PublishAot 針對部分 RID 進行條件化,但你仍希望每個 RID 在 RuntimeIdentifiers 都有基於 CoreCLR 的套件。

ToolPackageRuntimeIdentifiers 的使用時機:

  • 你只想為 工具封裝定義 RID 專屬行為,而不改變專案在其他部署情境下的建置方式。
  • 你正在使用 Native AOT,並計劃依據每個 RID 手動建立dotnet pack -r <RID>AOT 二進位檔。
  • 你需要一個 混合模式 ,有些 RID 會使用 Native AOT,有些則回退到可攜式的 CoreCLR 實作。

Notes:

  • 頂層指標套件指定可用的 RID 專用套件。 若指定 ToolPackageRuntimeIdentifiers,則決定工具的 RIDs;否則使用 RuntimeIdentifiers
  • ToolPackageRuntimeIdentifiers 應等於 RuntimeIdentifiers 中的 RID 或是其子集
  • PublishAot=true時,僅在你為特定 RID 打包時才會產生專屬 RID 套件(例如 dotnet pack -r linux-x64)。
  • 原生 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 中的作業系統部分與目標 RID 的作業系統相符。 SDK 可跨架構(例如 x64 轉為 ARM64),但無法跨作業系統(例如 Windows 轉 Linux)。

這表示你有多種方式來建立原生 AOT 套件:

  • 只為你的開發機器編譯:只支援你正在開發的作業系統上的原生 AOT。
  • Linux 建置時使用容器:如果你用的是 macOS 或 Windows,可以用容器來交叉編譯 Linux。 例如,使用 mcr.microsoft.com/dotnet/sdk:10.0-noble-aot 容器圖片。
  • 跨機器聯盟建置:使用 CI/CD 系統如 GitHub Actions 或 Azure DevOps Pipelines,在不同作業系統上建置。

你不需要在同一台機器或同時建立所有 RID 專屬套件。 你只需要先建置並發佈它們,再發佈頂層套件。

打包原生AOT工具

打包一次頂層套件(在任何平台):

dotnet pack

針對對應平台上的每個特定RID進行包裝,例如:

dotnet pack -r linux-x64

你必須在作業系統與目標 RID 作業系統相符的平台上執行每個 RID 專屬的 pack 指令。 欲了解更多關於 Native AOT 編譯的前置條件,請參見 Native AOT 部署

當你設定 PublishAottrue時,打包行為會改變:

  • dotnet pack 產生頂層指標封裝(封裝類型DotnetTool)。
  • RID 專用的 AOT 套件僅在你明確傳遞 -r <RID>,例如 , dotnet pack -r linux-x64dotnet pack -r osx-arm64時才會產生。

混合 AOT + CoreCLR 封裝模式(範例)

有些工具想要兩者兼得:

  • 原生AOT 用於部分高優先度平台(視工具而定)。
  • 一個 可攜式的 CoreCLR 替代方案 ,適用於原生 AOT 構建不支援的平台。

你可以透過以下模式達成這種「混合」模式:

  1. 設定工具以支援Native AOT和特定工具RID。

    在你的專案檔案中,使用 ToolPackageRuntimeIdentifiers 並啟用 PublishAot

    例如:

    <ToolPackageRuntimeIdentifiers>osx-arm64;linux-arm64;linux-x64;any</ToolPackageRuntimeIdentifiers>
    <PublishAot>true</PublishAot>
    
  2. 建立指標套件。

    執行 dotnet pack 一次(在任何平台)即可建立指向 RID 專屬套件的頂層套件:

    dotnet pack
    
  3. 為特定 RID 建置原生 AOT 套件。

    原生的《進擊的巨人》編譯需要在目標平台上建構。 請在匹配的平台上使用 dotnet pack -r <RID> 建立每個啟用 AOT 的 RID 套件。

例如:

dotnet pack -r linux-x64
  1. 建立一個 CoreCLR 備用套件。

    為了提供通用後備方案,請在沒有提前編譯的情況下打包 any RID:

    dotnet pack -r any -p:PublishAot=false
    

    這會產生一個可攜式的 CoreCLR 套件(例如 yourtool.any.<version>.nupkg),可以在沒有專用 AOT 建置的平台上執行。

備註

你也可以利用 .NET SDK 10.0-noble-aot 容器映像檔,從任何支援 Linux 容器的主機上建置並打包 Linux 原生 AOT 工具。 例如:

  • mcr.microsoft.com/dotnet/sdk:10.0-noble-aot

當你的開發機器不是原生運行 Linux 時,這很有用。

在這個混合配置中:

  • 指標封包(yourtool.<version>.nupkg)同時引用:
    • RID 專用的 Native AOT 套件(例如, yourtool.osx-arm64yourtool.linux-x64)。
    • CoreCLR any 套件作為備用方案。
  • .NET CLI 會在使用者執行 dotnet tool installdnx 時,根據使用者的平台自動選擇最合適的套件。

範例:dotnet10-hybrid-tool

dotnet10-hybrid-tool 倉庫 展示了這種混合封裝模式,包含針對 osx-arm64linux-arm64linux-x64 的原生 AOT 套件,以及針對 any RID 的 CoreCLR 備援套件(例如在 Windows 上,當沒有 AOT 建置可用時使用)。

你可以安裝並自行試用這個工具:

dotnet tool install -g dotnet10-hybrid-tool
dotnet10-hybrid-tool

該工具會回報其執行時框架描述、執行時識別碼(RID)及編譯模式(Native 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 專用套件必須與頂層套件版本完全相同。
  • 所有套件必須先發佈到你的動態消息,頂層套件才會開放。

為確保出版流程順利:

  1. 先發布所有 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
    
  2. 最後發佈頂層套件:

    dotnet nuget push yourtool.1.0.0.nupkg
    

最後發布頂層套件,確保使用者安裝工具時,所有參考的 RID 專用套件皆可用。 如果使用者在所有 RID 套件發布前安裝了你的工具,安裝將會失敗。

安裝與執行工具

工具是否使用RID專屬封裝,是對使用者透明的實作細節。 安裝和執行工具的方式相同,不論工具開發者是否選擇採用 RID 專屬的包裝。

若要全域安裝工具,請依照下列步驟進行:

dotnet tool install -g mytool

安裝完成後,您可以直接呼叫:

mytool

你也可以使用 dnx 輔助工具,其運作方式類似 npx 於 Node.js 生態系:如果工具尚未存在,它會以單一手勢下載並啟動:

dnx mytool

當工具使用 RID 專屬封裝時,.NET CLI 會自動選擇適合你平台的封裝。 你不需要指定 RID——CLI 會從你的系統推斷出它,並下載相應的 RID 專屬套件。

另請參閱