DDZZ669 发表于 2024-10-27 11:55

CMake构建实战读书笔记06-onnx查找模块



本篇来学习CMake的查找功能,并以onnxruntime库为例,来查找需要的文件。

涉及到的查找指令有:

- find_path:查找路径
- find_library:查找库文件
- find_file:查找文件
- find_package_handle_standard_args:用于在自定义模块中判断结果变量是否都已正确赋值

# 1 onnxruntime简介与下载

## 1.1 onnxruntime简介

ONNX Runtime 是一个跨平台的推理和训练机器学习加速器。

ONNX 运行时推理可以实现更快的客户体验并降低成本,支持来自深度学习框架(如 PyTorch 和 TensorFlow/Keras)的模型,以及经典的机器学习库(如 scikit-learn、LightGBM、XGBoost 等)。ONNX 运行时与不同的硬件、驱动程序和操作系统兼容,并通过利用硬件加速器(如果适用)以及图形优化和转换来提供最佳性能。

ONNX 运行时训练可以通过为现有 PyTorch 训练脚本添加一行代码,从而加快转换器模型的多节点 NVIDIA GPU 上的模型训练时间。



## 1.2 onnxruntime下载

在GitHub中onnxruntime项目的Release页面(https://github.com/microsoft/onnxruntime/releases)下载预编译包,我的是在Ununtu中测试,因此下载Linux版本的包。



下载后解压要测试代码的目录即可。

# 2 代码分析

## 2.1 Findonnxruntime.cmake

这里将此cmake分成两部分来分析,先来看第一部分:

```cmake
find_path(onnxruntime_INCLUDE_DIR onnxruntime_c_api.h
HINTS ENV onnxruntime_ROOT
PATH_SUFFIXES include)

find_library(onnxruntime_LIBRARY
NAMES onnxruntime
HINTS ENV onnxruntime_ROOT
PATH_SUFFIXES lib)

find_file(onnxruntime_VERSION_FILE VERSION_NUMBER
HINTS ENV onnxruntime_ROOT)

if(onnxruntime_VERSION_FILE)
file(STRINGS ${onnxruntime_VERSION_FILE} onnxruntime_VERSION LIMIT_COUNT 1)
endif()
```

- find_path来查找onnxruntime库中的onnxruntime_c_api.h文件路径,并将查找结果存入onnxruntime_INCLUDE_DIR缓存变量中;环境变量onnxruntime_ROOT的值作为候选路径,include目录作为查找子目录

- find_library来查找onnxruntime库中的onnxruntime库文件,并将查找结果存入onnxruntime_LIBRARY缓存变量中;环境变量onnxruntime_ROOT的值作为候选路径,lib目录作为查找子目录

- find_file来查找onnxruntime库的版本号。版本号是在一个名为VERSION_NUMBER的文件中的,将查找的结果存入onnxruntime_VERSION_FILE缓存变量中;onnxruntime_ROOT的值作为候选路径

如果找到了版本号,再通过file指令,来读取其中的版本值,限制读取的行数为1,并将其保存在onnxruntime_VERSION缓存变量中

再来看第二部分:

```cmake
include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(onnxruntime
REQUIRED_VARS onnxruntime_LIBRARY onnxruntime_INCLUDE_DIR
VERSION_VAR onnxruntime_VERSION
HANDLE_VERSION_RANGE)

if(onnxruntime_FOUND)
set(onnxruntime_INCLUDE_DIRS ${onnxruntime_INCLUDE_DIR})
set(onnxruntime_LIBRARIES ${onnxruntime_LIBRARY})

add_library(onnxruntime::onnxruntime SHARED IMPORTED)
target_include_directories(onnxruntime::onnxruntime INTERFACE ${onnxruntime_INCLUDE_DIRS})
if(WIN32)
    set_target_properties(onnxruntime::onnxruntime PROPERTIES
      IMPORTED_IMPLIB "${onnxruntime_LIBRARY}")
else()
    set_target_properties(onnxruntime::onnxruntime PROPERTIES
      IMPORTED_LOCATION "${onnxruntime_LIBRARY}")
endif()
endif()
```

FindPackageHandleStandardArgs是一个CMake预置的功能模块,通过find_package_handle_standard_args指令,来检查模块中的结果变量是否已经被正确赋值。

- 第一个参数onnxruntime是软件包名
- REQUIRED_VARS是待检查的变量,这里要检查onnxruntime_LIBRARY和onnxruntime_INCLUDE_DIR,即库文件和头文件
- VERSION_VAR是检测版本号,这里要检查onnxruntime_VERSION;若要检查版本号是否满足区间形式,加上参数HANDLE_VERSION_RANGE

经过检查之后,onnxruntime_FOUND会根据检查结果,被赋值为真或假。若为真:

- 设置onnxruntime_INCLUDE_DIRS变量为查找到的头文件目录
- 设置onnxruntime_LIBRARIES变量为查找到的库文件目录
- 调用add_library命令为项目添加动态库
- 调用target_include_directories命令为项目指定头文件目录
- 调用set_target_properties命令设置linux中动态库的导入属性为导致动态库文件自身

## 2.2 main.cpp

测试onnxruntime运行环境是否可用的代码如下:

```cpp
#include <onnxruntime_cxx_api.h>

int main() {
    Ort::Env env;
    Ort::Session session(env, ORT_TSTR(""), Ort::SessionOptions(nullptr));
    return 0;
}
```

测试的内容仅仅是从一个非法的空路径中加载模型文件。

## 2.3 CMakeLists.txt

下面来看下用于构建项目的CMakeLists.txt:

```cmake
cmake_minimum_required(VERSION 3.20)
project(find-onnxruntime)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR};${CMAKE_MODULE_PATH}")
set(CMAKE_CXX_STANDARD 11) # 设置C++标准为11
set(onnx_version 1.10.0) # 根据下载的版本进行设置,本例使用1.10.0版本

# 请下载onnxruntime库的压缩包,并解压至该目录中
if("$ENV{onnxruntime_ROOT}" STREQUAL "")
if(WIN32)
      set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-win-x64-${onnx_version}")
elseif(APPLE)
      set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-osx-universal2-${onnx_version}")
else()
      set(ENV{onnxruntime_ROOT} "${CMAKE_CURRENT_LIST_DIR}/onnxruntime-linux-x64-${onnx_version}")
endif()
endif()

find_package(onnxruntime 1.10) # 指定依赖的最小版本
add_executable(main main.cpp)
target_link_libraries(main onnxruntime::onnxruntime)
target_compile_definitions(main PRIVATE ORT_NO_EXCEPTIONS)
```

开头是指定CMake的最低版本和项目名称

然后通过set指令设置一些变量:

- 设置CMAKE_MODULE_PATH
- 设置CMAKE_CXX_STANDARD为C++11标准
- 设置onnx_version版本
- 设置onnxruntime_ROOT的目录

然后查找版本1.10的onnxruntime包

调用add_executable添加目标,调用target_link_libraries来链接库

# 3 运行结果

在项目目录中新建一个build目录,通过cmake编译

```sh
mkdir build
cd build
camke ..
camke --build .
```

运行结果如下:



# 4 总结

本篇学习了CMake的查找功能,包括查找头文件、库文件、版本号等,并以onnxruntime库为例,来测试CMake的查找功能。

freebsder 发表于 2024-10-28 15:04

<p>用起来还是好复杂</p>
页: [1]
查看完整版本: CMake构建实战读书笔记06-onnx查找模块