# 如何將 SCD 部署的 .NET Core 應用程式封裝單一可執行檔 (Warp)

我們知道 .NET Core 應用程式有兩種部署方式，一種叫 FDD (框架相依的部署)，另一種叫 SCD (自封式部署)。當使用 SCD 部署的時候，可以直接指定平台(RID)進行封裝，不過缺點是**檔案數量**與**檔案大小**都非常驚人，唯一的好處就是目的電腦不用安裝 .NET Core Runtime 就能執行程式。本篇文章我將介紹一套用 [Rust](https://www.rust-lang.org/) 程式語言寫成的 [Warp](https://github.com/dgiagio/warp) 工具，幫助你將檔案封裝成單一執行檔。

### 架構介紹

[Warp](https://github.com/dgiagio/warp) 是一套跨平台工具，其中包含兩個主程式：`warp-runner` 與 `warp-packer`。其中 `warp-packer` 用來將現有的 Node.js 或 .NET Core 應用程式封裝成**單一執行檔**，而 `warp-runner` 則是內建在這個由 `warp-packer` 建立的**單一執行檔**內，用來執行你的主程式。

簡單來說，`warp-packer` 是一支工具程式，它會將你**要部署的所有檔案**壓縮起來，包含主程式與所有相依的檔案，然後連同 `warp-runner` 一起封裝到一個**單一可執行檔**中。當要執行這支**單一可執行檔**的時候，`warp-runner` 會先將所有檔案解壓縮，放置到**本機快取資料夾**中，然後自動找到**主程式**來執行。

> 本機快取資料夾在不同平台的路徑分別是：
> 
> -   Linux: `$HOME/.local/share/warp/packages`
> -   macOS: `$HOME/Library/Application Support/warp/packges`
> -   Windows: `%LOCALAPPDATA%\warp\packages`

基於這個架構，其實不只有 Node.js 或 .NET Core 可以拿來封裝，就連 Java、Python 都可以用這套工具來封裝應用程式。

### 將 .NET Core 透過 SCD 部署的程式打包成可在 Windows 執行的單一執行檔

建立專案並使用 SCD 發行：

```bash
dotnet new console -n c1
cd c1
dotnet publish -c Release -r win10-x64
```

預設發行的路徑會在：`bin\Release\netcoreapp2.2\win10-x64\publish\`

接著下載 `warp-packer.exe` 工具，用來將發行的檔案封裝成單一可執行檔：

-   PowerShell 命令
    
    ```ps
    [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"; Invoke-WebRequest https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe -OutFile warp-packer.exe
    ```
    
-   命令提示字元 (Cmd)
    
    ```bash
    powershell -Command "[Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11, tls'; Invoke-WebRequest https://github.com/dgiagio/warp/releases/download/v0.3.0/windows-x64.warp-packer.exe -OutFile warp-packer.exe
    ```
    

然後透過 `warp-packer.exe` 工具產生單一執行檔：

```bash
.\warp-packer --arch windows-x64 --input_dir bin\Release\netcoreapp2.2\win10-x64\publish\ --exec c1.exe --output c1.exe
```

最後，在當前目錄下就會看到一個新的 `c1.exe` 執行檔，這個檔案由於有壓縮過，所以會比 SCD 封裝的檔案還小一點。接著直接執行它：

```bash
c1.exe
```

第一次執行的時候由於要先解壓縮，所以執行時間會久一些。不過第一次執行完之後，速度就跟直接執行 .NET Core 沒甚麼兩樣，因為所有檔案已經解壓縮到**本機快取資料夾**下！

### 在 Linux 或 macOS 封裝用 SCD 部署的 .NET Core 應用程式

其實在 [Warp](https://github.com/dgiagio/warp) 網站都有詳述這套工具在不同平台的使用方式，使用方是完全一樣，不外乎三個步驟：

1.  下載
2.  封裝 ( 在 `--arch` 參數要設定 `linux-x64` 或 `macos-x64` 架構 )
3.  執行

```
warp-packer 0.3.0
Diego Giagio <diego@giagio.com>
Create self-contained single binary application

USAGE:
    warp-packer.exe --arch <arch> --exec <exec> --input_dir <input_dir> --output <output>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -a, --arch <arch>              Sets the architecture.
                                   Supported: ["windows-x64", "linux-x64", "macos-x64"]
    -i, --input_dir <input_dir>    Sets the input directory containing the application and dependencies
    -e, --exec <exec>              Sets the application executable file name
    -o, --output <output>          Sets the resulting self-contained application file name
```

### 未來展望

這套工具其實不是理想的解決方案，真正理想的解決方案應該是微軟官方的 [CoreRT](https://github.com/dotnet/corert/blob/master/Documentation/intro-to-corert.md) 才對。

[CoreRT](https://github.com/dotnet/corert/blob/master/Documentation/intro-to-corert.md) 是一套全新的 .NET Core 執行環境，專門用來實現 .NET Core 的 AOT (ahead of time compilation) 編譯，讓編譯出來的檔案可以直接原生執行在不同平台。

不過目前 CoreRT 還在 Alpha 階段，還不建議在生產環境使用，但非常值得期待。我實際測試過，一個 .NET Core 專案透過 SCD 發行，需要部署的檔案數量有 217 個，檔案總大小為 66.1MB 左右。但若改用 CoreRT 進行 AOT 編譯，只會產生一個 `*.exe` 與一個 `*.pdb` 檔，該執行檔則只有 3.7MB 而已，而且程式的啟動速度極快，相當驚人！

### 相關連結

-   [dgiagio/warp: Create self-contained single binary applications](https://github.com/dgiagio/warp)
    -   [Releases · dgiagio/warp](https://github.com/dgiagio/warp/releases)
-   [Intro to CoreRT](https://github.com/dotnet/corert/blob/master/Documentation/intro-to-corert.md)
