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)

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_LIBRARIESBoost_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 会按以下顺序查找(可通过参数调整):

  1. PATHS/HINTS 指定的路径, 通过 CMake 变量直接指定路径(命令行 -D或 set()):
find_package(OpenCV REQUIRED)
# 命令行调用:cmake -DOpenCV_DIR=/opt/opencv/lib/cmake/opencv4
  1. <PackageName>_DIR CMake变量 指定多个根目录,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)
  1. 环境变量 ENV{<PackageName>_DIR}​​
export OpenCV_DIR=/opt/opencv
  1. 标准安装目录​​(自动搜索):
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_PATHset(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项目状态信息(前缀为 --配置进度提示
WARNINGCMake 警告(黄色文本,前缀 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_PROCESSORCPU架构x86_64, ARM64
UNIX是否为UNIX系统TRUE/FALSE
WIN32是否为WindowsTRUE/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_PATHFind模块搜索路径/custom/path/cmake

三、编译工具变量

变量名说明示例值
CMAKE_C_COMPILERC编译器路径/usr/bin/gcc
CMAKE_CXX_COMPILERC++编译器路径/usr/bin/g++
CMAKE_MAKE_PROGRAM生成工具路径/usr/bin/make, ninja
CMAKE_BUILD_TYPE构建类型Debug, Release
CMAKE_CXX_STANDARDC++标准11, 14, 17

四、语言相关变量

变量名说明示例值
CMAKE_C_FLAGSC编译选项-Wall -O2
CMAKE_CXX_FLAGSC++编译选项-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_COMMANDCTest路径/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")        # 设置临时环境变量