CMake
Make工具, 例如 GNU Make , QT 的 qmake , 微软的 MS nmake, BSD Make(pmake), Makepp, 等等;
这些 Make 工具遵循着不同的规范和标准, 所执行的 Makefile 格式也千差万别; 这样就带来了一个严峻的问题: 如果软件想跨平台, 必须要保证能够在不同平台编译; 而如果使用上面的 Make 工具, 就得为每一种标准写一次 Makefile , 这将是一件让人抓狂的工作;
CMake就是针对上面问题所设计的工具: 它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程, 然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件, 如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程; 从而做到”Write once, run everywhere”;
CMakeLists.txt
示例
CMakeList.txt 文件中, 命令名字是不区分大小写的, 而参数和变量是大小写相关的;
# 指定 cmake 最低编译版本
CMAKE_MINIMUM_REQUIRED(VERSION 3.14)
# 设置项目名称
PROJECT (MATH)
# aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中;
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
# 设置 <头文件目录> 相当于指定gcc的-I参数
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# 设置 <链接库搜索目录> 相当于gcc的-L参数
link_directories(
${CMAKE_CURRENT_SOURCE_DIR}/libs
ffpmeg/lib/x64/
)
# 设置编译类型
add_executable(demo.exe demo.cpp) # 生成可执行文件
add_library(demo ${SRC_LIST})d_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库
# <!> 需放在add_executable和 find_package 之后
# 添加 <链接库> 相当于gcc的 -l参数
TARGET_LINK_LIBRARIES(demoHello
"op_x64" "tools" # 可以忽略 .lib 后缀
)
# 指定生成版本号, VERSION指代动态库版本, SOVERSION指代API版本
SET_TARGET_PROPERTIES(math PROPERTIES VERSION 1.2 SOVERSION 1)路径分隔符:Windows 用 \,但 CMake 中建议统一用 /。
在当前目录执行
cmake .
配置项参考表
基础项目配置
| 配置项 | 说明 | 示例 |
|---|---|---|
cmake_minimum_required | 指定最低 CMake 版本 | cmake_minimum_required(VERSION 3.10) |
project() | 定义项目名称和元信息 | project(MyApp VERSION 1.0 LANGUAGES CXX) |
include() | 包含其他 CMake 文件 | include(CTest) |
add_subdirectory() | 添加子目录构建 | add_subdirectory(src) |
include_directories() | 添加头文件搜索路径 (全局影响所有目标) | |
target_link_directories | 设置 <链接库搜索目录> 相当于gcc的-L参数(全局影响所有目标) |
include_directories (指定头文件目录)
路径格式:
- 相对路径相对于
CMAKE_CURRENT_SOURCE_DIR - 建议使用
${CMAKE_SOURCE_DIR}构造绝对路径
# 添加单个目录
include_directories(include)
# 添加多个目录(绝对路径)
include_directories(
${CMAKE_SOURCE_DIR}/include
/usr/local/thirdparty/include
)
# 系统目录(抑制警告)
include_directories(SYSTEM /usr/include/opencv4)target_link_directories (指定链接库目录)
link_directories(directory1 directory2 ...) 命令用于向链接器添加一个目录,在链接可执行文件或共享库时搜索库文件(如.so、.dll、.a等)。
见
链接 静态库/动态库 CMake更推荐使用
target_link_directories命令,因为它可以针对特定的目标(target)设置链接目录,从而避免全局设置带来的潜在问题。
假设你有一个可执行文件目标myapp,需要链接位于/path/to/my/libs的库,可以这样做:
add_executable(myapp main.cpp)
# 添加链接目录
target_link_directories(myapp PRIVATE /path/to/my/libs)
# 然后链接库,假设库名为mylibrary
target_link_libraries(myapp PRIVATE mylibrary)与find_package结合:当使用
find_package找到第三方库时,通常它会提供导入的目标(如Boost::system)或者变量(如Boost_LIBRARIES和Boost_INCLUDE_DIRS)
目标配置
| 配置项 | 说明 | 示例 |
|---|---|---|
add_executable() | 创建可执行文件目标 | add_executable(app main.cpp) |
add_library() | 创建库目标(静态库、动态库或对象库) | add_library(mylib STATIC lib.cpp) |
target_sources() | 为目标添加源文件 | target_sources(mylib PRIVATE util.cpp) |
target_include_directories() | 指定头文件搜索路径 (精确控制单个目标的包含路径) | target_include_directories(mylib PUBLIC include) |
target_link_libraries() | 链接库和依赖项 | target_link_libraries(app PRIVATE mylib) |
target_compile_definitions() | 添加编译定义 | target_compile_definitions(mylib PRIVATE USE_FEATURE_X) |
target_compile_options() | 指定编译选项 | target_compile_options(mylib PRIVATE -Wall) |
target_link_options() | 指定链接选项 | target_link_options(app PRIVATE -static) |
target_precompile_headers() | 预编译头文件 | target_precompile_headers(mylib PRIVATE header.h) |
生成 静态库/动态库
编译静态库(Static Library)
静态库在编译时会被完整地链接到可执行文件中,生成的文件扩展名通常是 .a(Linux/macOS)或 .lib(Windows)。
# 生成静态库
add_library(my_static_lib STATIC
src/file1.cpp
src/file2.cpp
)
# 设置头文件目录
target_include_directories(my_static_lib PUBLIC include/)
# 链接其他库(可选)
target_link_libraries(my_static_lib PRIVATE some_other_lib)动态库(Shared Library)
动态库在运行时加载,扩展名通常是 .so(Linux)、.dylib(macOS)或 .dll(Windows)。
# 生成动态库
add_library(my_shared_lib SHARED
src/file1.cpp
src/file2.cpp
)
# 设置头文件目录
target_include_directories(my_shared_lib PUBLIC include/)
# 设置动态库的版本号(可选)
set_target_properties(my_shared_lib PROPERTIES
VERSION 1.0.0
SOVERSION 1
)
# 链接其他库(可选)
target_link_libraries(my_shared_lib PRIVATE some_other_lib)其实就是在 add_library 时 SHARED 和 STATIC 的区别
链接 静态库/动态库
静态库在编译时会被完整地链接到可执行文件中,生成的文件扩展名通常是 .a(Linux/macOS)或 .lib(Windows)。
# 生成可执行文件
add_executable(my_app main.cpp)
# 链接第三方库
target_link_libraries(my_app PRIVATE /path/to/libfoo.a)
# 链接多个库
target_link_libraries(my_app PRIVATE lib1 lib2)| 关键字 | 含义 |
|---|---|
PRIVATE | 依赖仅用于当前目标,不传播给使用者 |
PUBLIC | 依赖用于当前目标,并传播给使用者 |
INTERFACE | 依赖不用于当前目标,但传播给使用者(用于头文件库) |
变量与属性
| 配置项 | 说明 | 示例 |
|---|---|---|
set() | 设置变量 | set(CMAKE_CXX_STANDARD 17) |
option() | 创建用户选项 | option(BUILD_TESTS "Build tests" ON) |
find_package() | 查找外部包 | find_package(OpenCV REQUIRED) |
configure_file() | 配置文件生成 | configure_file(config.h.in config.h) |
list() | 列表操作 | list(APPEND SOURCES util.cpp) |
get_target_property() | 获取目标属性 | get_target_property(lib_type mylib TYPE) |
find_package (链接第三方库)
基础用法
find_package(OpenCV 4.5 REQUIRED COMPONENTS core videoio)
带自定义路径
find_package(Boost 1.75
PATHS /opt/boost
COMPONENTS system filesystem
REQUIRED
)
# 结果检查
find_package(Qt5 COMPONENTS Core QUIET)
if(NOT Qt5_FOUND)
find_package(Qt6 COMPONENTS Core REQUIRED)
endif()
- 查找链接库:
- 动态库:
find_library(... NAMES mylib) - 静态库:
find_library(... NAMES mylib.a)
- 动态库:
查找位置
当使用 find_package(PackageName CONFIG) 或默认搜索时,CMake 会查找 <PackageName>Config.cmake 或 <package-name>-config.cmake 文件。
CMake 会按以下顺序查找(可通过参数调整):
PATHS/HINTS指定的路径, 通过 CMake 变量直接指定路径(命令行-D或set()):
find_package(OpenCV REQUIRED)
# 命令行调用:cmake -DOpenCV_DIR=/opt/opencv/lib/cmake/opencv4
<PackageName>_DIRCMake变量 指定多个根目录,CMake 会自动在这些路径下搜索标准子目录
set(CMAKE_PREFIX_PATH "/opt/qt5;/usr/local/boost")
搜索子目录包括:
<prefix>/lib/cmake/<PackageName>*/
<prefix>/lib/<arch>/cmake/<PackageName>*/
<prefix>/share/cmake/<PackageName>*/
(<arch>如 x86_64-linux-gnu)- 环境变量
ENV{<PackageName>_DIR}:
export OpenCV_DIR=/opt/opencv
- 标准安装目录(自动搜索):
Unix:/usr/local/, /usr/, /opt/
Windows:C:/Program Files/, C:/Program Files (x86)/
macOS:/Applications/, /usr/local/
在这些路径下检查 lib/cmake/、share/等子目录。
| 优先级 | 控制方式 | 示例 |
|---|---|---|
| 最高 | -D<PackageName>_DIR=... | -DOpenCV_DIR=/custom/opencv4 |
| 高 | CMAKE_PREFIX_PATH | set(CMAKE_PREFIX_PATH "/opt/libs") |
| 中 | 环境变量 | export OpenCV_ROOT=/path/to/opencv |
| 低 | 系统默认路径 | /usr/local/lib/cmake/ |
| 最低 | 用户缓存路径 | ~/.cmake/packages/OpenCV/ |
配置
set(CMAKE_FIND_DEBUG_MODE TRUE)
find_package(OpenCV REQUIRED)
可以查看详细搜索过程, 输出会显示所有尝试的路径及结果。
编译特性
| 配置项 | 说明 | 示例 |
|---|---|---|
set(CMAKE_CXX_STANDARD) | 设置 C++标准 | set(CMAKE_CXX_STANDARD 20) |
set(CMAKE_BUILD_TYPE) | 设置构建类型 | set(CMAKE_BUILD_TYPE Release) |
add_compile_features() | 添加编译特性 | add_compile_features(cxx_std_17) |
enable_testing() | 启用测试 | enable_testing() |
add_test() | 添加测试 | add_test(NAME mytest COMMAND app --test) |
安装配置
| 配置项 | 说明 | 示例 |
|---|---|---|
install(TARGETS) | 安装目标文件 | install(TARGETS app DESTINATION bin) |
install(FILES) | 安装文件 | install(FILES header.h DESTINATION include) |
install(DIRECTORY) | 安装目录 | install(DIRECTORY docs/ DESTINATION share/doc) |
install(EXPORT) | 导出目标 | install(EXPORT mylib-targets DESTINATION lib/cmake) |
生成器表达式
| 配置项 | 说明 | 示例 |
|---|---|---|
$<CONFIG:Debug> | 条件表达式 | target_compile_options(app PRIVATE "$<$<CONFIG:Debug>:-g>") |
$<TARGET_FILE:target> | 获取目标文件路径 | $<TARGET_FILE:app> |
$<BUILD_INTERFACE:...> | 区分构建/安装路径 | $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include> |
其他常用配置
| 配置项 | 说明 | 示例 |
|---|---|---|
message() | 打印消息 | message(STATUS "Configuring project") |
file() | 文件操作 | file(GLOB SOURCES "src/*.cpp") |
find_path()/find_library() | 查找路径/库 | find_library(MATH_LIB m) |
add_custom_command() | 自定义构建命令 | add_custom_command(OUTPUT generated.cpp COMMAND generator) |
add_custom_target() | 自定义目标 | add_custom_target(run ALL DEPENDS app) |
add_dependencies() | 添加目标依赖 | add_dependencies(app generated_code) |
message
CMake message 命令 基本语法 cmake message([<mode>] "message text"...)
| 模式 | 说明 | 是否中断构建 | 典型用途 |
|---|---|---|---|
(无) | 普通消息,默认输出到终端(无前缀) | 否 | 常规信息输出 |
STATUS | 项目状态信息(前缀为 -- ) | 否 | 配置进度提示 |
WARNING | CMake 警告(黄色文本,前缀 CMake Warning:) | 否 | 非致命性问题 |
AUTHOR_WARNING | 开发者警告(需启用 WARNINGS_AS_ERRORS 才会显示) | 否 | 代码维护提示 |
SEND_ERROR | 发送错误(红色文本,前缀 CMake Error:) | 继续配置但停止构建 | 可恢复的配置错误 |
FATAL_ERROR | 致命错误(红色文本,立即终止) | 立即终止 | 关键配置失败 |
DEPRECATION | 弃用警告(需启用 CMAKE_ERROR_DEPRECATED 或 CMAKE_WARN_DEPRECATED) | 取决于配置 | 标记即将废弃的功能 |
CMake 默认变量参考表
一、系统信息变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_SYSTEM_NAME | 操作系统名称 | Linux, Windows, Darwin |
CMAKE_HOST_SYSTEM_NAME | 主机操作系统 | Linux, Windows |
CMAKE_SYSTEM_VERSION | 系统版本 | 10.0.19041 (Windows) |
CMAKE_SYSTEM_PROCESSOR | CPU架构 | x86_64, ARM64 |
UNIX | 是否为UNIX系统 | TRUE/FALSE |
WIN32 | 是否为Windows | TRUE/FALSE |
APPLE | 是否为Apple系统 | TRUE/FALSE |
二、路径控制变量
| 变量名 | 说明 | 示例值 | |
|---|---|---|---|
CMAKE_SOURCE_DIR | 顶层CMakeLists.txt所在目录 | /project/root | |
CMAKE_BINARY_DIR | 构建目录(build) | /project/root/build | |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的CMakeLists.txt目录 | /project/root/src | |
CMAKE_CURRENT_BINARY_DIR | 当前构建目录 | /project/root/build/src | |
CMAKE_INSTALL_PREFIX | 安装前缀 | /usr/local (Unix) | |
CMAKE_MODULE_PATH | Find模块搜索路径 | /custom/path/cmake |
三、编译工具变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_C_COMPILER | C编译器路径 | /usr/bin/gcc |
CMAKE_CXX_COMPILER | C++编译器路径 | /usr/bin/g++ |
CMAKE_MAKE_PROGRAM | 生成工具路径 | /usr/bin/make, ninja |
CMAKE_BUILD_TYPE | 构建类型 | Debug, Release |
CMAKE_CXX_STANDARD | C++标准 | 11, 14, 17 |
四、语言相关变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_C_FLAGS | C编译选项 | -Wall -O2 |
CMAKE_CXX_FLAGS | C++编译选项 | -Wall -std=c++17 |
CMAKE_EXE_LINKER_FLAGS | 可执行文件链接选项 | -lpthread |
CMAKE_SHARED_LINKER_FLAGS | 动态库链接选项 | -fPIC |
五、生成器变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_GENERATOR | 当前生成器名称 | Unix Makefiles, Ninja |
CMAKE_GENERATOR_PLATFORM | 生成器平台 | x64, Win32 (VS) |
CMAKE_GENERATOR_TOOLSET | 生成器工具集 | v142 (VS2019) |
六、包管理变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_PREFIX_PATH | 包搜索路径 | /opt/qt5;/usr/local |
CMAKE_FIND_ROOT_PATH | 交叉编译根路径 | /arm/sysroot |
CMAKE_FIND_USE_PACKAGE_REGISTRY | 是否使用注册表 | ON/OFF |
七、测试/安装变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_CTEST_COMMAND | CTest路径 | /usr/bin/ctest |
CMAKE_INSTALL_RPATH | 安装目标RPATH设置 | $ORIGIN/../lib |
八、特殊控制变量
| 变量名 | 说明 | 示例值 |
|---|---|---|
CMAKE_EXPORT_COMPILE_COMMANDS | 生成编译数据库 | ON (用于clangd) |
CMAKE_VERBOSE_MAKEFILE | 显示详细构建信息 | ON |
CMAKE_COLOR_MAKEFILE | 彩色输出 | ON |
九、环境变量映射
CMake 会自动将系统环境变量映射为 ENV{var} 格式:
message("PATH is $ENV{PATH}") # 访问系统PATH
set(ENV{CFLAGS} "-O2") # 设置临时环境变量