1.常用的 CMake 内置变量

变量名

典型用途

备注 / 常见写法

CMAKE_SOURCE_DIR

CMAKE_CURRENT_SOURCE_DIR

项目根目录,几乎必用

CMAKE_CURRENT_SOURCE_DIR

当前 CMakeLists.txt 所在目录

子目录中最常用

CMAKE_BINARY_DIR

顶层构建目录(build 目录)

CMAKE_CURRENT_BINARY_DIR

当前构建目录(当前 CMakeLists.txt 的输出目录)

PROJECT_NAME

当前 project() 定义的项目名

CMAKE_PROJECT_NAME

顶层项目名

CMAKE_CXX_COMPILER

C++ 编译器完整路径

CMAKE_C_COMPILER

C 编译器完整路径

CMAKE_BUILD_TYPE

当前构建类型(Debug / Release 等)

CMAKE_RUNTIME_OUTPUT_DIRECTORY

可执行文件输出目录(全局)

CMAKE_LIBRARY_OUTPUT_DIRECTORY

库文件输出目录(全局)

CMAKE_CURRENT_LIST_DIR

当前正在处理的 .cmake / CMakeLists.txt 所在目录

CMAKE_CURRENT_LIST_FILE

当前正在处理的 CMake 文件完整路径

查找 FindXXX.cmake / *.cmake 模块的路径列表

查找 FindXXX.cmake / *.cmake 模块的路径列表

非常重要!

2.基础语法

2.1 定义变量

# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
  • VAR:变量名

  • VALUE:变量值

2.2 搜索文件

aux_source_directory(< dir > < variable >)
# 搜索 src 目录下的源文件
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
  • dir:要搜索的目录

  • variable:将从dir目录下搜索到的源文件列表存储到该变量中

file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
# 搜索当前目录的src目录下所有的源文件,并存储到变量中
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
  • GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。

  • GLOB_RECURSE:递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。

2.3 包含头文件

include_directories(headfilepath)
#引入include文件夹
include_directories(${PROJECT_SOURCE_DIR}/include)

2.4 制作动态库或静态库

add_library(库名称 STATIC 源文件1 [源文件2] ...) 
## 使用上面学习的语法 编译静态库
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
## 同样的动态库
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc SHARED ${SRC_LIST})

2.5 修改输出的路径

include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
# 设置动态库生成路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(calc SHARED ${SRC_LIST})

2.6 包含库文件

#指定静态库的位置
link_directories(<lib path>)
# 链接静态库
link_libraries(<static lib> [<static lib>...])

# 链接动态库
target_link_libraries(
    <target> 
    <PRIVATE|PUBLIC|INTERFACE> <item>... 
    [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)

# 指定要链接的动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 添加并生成一个可执行程序
add_executable(main ${SRC_LIST})
# 指定要链接的动态库
target_link_libraries(main yaml calc)
  • 可以是全名 libxxx.a

  • 也可以是掐头(lib)去尾(.a)之后的名字 xxx

3. 多层嵌套CMake(工程化模块化使用)

如果项目很大,或者项目中有很多的源码目录,在通过CMake管理项目的时候如果只使用一个CMakeLists.txt,那么这个文件相对会比较复杂,有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt文件(头文件目录不需要),这样每个文件都不会太复杂,而且更灵活,更容易维护。

CMakeLists.txt 文件变量作用域

  • 根节点CMakeLists.txt中的变量全局有效

  • 父节点CMakeLists.txt中的变量可以在子节点中使用

  • 子节点CMakeLists.txt中的变量只能在当前节点中使用

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

source_dir:指定了CMakeLists.txt源文件和代码文件的位置,其实就是指定子目录

binary_dir:指定了输出文件的路径,一般不需要指定,忽略即可。

EXCLUDE_FROM_ALL:在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标。

如此 CMakeLists.txt文件之间的父子关系就被构建出来了