ONNX Runtime 中的依赖项管理
本文档补充了 CMake 的 “使用依赖项指南”,重点关注 ONNX Runtime。ONNX Runtime 使用了许多开源 C++ 库。例如,abseil、protobuf、re2、onnx 等。有三种主要方法可以为 ONNX Runtime 构建获取它们
- 使用 VCPKG(推荐)
- 从源代码构建所有内容
- 使用预安装的软件包(高级用户)
以下是快速比较
支持网络隔离1 | 支持二进制缓存2 | 支持交叉编译 | 开发状态 | 漏洞管理 | |
---|---|---|---|---|---|
VCPKG | 是 | 是 | 良好 | 进行中 | 由 ONNX Runtime 团队提供 |
从源代码构建所有内容 | 部分支持3 | 否 | 即用即用4 | 完全支持 | 由 ONNX Runtime 团队提供 |
使用预安装的软件包 | 是 | 是 | 难以设置 | 某些软件包无法通过这种方式处理 | 由您的软件包管理器提供 |
如果您的软件需要满足美国总统关于改进国家网络安全的第 14028 号行政命令 (EO),我们强烈建议使用 VCPKG。
VCPKG
什么是 VCPKG?
VCPKG 是一个免费且开源的 C/C++ 包管理器,由 Microsoft 和 C++ 社区维护。它主要由 Microsoft 的 Visual Studio 团队开发。它可以帮助开发人员以简单且声明式的方式管理其 C++ 依赖项。它基于 CMake,可以集成到您的 CMake 项目中,也可以在构建之前单独使用。ONNX Runtime 使用前一种方法,称为清单模式。
使用 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,步骤如下
- 安装 Git 并运行“git clone https://github.com/microsoft/vcpkg.git”
- 导航到 VCPKG 目录并运行引导脚本
- 在 Windows 上:bootstrap-vcpkg.bat
- 在其他系统上:bootstrap-vcpkg.sh
如果脚本找不到某些先决条件,请安装缺少的软件并重试。
- 将环境变量 VCPKG_INSTALLATION_ROOT 设置为 VCPKG 目录,然后返回到 ONNX Runtime 源代码文件夹并再次运行构建脚本。有关更多详细信息,请参阅:https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/get_started/includes/setup-vcpkg.md。如果您在引导 VCPKG 时遇到问题,请联系 VCPKG 团队寻求支持。
VCPKG 端口、三元组和工具链
VCPKG 中的软件包称为 VCPKG 端口。端口的构建脚本可以在 http://github.com/microsoft/vcpkg/tree/master/ports 中找到。ONNX Runtime 也有一些自定义端口,托管在 https://github.com/microsoft/onnxruntime/tree/main/cmake/vcpkg-ports。自定义端口的优先级高于官方端口。端口目录中的文件包含特定于该端口的配置。例如,是否启用 CUDA。
三元组是一个 cmake 文件,其中包含应用于当前构建中所有端口的配置。例如,是否启用 C++ 异常。它仅用于构建依赖项。它不会影响 ONNX Runtime 源代码的构建标志。tools/ci_build/build.py 中设置的编译器标志和 cmake 变量仅适用于 ONNX Runtime,不适用于 vcpkg 端口。因此,我们需要使用自定义三元组文件来使设置保持一致。
工具链文件用于设置编译器/链接器等,功能更强大。ONNX Runtime 通常使用标准的 vcpkg 工具链文件,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 的支持仍在开发中。它不支持以下场景
- 最小化构建
- iOS 构建
- Windows WebGPU 原生构建
并且某些依赖项尚未由 VCPKG 管理。例如,Dawn。
在为 webassembly 构建时,它假定始终设置“–enable_wasm_simd”标志和“–enable_wasm_threads”标志。它支持的构建变体比第二种模式(从源代码构建所有内容)少得多
此外,在这种模式下,用于运行 tools/ci_build/build.py 的 python 解释器可能与用于构建 VCPKG 端口的解释器不同。这种不一致可能会导致问题。因此,如果您安装了多个 Python 版本,我们建议将所需的版本添加到您的 PATH
的开头,将其设置为默认版本。
它尚不支持设置 VC 工具集版本或 Windows SDK 版本。
对 Windows ARM64EC(包括 ARM64X)的支持是实验性的,尚未经过充分测试。
虽然标准 cmake 有 4 种不同的构建类型(Debug、Release、RelWithDebInfo 和 MinSizeRel),但 vcpkg 仅支持两种。因此,当为 RelWithDebInfo 或 MinSizeRel 构建 ONNX Runtime 时,您可能会看到二进制文件大小增加。可以通过在自定义三元组文件中进行更多自定义来解决此问题。
我是 EP 开发人员。我是否必须将所有依赖项转换为 vcpkg 端口?
如果依赖项被 Microsoft 发布的 ONNX Runtime 发行包使用,那么答案肯定是肯定的。否则,我们可以根据具体情况进行讨论。
更新 VCPKG 端口的流程
首先,请检查该端口是否是 cmake/vcpkg/vcpkg-ports
目录中的自定义端口。如果是,您需要在那里更新它。并且您至少需要更新两个地方: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)中,则需要使用此方法。
但是,它有一些注意事项
- ONNX Runtime 具有依赖项的本地补丁,这些补丁不会应用于您预安装的库。大多数补丁对于基本功能不是必需的。
- 如果您安装的库版本与 ONNX Runtime 期望的版本不同,则构建脚本无法警告您。这可能会导致奇怪的构建失败。
- 每个库都可以通过不同的方式构建。例如,ONNX Runtime 期望 ONNX 使用 “-DONNX_DISABLE_STATIC_REGISTRATION=ON” 构建。如果您从某处获得了预构建的 ONNX 库,则很可能不是以这种方式构建的。
因此,我们说它是为高级用户准备的。