CMake 关键字

本页记录 CMakeLists.txt 中最常用的命令、变量和关键字。基础流程见 cmake基础知识

CMakeLists.txt 基本骨架

现代 CMake 推荐围绕 target 组织配置。target 可以是可执行程序、静态库、动态库或接口库。

cmake_minimum_required(VERSION 3.20)
 
project(MyProject
    VERSION 1.0.0
    LANGUAGES CXX
)
 
add_library(my_library STATIC
    src/library.cpp
)
 
target_include_directories(my_library
    PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/include
)
 
target_compile_features(my_library
    PUBLIC
        cxx_std_17
)
 
add_executable(my_app
    src/main.cpp
)
 
target_link_libraries(my_app
    PRIVATE
        my_library
)

核心关键字自查表

命令/关键字作用常见写法
cmake_minimum_required声明最低 CMake 版本cmake_minimum_required(VERSION 3.20)
project定义项目名称、版本、语言project(App VERSION 1.0 LANGUAGES CXX)
set设置变量set(CMAKE_CXX_STANDARD 17)
option定义开关选项option(ENABLE_TESTS "Build tests" ON)
message输出配置日志message(STATUS "Configuring app")
add_executable创建可执行程序目标add_executable(app src/main.cpp)
add_library创建库目标add_library(core STATIC src/core.cpp)
target_include_directories配置目标头文件目录target_include_directories(core PUBLIC include)
target_link_libraries配置目标链接库target_link_libraries(app PRIVATE core)
target_compile_features配置目标语言特性target_compile_features(core PUBLIC cxx_std_17)
target_compile_options配置目标编译选项target_compile_options(core PRIVATE -Wall)
target_compile_definitions配置宏定义target_compile_definitions(core PRIVATE USE_LOG)
find_package查找外部依赖包find_package(fmt REQUIRED)
include加载其他 CMake 脚本include(GNUInstallDirs)
add_subdirectory加载子目录项目add_subdirectory(src)
install定义安装规则install(TARGETS app RUNTIME DESTINATION bin)
enable_testing启用测试enable_testing()
add_test添加测试add_test(NAME unit COMMAND unit_tests)

cmake_minimum_required

声明项目要求的最低 CMake 版本。它应该放在顶层 CMakeLists.txt 的第一条有效命令。

cmake_minimum_required(VERSION 3.20)

作用:

  • 避免用户使用过旧版本 CMake 配置项目。
  • 固定 CMake 策略行为,减少不同版本之间的兼容性问题。

project

定义项目名称、版本、描述和启用语言。

project(Hello
    VERSION 1.0.0
    DESCRIPTION "Hello application"
    LANGUAGES CXX
)

常用形式:

project(Hello LANGUAGES C)
project(Hello LANGUAGES CXX)
project(Hello LANGUAGES C CXX)

project 会设置一些常用变量:

变量说明
PROJECT_NAME当前项目名称
PROJECT_VERSION当前项目版本
PROJECT_SOURCE_DIR当前项目源码目录
PROJECT_BINARY_DIR当前项目构建目录
<PROJECT-NAME>_SOURCE_DIR指定项目名对应的源码目录
<PROJECT-NAME>_BINARY_DIR指定项目名对应的构建目录

推荐在通用脚本中优先使用 PROJECT_SOURCE_DIRPROJECT_BINARY_DIRCMAKE_CURRENT_SOURCE_DIR,避免项目改名后变量名失效。

set

设置普通变量、缓存变量或 CMake 内置变量。

set(SRC_LIST
    src/main.cpp
    src/app.cpp
)
 
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

常见用途:

  • 保存源码列表。
  • 设置语言标准。
  • 设置安装路径、输出路径等配置。

更推荐的现代写法是把配置绑定到目标上:

target_compile_features(my_target PUBLIC cxx_std_17)

option

定义用户可以通过 -D 修改的开关。

option(ENABLE_TESTS "Build test targets" ON)
option(ENABLE_WARNINGS "Enable compiler warnings" ON)

命令行修改:

cmake -S . -B build -DENABLE_TESTS=OFF

配合 if 使用:

if(ENABLE_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

message

输出配置阶段日志。

message(STATUS "Project source dir: ${PROJECT_SOURCE_DIR}")
message(WARNING "Optional dependency not found")
message(FATAL_ERROR "Required dependency missing")

常用级别:

级别作用
STATUS普通状态信息
WARNING警告,不中断配置
SEND_ERROR记录错误,配置继续执行但最终失败
FATAL_ERROR立即终止配置

add_executable

创建可执行文件目标。

add_executable(demo_app
    src/main.cpp
    src/app.cpp
)

目标名 demo_app 是 CMake 内部使用的 target 名称,最终文件名默认也会使用它。可以通过目标属性修改输出名:

set_target_properties(demo_app PROPERTIES
    OUTPUT_NAME demo
)

add_library

创建库目标。

add_library(core STATIC
    src/core.cpp
)
 
add_library(plugin SHARED
    src/plugin.cpp
)
 
add_library(headers_only INTERFACE)

库类型:

类型说明
STATIC静态库
SHARED动态库
MODULE插件模块库
INTERFACE只携带头文件、宏、编译选项等使用要求,不产生二进制

target_include_directories

给目标配置头文件搜索路径。

target_include_directories(core
    PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/include
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)

可见性含义:

可见性含义
PRIVATE只给当前目标使用
PUBLIC当前目标使用,依赖它的目标也继承
INTERFACE当前目标不用,依赖它的目标继承

经验规则:

  • 公开头文件目录通常写 PUBLIC
  • 源码内部目录通常写 PRIVATE
  • 头文件库通常写 INTERFACE

给目标链接库或声明目标之间的依赖关系。

target_link_libraries(demo_app
    PRIVATE
        core
)

链接第三方包时也使用这个命令:

find_package(fmt REQUIRED)
 
target_link_libraries(demo_app
    PRIVATE
        fmt::fmt
)

PRIVATEPUBLICINTERFACE 的含义和头文件目录相同。业务程序链接内部库时通常使用 PRIVATE;库的公开 API 暴露了某个依赖的类型时,才需要使用 PUBLIC

target_compile_features

给目标声明需要的 C++ 标准或编译特性。

target_compile_features(core
    PUBLIC
        cxx_std_17
)

相比全局设置 CMAKE_CXX_STANDARD,这个写法更精确,因为它描述的是目标自己的使用要求。

target_compile_options

给目标添加编译器参数。

if(MSVC)
    target_compile_options(core PRIVATE /W4)
else()
    target_compile_options(core PRIVATE -Wall -Wextra -Wpedantic)
endif()

注意:

  • 不同编译器参数不完全相同,需要区分 MSVC、GCC、Clang。
  • 优先绑定到具体目标,避免全局污染第三方库。

target_compile_definitions

给目标添加宏定义。

target_compile_definitions(core
    PRIVATE
        CORE_ENABLE_LOG
    PUBLIC
        CORE_USE_FAST_MATH
)

等价于给编译器传入:

-DCORE_ENABLE_LOG

如果宏会影响公开头文件中的 API,需要考虑使用 PUBLIC

add_subdirectory

把子目录中的 CMakeLists.txt 加入当前构建。

add_subdirectory(src)
add_subdirectory(tests)

常见项目结构:

project/
├── CMakeLists.txt
├── src/
│   └── CMakeLists.txt
└── tests/
    └── CMakeLists.txt

适合中大型项目按模块拆分配置。

find_package

查找外部依赖包。

find_package(fmt REQUIRED)
 
target_link_libraries(demo_app
    PRIVATE
        fmt::fmt
)

常见参数:

参数作用
REQUIRED找不到就配置失败
QUIET找不到时减少输出
COMPONENTS指定包组件

示例:

find_package(Boost REQUIRED COMPONENTS filesystem system)

install

定义安装规则,让构建产物可以被安装到统一目录。

include(GNUInstallDirs)
 
install(TARGETS demo_app core
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
 
install(DIRECTORY include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

执行安装:

cmake --install build --prefix ./dist

安装目标说明:

目标类型常见安装目录
RUNTIME可执行文件,通常是 bin
LIBRARY动态库,通常是 lib
ARCHIVE静态库,通常是 lib
头文件目录通常是 include

测试相关关键字

启用测试:

enable_testing()

添加测试目标:

add_executable(unit_tests
    tests/test_calculator.cpp
)
 
target_link_libraries(unit_tests
    PRIVATE
        core
)
 
add_test(NAME calculator_tests COMMAND unit_tests)

运行测试:

ctest --test-dir build

条件判断关键字

if(WIN32)
    message(STATUS "Configuring on Windows")
elseif(APPLE)
    message(STATUS "Configuring on macOS")
elseif(UNIX)
    message(STATUS "Configuring on Unix-like system")
endif()

常见条件变量:

变量说明
WIN32Windows 平台
APPLEApple 平台
UNIXUnix-like 平台,包括 Linux 和 macOS
MSVCMicrosoft Visual C++ 编译器
CMAKE_CXX_COMPILER_IDC++ 编译器 ID,如 GNUClangMSVC

变量引用和列表

变量引用:

message(STATUS "Source dir: ${CMAKE_CURRENT_SOURCE_DIR}")

列表变量:

set(SOURCES
    src/main.cpp
    src/app.cpp
    src/service.cpp
)
 
add_executable(app
    ${SOURCES}
)

追加列表:

list(APPEND SOURCES
    src/new_feature.cpp
)

完整可直接使用的 CMakeLists.txt 模板

适用于常见 C++ 业务程序:一个内部库、一个可执行程序、可选测试、可安装。

cmake_minimum_required(VERSION 3.20)
 
project(BusinessApp
    VERSION 1.0.0
    DESCRIPTION "Business application"
    LANGUAGES CXX
)
 
option(BUSINESS_APP_BUILD_TESTS "Build tests" ON)
option(BUSINESS_APP_ENABLE_WARNINGS "Enable compiler warnings" ON)
 
add_library(business_core STATIC
    src/service.cpp
    src/repository.cpp
)
 
target_include_directories(business_core
    PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/include
)
 
target_compile_features(business_core
    PUBLIC
        cxx_std_17
)
 
if(BUSINESS_APP_ENABLE_WARNINGS)
    if(MSVC)
        target_compile_options(business_core PRIVATE /W4)
    else()
        target_compile_options(business_core PRIVATE -Wall -Wextra -Wpedantic)
    endif()
endif()
 
add_executable(business_app
    src/main.cpp
)
 
target_link_libraries(business_app
    PRIVATE
        business_core
)
 
include(GNUInstallDirs)
 
install(TARGETS business_core business_app
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
 
install(DIRECTORY include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
 
if(BUSINESS_APP_BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

配套命令:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
ctest --test-dir build
cmake --install build --prefix ./dist

常见错误排查

现象常见原因处理方式
CMakeLists.txt 修改后构建不生效没有重新配置重新执行 cmake -S . -B build
找不到头文件没有配置 target_include_directories给对应库或程序添加头文件目录
链接时报 unresolved symbol没有链接库或源码未加入目标检查 target_link_libraries 和源码列表
Debug/Release 参数不生效生成器类型不同Make/Ninja 用 CMAKE_BUILD_TYPE,Visual Studio 用 --config
第三方包找不到没安装包或 CMAKE_PREFIX_PATH 不正确安装依赖,或配置 -DCMAKE_PREFIX_PATH=...