6

使用 dotnet 命令列工具發行 .NET 6 專案

 3 years ago
source link: https://blog.darkthread.net/blog/dotnet6-publish-notes/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
使用 dotnet 命令列工具發行 .NET 6 專案-黑暗執行緒

.NET 5 時介紹過用 Visual Studio 發行 .NET 5 專案,.NET 6 這篇改整理 .NET CLI (dotnet 命令列工具) 發行技巧。

主要參考來源為微軟文件 - .NET application publishing overview

dotnet publish 產生的執行程式有兩種形式:可執行檔 (在 Windows 為 .exe,在 Linux/macOS 則是與專案同名的無附檔名檔案) 或跨平台程式檔 (.dll,用 dotnet appName.dll 執行)。

可執行檔種類取決執行 dotnet publish 所在的平台,加上 -r win-x64、-r linux-x64 則可產生特定平台用的可執行檔,win-x64 是所謂 RID ( .NET 6 支援的 RID 清單),不同平台又再有 Self-Contained 及 Framework-Dependent 兩種選擇。

  • Self-Contained
    部署結果包含 .NET Runtime,部署對象不需先安裝 .NET SDK 或 .NET Runtime,缺點是檔案較多,且每支程式重複自帶 Runtime 會多佔用磁碟空間
  • Framework-Dependent
    只包含程式及其參照程式庫,部署對象必須裝好 .NET SDK 或 .NET Runtime

由可執行檔 vs 跨平台程式檔,Self-Contained vs Framework-Dependent 兩個維度排列組合,dotnet publish 參數分別為:(適用 .NET Core 3.1、.NET 5/6,排除 .NET 2.1)

  • Framework-Dependent 跨平台程式檔
    dotnet publish -c Release -p:UseAppHost=false
  • Framework-Dependent 可執行檔
    dotnet publish -c Release -r <RID> --no-self-contained
    dotnet publish -c Release -r <RID> --self-contained false
    dotnet publish -c Release (未指定 -r 時,產出目前所在平台的可執行檔)
  • Self-Contained 可執行檔
    dotnet publish -c Release -r <RID> --self-contained
  • Self-Contained 跨平台程式檔
    無此組合

先列出主要可用參數,後面再補充說明

  • PublishSingleFile
  • UseAppHost
  • IncludeNativeLibrariesForSelfExtract
  • IncludeAllContentForSelfExtract
  • IncludeSymbolsInSingleFile
  • PublishReadyToRun
  • EnableCompressionInSingleFile

以上參數有兩種設定方式,直接寫在 .csproj:

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <RootNamespace>dotnet_publish_test</RootNamespace>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishSingleFile>false</PublishSingleFile>
  </PropertyGroup>

或是 dotnet publish 加上 -p:PublishSingleFile=true 設定,它將覆寫 .csproj 裡的設定:

dotnet publish -c Release -r win-x64 --no-self-contained -p:PublishSingleFile=true

簡單介紹各參數用法。

如果覺得 Publish 結果包含一堆 DLL 太亂,有個 PublishSingleFile 參數可將所有 DLL 整併成單一執行檔,部署時一檔搞定。但 --self-contained 時會內含 .NET Runtime,執行檔大小常超過 70MB,有個 PublishTrimmed 參數可排除沒用到 DLL,執行檔有時可瘦身一半以上。但偵測未用 DLL 很難完全精準,瘦身版務必仔細測試再上線。

PublishSingleFile 預設只會整併 .NET 寫的 DLL (Managed DLL),DLL 依附的原生函式庫仍保留獨立檔案形式,IncludeNativeLibrariesForSelfExtract 參數能將這部分也合併進執行檔,執行時原生 DLL 檔將匯出到特定目錄(在 Windows 為 %TEMP%/.net、Linux 及 MacOS 為 $HOIME/.net,或可使用 DOTNET_BUNDLE_EXTRACT_BASE_DIR 環境變數指定)。依實測,沒用到原生 DLL,PublishSingleFile 併入的 Managed DLL 可直接載入記憶體使用,檔案不需落地;但如用到 IncludeNativeLibrariesForSelfExtract 併入原生 DLL,則需一併指定 IncludeAllContentForSelfExtract,將原生 DLL 跟參照 .NET DLL 都匯出到 %TEMP%/.net、$HOME/.net 或 DOTNET_BUNDLE_EXTRACT_BASE_DIR 指定目錄,才能正確載入原生 DLL。實地觀察可在 .net 目錄看到匯出檔案:

PublishSingleFile 合併成單一檔案後,仍會有 .pdb 檔,使用 IncludeSymbolsInSingleFile 則可合併 .pdb 內容,實現真正單一檔案。

若有特殊 DLL 檔不要併入執行檔但要放進發行目錄,可修改 csproj:

<ItemGroup>
  <Content Update="Plugin.dll">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
  </Content>
</ItemGroup>

另外,PublishReadyToRun 參數可指定預先完成 JIT 編譯,程式碼體積會變大,但可節省程式啟動時間。

.NET 6 起,多了 EnableCompressionInSingleFile 參數可壓縮併入執行檔的 DLL,進一步縮小體積。但程式啟動時需先在記憶體中解壓縮,要付出效能上的代價,建議視應用情境取捨。

[2021-12-14 補充] dotnet publish 預設包含編譯程序,還有個 --no-build 參數可直接使用 obj 下的內容。若發行程序有使用混淆器處理 obj 目錄檔案,--no-build 可避免混淆過的檔案被覆寫,但此時不可用 PublishTrimmed。(感謝讀者 Peter Cheng 分享)

最後來個範例整理:

  1. dotnet publish -c Release
    不含 .NET Runtime,同時產出 .dll 及 .exe (或是所在平台的可執行檔),部署對象需安裝 .NET Runtime/SDK
  2. dotnet publish -c Release -p:UseAppHost=false
    不含 .NET Runtime,只產出 .dll,部署對象需安裝 .NET Runtime/SDK,使用 dotnet appName.dll 執行
  3. dotnet publish -c Release -r win-x64 --self-contained
    包含 Windows x64 .NET Runtime 以及 .exe 可執行檔
  4. dotnet publish -c Release -r linux-x64 --no-self-contained
    產生 64 位元 Linux 用的 .exe 可執行檔,部署對象需安裝 .NET Runtime/SDK
  5. dotnet publish -c Release -r linux-x64 --self-contained
    包含 64 位元 Linux .NET Runtime 以及 Linux 用的可執行檔
  6. dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true
    將 Windows x64 .NET Runtime、參照的 .NET .dll,以及程式本身打包成一個 .exe 可執行檔 (大小可能超過 70MB),但參照程式庫附屬的原生程式庫仍維持個別檔案
  7. dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:IncludeAllContentForSelfExtract=true 同 6,但將參照程式庫附屬的原生程式庫也包進 .exe,實測 IncludeNativeLibrariesForSelfExtract 需配合 IncludeAllContentForSelfExtract 參數才能正確執行
  8. dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -p:PublishTrimmed=true
    同 6,但進行程式瘦身,剔除沒用到的程式庫部分,.exe 甚至可縮小一半以上。但有可能出現誤刪,部署前請慎重測試

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK