ONNX Runtime 中的依賴項管理

本文件以 ONNX Runtime 為重點,為 CMake 的“使用依賴項指南”提供了額外資訊。ONNX Runtime 使用了許多開源 C++ 庫。例如,abseil、protobuf、re2、onnx 等。有三種主要方式可以獲取它們以用於 ONNX Runtime 構建:

  1. 使用 VCPKG(推薦)
  2. 從原始碼構建所有內容
  3. 使用預安裝包(適用於高階使用者)

下面是一個快速比較

  支援網路隔離1 支援二進位制快取2 支援交叉編譯 開發狀態 漏洞管理
VCPKG 良好 進行中 由 ONNX Runtime 團隊提供
從原始碼構建所有內容 部分支援3 可以直接使用4 完全支援 由 ONNX Runtime 團隊提供
使用預安裝包 難以設定 有些包無法透過此方式處理 由你的包管理器提供

如果你的軟體需要符合美國總統關於改善國家網路安全的行政命令 (EO) 14028,我們強烈建議使用 VCPKG。

VCPKG

什麼是 VCPKG?

VCPKG 是一個由微軟和 C++ 社群維護的免費開源 C/C++ 包管理器。它主要由微軟的 Visual Studio 團隊開發。它幫助開發人員以簡單和宣告式的方式管理其 C++ 依賴項。它基於 CMake,可以整合到你的 CMake 專案中,也可以在構建前單獨使用。ONNX Runtime 使用前者,即清單模式(manifest mode)。

使用 VCPKG 的先決條件

有關支援的主機,請參閱 VCPKG 文件:https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/concepts/supported-hosts.md。例如,在 Ubuntu 上,你需要安裝以下軟體包:apt-get install git curl zip unzip pkgconfig ninja-build

如何使用 VCPKG 構建 ONNX Runtime

只需在你的構建命令中新增“–use_vcpkg”。構建指令碼 (build.py) 會將一個新的 vcpkg 倉庫檢出到你的構建目錄中,並引導 vcpkg 工具。如果你遇到任何錯誤,你可能需要使用以下步驟手動獲取 VCPKG:

  1. 安裝 Git 並執行“git clone https://github.com/microsoft/vcpkg.git”
  2. 導航到 VCPKG 目錄並執行引導指令碼
    • 在 Windows 上:bootstrap-vcpkg.bat
    • 在其他系統上:bootstrap-vcpkg.sh

    如果指令碼找不到某些先決條件,請安裝缺失的軟體並重試。

  3. 將環境變數 VCPKG_INSTALLATION_ROOT 設定為 VCPKG 目錄,然後回到 ONNX Runtime 原始碼資料夾並再次執行構建指令碼。更多詳細資訊請參閱:https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/get_started/includes/setup-vcpkg.md。如果你在引導 VCPKG 時遇到問題,請聯絡 VCPKG 團隊尋求支援。

VCPKG ports、triplets 和 toolchains

VCPKG 中的一個包被稱為 VCPKG port。port 的構建指令碼可以在 http://github.com/microsoft/vcpkg/tree/master/ports 找到。ONNX Runtime 也有一些自定義 port,它們託管在 https://github.com/microsoft/onnxruntime/tree/main/cmake/vcpkg-ports。自定義 port 具有比官方 port 更高的優先順序。port 目錄中的檔案包含特定於該 port 的配置。例如,是否啟用 CUDA。

triplet 是一個 cmake 檔案,包含應用於當前構建中所有 port 的配置。例如,是否啟用 C++ 異常。它僅用於構建依賴項。它不會影響 ONNX Runtime 原始碼的構建標誌。在 tools/ci_build/build.py 中設定的編譯器標誌和 cmake 變數僅適用於 ONNX Runtime,不適用於 vcpkg port。因此,我們需要使用自定義 triplet 檔案來保持設定一致。

toolchain 檔案用於設定編譯器/連結器等,功能更強大。ONNX Runtime 通常使用標準的 vcpkg toolchain 檔案,WebAssembly 構建除外。

獨特功能

與本頁列出的其他解決方案相比,VCPKG 提供了一些我們非常希望擁有的獨特功能

VCPKG 為交叉編譯提供了更好的支援。例如,ONNX Runtime 依賴於 ONNX。ONNX 的原始碼有一些 *.proto 檔案。從原始碼構建 ONNX 時,我們需要使用 protoc 從 *.proto 檔案生成 C++ 原始檔。因此,我們需要為宿主作業系統構建 protoc 和 protoc 的依賴項。例如,如果我們在 x64 機器上構建 arm64 包,我們需要為 x64 而不是 arm64 構建 protoc。而且因為 protoc 依賴於 libprotobuf,我們必須為每個 CPU 架構構建兩次 libprotobuf。無論是否使用 vcpkg,都必須構建兩次。CMake 不處理這種情況,這增加了我們構建系統的複雜性。現在我們可以使用 vcpkg 解決這個問題。它開箱即用,執行良好。

使用 VCPKG,我們只需要宣告根依賴項。在轉向 VCPKG 之前,我們需要將所有傳遞依賴項新增到 cmake/deps.txt 和 cmake/external 資料夾下的 cmake 檔案中,以滿足網路隔離要求(這樣我們可以輕鬆找到所有下載 URL)和 元件檢測 要求。現在不再需要了,因為 VCPKG 內建支援資產快取和 SBOM 生成

VCPKG 強制一個庫只能有一個版本。例如,onnxruntime_provider_openvino.dll 和 onnxruntime.dll 使用的 protobuf 庫必須完全相同。雖然這比必要的更嚴格,但它有助於防止 ODR 違規問題。與處理因使用同一庫的多個版本而產生的潛在衝突和不一致相比,它提供了更多好處。

限制

目前,對 vcpkg 的支援仍在開發中。它不支援以下場景:

  1. 最小化構建
  2. iOS 構建
  3. Windows WebGPU 原生構建

此外,一些依賴項尚未由 VCPKG 管理。例如,Dawn。

當為 WebAssembly 構建時,它假定“–enable_wasm_simd”標誌和“–enable_wasm_threads”標誌始終已設定。它支援的構建變體比第二種模式(從原始碼構建所有內容)少得多

此外,在此模式下,用於執行 tools/ci_build/build.py 的 Python 直譯器可能與用於構建 VCPKG port 的直譯器不同。這種不一致可能會導致問題。因此,如果你有多個 Python 安裝,我們建議將所需的版本新增到 PATH 的開頭,以將其設定為預設值。

它尚不支援設定 VC 工具集版本或 Windows SDK 版本。

對 Windows ARM64EC(包括 ARM64X)的支援是實驗性的,尚未經過充分測試。

標準 cmake 有 4 種不同的構建型別(Debug、Release、RelWithDebInfo 和 MinSizeRel),而 vcpkg 只支援兩種。因此,當你為 RelWithDebInfo 或 MinSizeRel 構建 ONNX Runtime 時,可能會發現二進位制檔案大小增加。這個問題可以透過在自定義 triplet 檔案中進行更多自定義來解決。

我是 EP 開發者。我是否必須將所有依賴項轉換為 vcpkg port?

如果依賴項被微軟釋出的 ONNX Runtime 釋出包使用,那麼肯定需要。否則我們可以逐案討論。

更新 VCPKG port 的過程

首先,請檢查該 port 是否是 cmake/vcpkg/vcpkg-ports 目錄中的自定義 port。如果是,你需要在此處更新它。並且至少需要更新兩個地方:vcpkg.json 檔案中的版本號,以及 ports.cmake 檔案中的 SHA512 雜湊值。如果你不知道要放入哪個 SHA512 值,你可以稍微修改當前雜湊值(翻轉幾個位元組),然後使用“–use_vcpkg”標誌構建 ONNX Runtime(不要使用額外的標誌來啟用任何資產快取),然後 vcpkg 將生成一條錯誤訊息,告訴你它期望的實際雜湊值。你可能還需要更新補丁檔案。你可以克隆庫的倉庫,然後檢出你正在更新的新版本,然後應用舊的補丁檔案,解決衝突,最後使用“git diff”生成一個新的補丁檔案來覆蓋現有的補丁檔案。

如果依賴項來自 VCPKG 的官方登錄檔(在 https://github.com/microsoft/vcpkg 中),那會容易得多。只需開啟 vcpkg-configuration.json 並將基線提交 ID 更新為最新的 vcpkg 提交 ID。

然後建立一個 PR。ONNX Runtime 開發團隊的成員將審查你的更改,將依賴項複製到內部位置並觸發拉取請求管道。如果一切順利,我們將合併你的更改。

從原始碼構建所有內容

在你的構建命令中新增“–cmake_extra_defines FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER”。當 VCPKG 未啟用時,我們使用 CMake 的 FetchContent 管理依賴項。所有此類依賴項都列在 cmake/deps.txt 中,允許你自定義版本和下載 URL。這對於滿足網路隔離要求或升級/降級庫版本非常有用。在 ONNX Runtime 的 CMake 檔案中宣告依賴項時,如果提供了 FIND_PACKAGE 引數,FetchContent 將使用 CMake 的 FindPackage 模組從系統位置查詢依賴項。新增 –cmake_extra_defines FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER 以停用此行為。

使用預安裝包

這是從原始碼構建 ONNX Runtime 時的預設模式。如果構建既沒有‘–use_vcpkg’也沒有‘–cmake_extra_defines FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER’,它將處於此模式。這是因為 FetchContent 是各種 CMake 依賴提供程式的包裝器。預設情況下,如果為依賴項提供了 FIND_PACKAGE 引數,它傾向於使用 find_package。如果你將 ONNX Runtime 整合到包管理器(如 dnf)中,你需要使用這種方法。

然而,它有一些注意事項

  1. ONNX Runtime 為依賴項提供了本地補丁,這些補丁將不會應用於你預安裝的庫。大多數補丁對於基本功能來說不是必需的。
  2. 如果你安裝的庫版本與 ONNX Runtime 期望的不同,構建指令碼無法警告你。這可能會導致奇怪的構建失敗。
  3. 每個庫都可以以不同的方式構建。例如,ONNX Runtime 期望 ONNX 是使用“–DONNX_DISABLE_STATIC_REGISTRATION=ON”構建的。如果你從其他地方獲得了預構建的 ONNX 庫,很可能它不是以這種方式構建的。

因此我們說它適用於高階使用者。

  1. ONNX Runtime 可以在隔離的網路環境(無需訪問公共網際網路)中構建嗎? 

  2. 如果依賴庫保持不變,它們是否只需要構建一次? 

  3. 例如,ONNX Runtime 的原生 WebGPU 不支援在隔離網路中構建。因為該 EP 依賴於 Dawn,這很難處理。 

  4. 它今天有效,但 ONNX Runtime 有許多 EP 和依賴項。隨著時間的推移,維護當前狀態變得困難。