CMake 常用函数、技巧与错误 | C & C++
本文列举了常用的 CMake 中的常用函数、技巧与错误。
指令
find_package
find_package 的作用就是寻找第三方模块的头文件目录和库文件路径,并将其设为变量,返回提供给 CMakeLists.txt 其他部分使用。
find_package 首先会寻找并执行模块相关的
.cmake
文件。寻找顺序如下:- 在寻找模块的时候显式指定了模块目录:
find_package(${module_name} REQUIRED PATHS ${module_dir})
- 在
${module_name}_DIR
变量中指定了模块目录 - 查找路径的根目录,默认查找目录如下:
${module_name}_DIR
MAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH
:如果以 bin 或 sbin 结尾,则自动回退到上一级目录
- 检查上述目录下的这些目录:
(lib/${arch}|lib|share)/cmake/${module_name}*/
(lib/${arch}|lib|share)/${module_name}*/
(lib/${arch}|lib|share)/${module_name}*/(cmake|CMake)/
- 寻找并执行
${module_name}Config.cmake
或Find${module_name}.cmake
脚本
- 在寻找模块的时候显式指定了模块目录:
find_package 然后会设置以下几个变量:
${module_name}_FOUND
:是否找到该模块${module_name}_INCLUDE_DIR
:模块头文件目录${module_name}_LIBRARY
或${module_name}_LIBRARIES
:模块库文件路径
以 LibTorch 为例展示一个例子
1 | find_package(Torch REQUIRED) # REQUIRED 表明这个模块是必需的,如果找不到就报错 |
参考
file
查找某些文件并构成一个文件列表变量
1 | file(GLOB LIB_CPP_SRCS ${CMAKE_SOURCE_DIR}/src/*.cpp) |
list
1 | list(LENGTH <list><output variable>) |
- LENGTH:返回 list 的长度
- GET:返回 list 中 index 的 element 到 value 中
- APPEND:添加新 element 到 list中
- FIND:返回 list 中 element 的 index,没有找到返回 -1
- INSERT:将新 element 插入到 list 中 index 的位置
- REMOVE_ITEM:从 list 中删除某个 element
- REMOVE_AT:从 list 中删除指定 index 的 element
- REMOVE_DUPLICATES:从 list 中删除重复的 element
- REVERSE:将 list 的内容反转
- SORT:将 list 按字母顺序排序
include_directories
将指定目录添加到编译器的头文件搜索路径之下,指定的目录被解释成当前源码路径的相对路径
1 | include_directories(${CMAKE_SOURCE_DIR}/src) |
该命令不会进行递归查找,正常情况下只需要 include src 目录即可,引用头文件时相对于 src 路径填写头文件路径
include
用于包含其他 cmake 文件
1 | include_directories(${CMAKE_SOURCE_DIR}/third_path.cmake) |
add_subdirectory
添加子目录,子目录中需要也有 cmake 文件,使用该命令即运行子目录的 cmake 文件。子目录中的 set 命令默认有效范围仅子目录和子目录的子目录,如果想令子目录的 set 在上层目录生效,需要加上 PARENT_SCOPE 参数,但是这样在子目录就无法生效了
1 | add_subdirectory(src/proto) |
add_library
将指定的源文件生成库文件
1 | # SHARED,动态库 |
这里 hello_shared 和 hello_static 名字必须不同,否则会忽略掉第二个库,所以使用 set_target_properties 命令重命名
add_executable
和 add_library 类似,将指定的源文件生成可执行文件
set_target_properties
1 | set_target_properties(hello PROPERTIES VERSION 1.6.0. SOVERSION 1) |
这条命令会生成三个文件:
1 | libhello.so => libhello.so.1* |
其中,libhello.so.1.6.0 为动态库的文件名(realname),libhello.so.1 为动态库的别名(soname),libhello.so 为动态库的链接名(linkname)
target_link_libraries
为 target 添加需要链接的共享库
1 | target_link_libraries(${PROJECT_NAME} opencv_imgcodecs) |
option
命令行参数
1 | project(hello) |
1 | cmake -DUSE_XXX=ON .. |
install
CMake之install方法的使用
【CMake】cmake的install指令
add_custom_command
和 install 相比,add_custom_command 更加灵活,下面展示一个用 add_custom_command 做拷贝的示例:
1 | add_custom_command(TARGET ${target_name} POST_BUILD |
target_sources
target_sources 用于向 target 中追加源文件,例如:
1 | add_library(my_lib "") # 这里的 "" 不能省略 |
注:
- 如果在根目录通过 add_library 定义了一个 target,也可以在子目录中用 target_sources 命令往这个 target 中追加源文件
- C++ 的源文件指定为 PRIVATE,是因为源文件只是在构建库文件时使用,头文件指定为 PUBLIC 是因为构建库文件和使用库文件时都会使用
参考
CMake - 使用 target_sources() 提高源文件处理能力
execute_process
1 | execute_process( |
如果 OUTPUT_VARIABLE 和 ERROR_VARIABLE 变量名相同,它们的输出将按照产生顺序被合并。
技巧
target_**() 中的 PRIVATE、INTERFACE 和 PUBLIC
以 target_link_libraries
为例:
1 | target_link_libraries(A PRIVATE/INTERFACE/PUBLIC B) |
PRIVATE
:依赖项 B 仅链接到目标 A,不链接到 CINTERFACE
:依赖项 B 仅链接到目标 C,不链接到 APUBLIC
:依赖项 B 链接到目标 A 和 目标 C
target_include_directories
同理
参考
CMake 中的 PUBLIC,PRIVATE,INTERFACE
macro 形参获取
1 | cmake_minimum_required (VERSION 3.5) |
1 | ARGC=5 |
参考
错误
Unknown CMake command “cuda_add_library”
在这之前使用 find_package(CUDA)
指令即可。
CMake 常用函数、技巧与错误 | C & C++