2、环境搭建:安装C++开发环境、ONNX Runtime库、依赖管理

2.1 核心原理:为什么环境搭建决定部署成败

ONNX Runtime 的 C++ 部署并非简单的“复制几个文件”,而是一套涉及编译器 ABI 兼容性、动态链接库搜索路径、依赖传递关系的工程体系。很多初学者在 Python 环境中运行模型毫无问题,一旦切换到 C++ 就遇到“找不到 onnxruntime.dll”或“链接错误 LNK2019”,根源往往在于环境搭建阶段埋下的隐患。

理解环境搭建的核心,需要抓住三个关键点:

  • ABI 兼容性:ONNX Runtime 的 C++ API 使用 C++11 标准导出,但不同编译器(MSVC、GCC、Clang)生成的符号修饰规则不同。使用 MSVC 编译的库无法被 MinGW 直接链接,反之亦然。
  • 运行时依赖:ONNX Runtime 动态库(.dll/.so/.dylib)本身依赖系统运行库(如 VC++ Redistributable、libstdc++),且需要正确设置动态库搜索路径。
  • 头文件与库版本匹配:头文件(onnxruntime_cxx_api.h)中的 API 声明必须与库文件的实际导出符号严格对应,混用不同版本会导致难以排查的运行时崩溃。
经验法则:在 Windows 上优先选择 MSVC(Visual Studio)工具链,在 Linux 上优先选择 GCC 9+ 或 Clang 10+,并始终使用与 ONNX Runtime 官方发布页一致的编译配置。
ONNX Runtime C++ 环境依赖关系全景 编译器工具链 MSVC (Windows) GCC / Clang (Linux) C++11/14/17 标准 ONNX Runtime 库 onnxruntime.dll / .so onnxruntime_cxx_api.h CPU / CUDA / TensorRT EP 依赖管理 CMake + FetchContent vcpkg / Conan 动态库搜索路径 ABI 链接 最终部署产物 可执行文件 + onnxruntime 动态库 + 模型文件 任何一环缺失或版本不匹配,都会导致编译失败或运行时崩溃

2.2 方法流程:Windows + Linux 双平台搭建步骤

2.2.1 Windows 平台(MSVC + Visual Studio 2022)

Windows 下推荐使用 Visual Studio 2022 作为 IDE,配合 CMake 构建项目。ONNX Runtime 官方发布的 Windows 包分为 CPU 版和 GPU 版(需 CUDA),下载时需注意选择 win-x64 架构。

# 1. 下载 ONNX Runtime Windows 包(以 v1.17.1 为例)
# 访问 https://github.com/microsoft/onnxruntime/releases
# 选择: onnxruntime-win-x64-1.17.1.zip

# 2. 解压到指定目录,例如 C:\libs\onnxruntime
# 目录结构如下:
C:\libs\onnxruntime\
├── include\          # 头文件
│   ├── onnxruntime_cxx_api.h
│   └── onnxruntime_c_api.h
├── lib\              # 静态库与导入库
│   ├── onnxruntime.lib
│   └── onnxruntime.dll
└── bin\              # 运行时动态库
    └── onnxruntime.dll

在 Visual Studio 中配置项目属性:

  • C/C++ → 常规 → 附加包含目录:添加 C:\libs\onnxruntime\include
  • 链接器 → 常规 → 附加库目录:添加 C:\libs\onnxruntime\lib
  • 链接器 → 输入 → 附加依赖项:添加 onnxruntime.lib
  • 调试 → 环境:设置 PATH=C:\libs\onnxruntime\bin;%PATH%(或将 onnxruntime.dll 复制到 exe 同目录)

2.2.2 Linux 平台(GCC + CMake)

Linux 下推荐使用 CMake 的 FetchContent 或 find_package 方式管理依赖。以下展示使用 FetchContent 自动下载并编译 ONNX Runtime 的配置:

# CMakeLists.txt 核心片段
cmake_minimum_required(VERSION 3.18)
project(OnnxDeployDemo CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 方式一:FetchContent 自动拉取(适合快速原型)
include(FetchContent)
FetchContent_Declare(
  onnxruntime
  URL https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-linux-x64-1.17.1.tgz
  URL_HASH SHA256=your_checksum_here
)
FetchContent_MakeAvailable(onnxruntime)

# 方式二:find_package(需先安装到系统)
# find_package(onnxruntime REQUIRED)

add_executable(demo main.cpp)
target_link_libraries(demo PRIVATE onnxruntime::onnxruntime)

若使用 vcpkg 管理依赖,安装命令更为简洁:

# 安装 vcpkg 后执行
vcpkg install onnxruntime:x64-linux
# 或 Windows 下
vcpkg install onnxruntime:x64-windows

# 然后在 CMake 中启用工具链
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake

2.3 案例实战:最小可运行推理程序

环境搭建完成后,编写一个最小程序验证 ONNX Runtime 能否正确加载并执行模型。以下代码使用 C++ API 加载一个简单的 ONNX 模型并执行前向推理:

#include <onnxruntime_cxx_api.h>
#include <vector>
#include <iostream>

int main() {
    // 1. 创建环境(日志级别为警告)
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test_env");
    
    // 2. 创建会话选项并设置优化级别
    Ort::SessionOptions session_options;
    session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
    
    // 3. 加载模型(请替换为实际模型路径)
    const char* model_path = "model.onnx";
    Ort::Session session(env, model_path, session_options);
    
    // 4. 获取输入输出信息
    Ort::AllocatorWithDefaultOptions allocator;
    auto input_name = session.GetInputNameAllocated(0, allocator);
    auto output_name = session.GetOutputNameAllocated(0, allocator);
    
    std::cout << "Input: " << input_name.get() << std::endl;
    std::cout << "Output: " << output_name.get() << std::endl;
    
    // 5. 构造输入张量(假设输入为 1x3x224x224 的 float 数据)
    std::vector<int64_t> input_shape = {1, 3, 224, 224};
    std::vector<float> input_data(1 * 3 * 224 * 224, 0.5f);
    
    Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(
        OrtArenaAllocator, OrtMemTypeDefault);
    
    Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
        memory_info, input_data.data(), input_data.size(),
        input_shape.data(), input_shape.size());
    
    // 6. 执行推理
    const char* input_names[] = {input_name.get()};
    const char* output_names[] = {output_name.get()};
    
    auto output_tensors = session.Run(Ort::RunOptions{nullptr},
                                      input_names, &input_tensor, 1,
                                      output_names, 1);
    
    // 7. 获取输出结果
    auto& output_tensor = output_tensors.front();
    auto output_info = output_tensor.GetTensorTypeAndShapeInfo();
    auto output_shape = output_info.GetShape();
    
    std::cout << "Output shape: ";
    for (auto dim : output_shape) std::cout << dim << " ";
    std::cout << std::endl;
    
    return 0;
}

编译命令(Linux):

g++ -std=c++17 demo.cpp -I/path/to/onnxruntime/include \
    -L/path/to/onnxruntime/lib -lonnxruntime \
    -Wl,-rpath,/path/to/onnxruntime/lib -o demo

2.4 常见误区与排障复盘

误区/错误 现象 根因分析 解决方案
混用编译器 链接错误 LNK2019 / undefined reference MSVC 与 MinGW 的符号修饰不同 统一使用 MSVC 或 GCC,不混用
忽略运行时 DLL 程序启动报“找不到 onnxruntime.dll” 动态库未在搜索路径中 将 DLL 复制到 exe 目录或设置 PATH
Debug/Release 不匹配 内存访问冲突或崩溃 ONNX Runtime 仅提供 Release 版 项目必须使用 Release 配置链接
版本混用 编译通过但运行崩溃 头文件与库版本不一致 确保 include 和 lib 来自同一版本包
CUDA 版误用 CPU 包 无法使用 GPU 执行 未安装 CUDA 版 ONNX Runtime 下载对应 CUDA 版本的包并配置 CUDA 环境
重要提醒:ONNX Runtime 官方发布的 Windows 包仅支持 MSVC 编译的 C++ 程序。若使用 MinGW 或 Cygwin,需要自行从源码编译,过程复杂且容易出错。对于生产环境,强烈建议使用 MSVC + Visual Studio 或 CMake + Ninja 工具链。

2.5 环境验证清单

完成搭建后,建议按以下清单逐项验证,确保环境万无一失:

  1. 头文件可访问:编译一个仅包含 #include <onnxruntime_cxx_api.h> 的空程序,确认无编译错误。
  2. 链接成功:链接时能正确找到 onnxruntime.lib 或 libonnxruntime.so。
  3. 运行时加载:运行程序时能加载动态库,无“DLL not found”错误。
  4. 模型推理:使用 2.3 节的最小程序加载一个真实 ONNX 模型,确认输出形状符合预期。
  5. 优化级别生效:设置 ORT_ENABLE_ALL 后,对比推理耗时,确认优化生效。