基本常识
动态库链接
在 Windows 上,动态库使用 .dll 后缀,但编译器无法直接链接 .dll 文件。通常,我们链接 .dll 对应的 .lib 文件,提供编译时的库信息。 在 Linux 上,直接链接.so既可。 运行时动态库搜索路径
运行时动态库搜索路径
- Windows:动态库必须位于系统的搜索路径中。一般通过环境变量 PATH 指定,或者直接放在可执行文件所在目录。
- Linux:运行时动态库一般通过环境变量 LD_LIBRARY_PATH 查找,确保动态库在执行时可被找到。
生成器
CMake支持多种生成器来支持不同的构建系统,默认的生成器是(cmake --help 输出中带*
标记的generator)
可以设置环境变量CMAKE_GENERATOR来改变默认生成器(CMake 3.15+))。
缓存变量
CMake 支持缓存变量,它们存储在构建目录
中的 CMakeCache.txt
文件中。调用 CMake 时使用 -D 参数传递的变量会自动作为缓存变量保存。
缓存变量与普通变量的区别:
- 普通变量: 定义在 CMakeLists.txt 中,具有动态作用域,仅在当前 CMakeLists.txt 或作用域中有效。
- 缓存变量: 全局可见,存在于整个 CMake 配置过程中,即使 CMakeLists.txt 的变量被修改,缓存变量的值不会自动更新,除非强制修改或清除缓存。
创建缓存变量的方式:
- 通过命令行 -D 参数:
cmake -DCMAKE_BUILD_TYPE=Release
- 使用 option 命令创建布尔缓存变量
option(ENABLE_FEATURE_A "feature_a" ON)
- 使用 set 命令指定缓存类型:
set(VAR "value" CACHE STRING "注释")
注意: 缓存变量修改必须使用set的带FORCE版本set(VAR "value" CACHE STRING "注释" FORCE)
CMake配置的多种方式
- 使用当前工作目录作为构建树,使用
作为源代码目录。
cmake [options] <path-to-source> # 不推荐, cmake .
- 使用
作为构建树,并从其 CMakeCache.txt 文件加载源树的路径。
cmake [options] <path-to-existing-build> # 加载已经构建了的缓存,刷新CMakeLists的修改, cmake build/
- 使用
作为构建树,使用 作为源树(推荐)。 如果仅给出一种类型的路径,则当前工作目录 (cwd) 将用于另一种路径。例如:
cmake [options] -S <path-to-source> -B <path-to-build> # 无歧义, cmake -S . -B build/
CMake标识符规则
CMake命令不去分大小写。 CMake 保留以下标识符(无论是大写、小写或混合大小写):
- begin with
CMAKE_
- begin with
_CMAKE_
- begin with
_
CMakeLists.txt 内文件路径的查找规则
路径分隔符统一以/
分隔,cmake会自动处理。\
需转义,即\\
。
- 绝对路径:直接按照文件系统中的实际路径查找,无需依赖当前目录()。
- 相对路径:
- 一般情况下:相对路径是相对于当前 CMakeLists.txt 文件所在的目录。例如,
add_executable()
或add_library()
等命令使用的文件路径,都会以当前 CMakeLists.txt 的目录作为基准。 - 特殊情况:当使用
include(script.cmake)
或find_package()
等命令时,路径会相对于调用这些命令的 CMakeLists.txt 文件所在的目录,而不是被包含的脚本文件。
- 一般情况下:相对路径是相对于当前 CMakeLists.txt 文件所在的目录。例如,
示例
假设目录结构如下:
project/
├── CMakeLists.txt
├── src/
│ ├── CMakeLists.txt
│ └── main.cpp
├── scripts/
│ └── setup.cmake
示例代码
顶层的CMakeLists.txt 中的相对路径:
cmake_minimum_required(VERSION 3.20)
project(DemoProject)
add_subdirectory(src) # project/
include(scripts/setup.cmake) # project/
src/CMakeLists.txt 中的相对路径:
add_executable(app main.cpp) # project/src/
scripts/setup.cmake
文件的相对路径
message("正在处理的cmake文件路径: ${CMAKE_CURRENT_LIST_DIR}") # 输出: project/scripts
message("当前所在的CMakeLists文件路径: ${CMAKE_CURRENT_SOURCE_DIR}") # 输出: project
CMake 变量细则
CMake 的变量用来存储值,但所有值都是字符串类型。即使看起来像数字或布尔值,CMake 都会以字符串的形式存储它们。
set(VAR1 "Hello, World!") # 设置变量 VAR1 的值为字符串 "Hello, World!"
set(VAR2 42) # 虽然看起来是数字,但 CMake 将 "42" 存储为字符串
set(VAR3 true) # 同样,"true" 也是字符串
- 变量具有动态Block Scope(作用域)。
- 每个变量“set”或“unset”都会在当前作用域中创建一个绑定,Block Scope结束删除绑定,每次创建作用域会复制父作用域的变量绑定。这意味着函数内部设置的变量不会渗透到父作用域中。
以下命令可以创建新的Block Scope:
- block()
- function()
- add_subdirectory()
set命令语法:
set(<variable> <value>... [PARENT_SCOPE])
CMake set 命令提供了一个关于作用域的选项,PARENT_SCOPE 将变量设置到父作用域中,而不是当前作用域中。
另外,CMake缓存变量是具有全局作用域的,除非指定了FORCE
选项,否则CACHE
选项不会设置CACHE
中已存在的变量,即set(VAR "value" CACHE STRING "注释" FORCE)
。
与大多编程语言不同,CMake 的循环(if)和控制流(foreach、while)没有自己的作用域。