CMake文件在项目中的分布
1. 按模块分层的 CMakeLists.txt
用过 CMake 的开发者都清楚,CMakeLists.txt 是一个编译规则的描述文件。一般来说,自己在使用 CMake 的时候,如果项目不大,往往都喜欢仅使用一个 CMakeLists.txt 来管理所有的属性配置。但随着项目越做越大,一个 CMakeLists.txt 的配置维护起来将十分困难。为此需要对每个特定的模块编写 CMakeLists.txt。可以参考 OpenCV 的 CMakeLists.txt 布局。
.
├── cmake
│ └── ...
├── CMakeLists.txt(项目整体配置)
├── include
│ ├── CMakeLists.txt(用于全局包含的 opencv.hpp 的发布)
│ └── ...
├── modules
│ └── core
│ ├── CMakeLists.txt(核心模块 core 的配置)
│ ├── include
│ │ └── ...
│ ├── src
│ │ └── ...
│ └── test
│ └── ...
├── README.md
└── samples
很显然,每个模块的文件夹下都会存在一个 CMakeLists.txt 。
-
最底层的 CMakeLists.txt 是为了管理该模块功能的编译、测试文件编译,以及提供指定的接口(可以是库,也可以是若干 CMake 变量)给外部。OpenCV 中广泛使用语句 ocv_add_module() 来添加模块。例如:
# 定义于 <opencv-path>/modules/core/CMakeLists.txt 中的内容 ocv_add_module(core OPTIONAL opencv_cudev WRAP java objc python js)
这句话大概意思就是说,添加一个名为
core
的模块,opencv_cudev
为模块中可选的,不一定需要参与构建的部分,以及提供java
等其他语言接口的包装。这个语句并不是 CMake 原生语法中自带的,而是程序员自行设计的宏。根据这个宏以及本 CMakeLists.txt 的其余功能,可以创建该
core
模块的目标,并为此添加合适的依赖项。 -
4.x 系列版本的 OpenCV 设置两级 CMakeList.txt。最高一级 CMakeLists.txt 一般是对于整个库编译选项的设置,以及对系统、平台、编译器等编译环境信息的兼容处理。OpenCV 项目根目录的 CMakeLists.txt 前一大段都是在对当前平台、编译配置的信息做处理,例如:
# 定义于 <opencv-path>/CMakeLists.txt 中的内容 if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore) cmake_minimum_required(VERSION 3.1 FATAL_ERROR) cmake_policy(VERSION 2.8) else() cmake_minimum_required(VERSION "${MIN_VER_CMAKE}" FATAL_ERROR) endif()
2. 扩展名为cmake的文件
CMake 中除了解析 CMakeLists.txt 文件,还允许解析扩展名为 cmake 的文件。一般有两种方式对这类文件进行访问,一种是 find_package()
,另一种是 include()
,其中第一种方案会在后文中介绍。
2.1 *.cmake
OpenCV 中,*.cmake
文件全部存放在 <opencv-path>/cmake
文件夹下,常见的名称有 Findxxx.cmake
、OpenCVxxx.cmake
。第一种是本地项目中用于 find_package()
的,例如 OpenCV 中 FindONNX.cmake
等文件。第二种则是添加了各种各样的能够减少重复操作的宏与函数,ocv_add_module()
就是其中之一,他被定义在 OpenCVModule.cmake
中,这种一般需要执行 include()
操作,例如:
# 定义于 <opencv-path>/CMakeLists.txt 中的内容
# --- OpenCL ---
if(WITH_OPENCL)
include(cmake/OpenCVDetectOpenCL.cmake)
endif()
# --- Halide ---
if(WITH_HALIDE)
include(cmake/OpenCVDetectHalide.cmake)
endif()
# --- VkCom ---
if(WITH_VULKAN)
include(cmake/OpenCVDetectVulkan.cmake)
endif()
# --- WebNN ---
if(WITH_WEBNN)
include(cmake/OpenCVDetectWebNN.cmake)
endif()
2.2 *.in 文件
此类文件严格意义上来说不属于 CMake 文件,而是 OpenCV 项目里的一种模板文件,其后缀统一使用成 *.in
罢。*.in
文件一般是用于在 cmake 执行阶段将其嵌入的 CMake 变量、列表展开,并生成目标文件的过程中的。这一步通常是由 configure_file()
完成,会在后文中进行介绍。
OpenCV 中的此类文件一般放在 <opencv-path>/cmake/template
文件夹下,主要是用于在执行 sudo make install
的时候将OpenCVConfig.cmake
等一系列文件安装至目标路径下,而 OpenCVConfig.cmake
文件的产生,就需要 <opencv-path>/cmake/template
文件夹下的 OpenCVConfig.cmake.in
文件。