前幾天聊到我喜歡將小工具程式編譯成單一檔案,免安裝,不必解壓縮 DLL,整個工具就一個 EXE 檔,放到桌面上點兩下就能用,這是最棒的部署方式! 文章裡提到 .NET 5 內建嵌入參照 DLL 功能,且不像 .NET Core 3.1 得將內嵌參照 DLL 寫成實體檔暫存,實現真正的單檔執行。這篇文章會實際體驗 .NET 5 的單檔編譯功能。

好孩子要先看操作說明書,MSDocs 文件 - Single file deployment and executable 的說明很完整,摘要重點如下:

  1. .NET Core/.NET 5 程式有兩種打包模式:Framework-Depedent Deployment Model (執行環境已安裝 .NET Core/.NET 5 Runtime 或 SDK) 以及 Self-Contained Appliations (自備 Runtime DLL,執行環境不用預先裝 .NET Core/.NET 5 Runtime 或 SDK,但檔案數很多,體積也大,50MB 起跳)。這兩種模式都支援單檔輸出,也支援 ReadyToRun (預先完成 JIT 編譯,可加快程式啟動速度,但必須先確認部署對象為 Linux/Windows/macOS、x86/x64/ARM,啟用 R2R 後 EXE 檔案會變大)。而 .NET 5 還支援實驗性質的 Trim 功能,可偵測並排除 Self-Contained Applictation 沒用到 Runtime 或 Framework DLL 減少資料量。
  2. 在單檔部署模式下某些 API 行為會改變或無法使用,包含:
    • Assembly.Location 傳回空字串 (可改用 AppContext.BaseDirectory 取代)
    • Module.FullQualfieldName 傳回 <Unknown> 或抛出例外
    • Mudule.Name 傳回 <Unknown>
    • Assembly.GetFile、Assembly.GetFiles 抛出 IOException
    • Assembly.CodeBase、Assembly.EscapedCodeBase 抛出 PlatformNotSupportedException.
    • AssemblyName.CodeBase、AssemblyName.EscapedCodeBase 傳回 null
  3. Self-Contained Single-File 模式需額外提供 mscordbi.dll/mccordbi.so 以進行偵錯
  4. 單檔部署預設不包含原生 DLL,但有個旗標 IncludeNativeLibrariesForSelfExtract 可將原生 DLL 也嵌入 EXE,執行時再解到暫存目錄使用。
  5. PDB 檔預設獨立存在,在 csproj 設定 <DebugType>embedded</DebugType> 可將它也併進 EXE。
  6. 透過 csproj <ExcludeFromSingleFile>true</ExcludeFromSingleFile> 可排除特定 DLL 不要內嵌

背景知識學完開始實際演練。以下以 Visual Studio 2019 為例,主要控制介面在 Publish Profile 的 Configuration 設定:

Target framework 選 net5.0
Deployment mode 可選 Self-contained 或 Framework-dependent
Target runtime 則依要部署的作業系統選 win-x86、win-x64、linux-x64... 等等

下方 File publish options 是重點:

Produce single files 是否啟用單檔部署(將參照 DLL 包進 EXE 檔)?
Enable ReadyToRun complication 是否啟用 R2R?
Trim unused assemblies (只適用單檔部署)是否排除沒用到的 Runtime 或 Framework DLL?

實測不同選項的效果,以 Self-Contained 模式為例,若不開啟單檔部署,編譯輸出檔案數高達 233 個(含 EXE、DLL、JSON 檔):

啟用單檔部署後,大部分檔案都已併入 Net5SingleFile.exe,e_sqlite3.dll 是 SQLite 的原生 DLL,預設不會包進去,另外還有幾個檔案 clrcompression.dll、clrjit.dll、coreclr.dll、mscordaccore.dll 是 .NET 5 Runtime / Framework 用到的原生 DLL:

開啟 ReadyToRun 後,Net5SingleFile.exe 變胖 (由 53,988KB 增加到 54,945KB):

啟用 Trim unused assemblies,Net5SingleFile.exe 縮小到 44,664 KB:

為了實現真正的單一檔案,修改 csproj 加入 IncludeNativeLibrariesForSelfExtract、DebugType true,達成一檔獨大 66.6MB。(註:未開 Trim unused assemblies)

如果確定待部署環境有裝 .NET 5 Runtime 或 SDK,改用 Framework-dependent 模式,EXE 檔案可縮小到 7MB 有找。

體驗完 .NET 5.0 的單檔部署,系統內建就是不一樣,再加上 Visual Studio 的火力支援,操作比原本預期方便流暢,簡單! 快速! 好用到咩噗。整體使用下來,.NET 5.0 的成熟完整度令我驚喜,未來要開發小工具,我會優先考慮用 .NET 5.0 來寫。

Introdcing to .NET 5.0 single-file deployment features.


Comments

Be the first to post a comment

Post a comment