cmake

Installation
SKILL.md

CMake

用途

引导完成以目标为核心的现代 CMake(C/C++ 项目):源外构建、依赖管理、生成器选择,以及与 CI 和 IDE 的集成。

触发场景

  • "如何为项目编写 CMakeLists.txt?"
  • "如何用 CMake 添加外部库?"
  • "CMake 找不到我的包/库"
  • "如何在 CMake 中启用 Sanitizer?"
  • "如何用 CMake 进行交叉编译?"
  • "如何使用 CMake Presets?"

工作流程

1. 现代 CMake 原则

  • 定义目标,而非变量。使用 target_* 命令。
  • 使用 PUBLIC/PRIVATE/INTERFACE 控制属性传播。
  • 不使用 include_directories()link_libraries()(遗留 API)。
  • 最低 CMake 版本:大多数特性需要 cmake_minimum_required(VERSION 3.20)

2. 最小项目

cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0 LANGUAGES C CXX)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(myapp
    src/main.c
    src/utils.c
)

target_include_directories(myapp PRIVATE include)
target_compile_options(myapp PRIVATE -Wall -Wextra)

3. 静态库与共享库

# 静态库
add_library(mylib STATIC lib/foo.c lib/bar.c)
target_include_directories(mylib
    PUBLIC  include      # 消费者获得此 include 路径
    PRIVATE src          # 仅 mylib 自身可见
)

# 共享库
add_library(myshared SHARED lib/foo.c)
set_target_properties(myshared PROPERTIES
    VERSION   1.0.0
    SOVERSION 1
)

# 将可执行文件链接到库
add_executable(myapp src/main.c)
target_link_libraries(myapp PRIVATE mylib)

4. 配置与构建

# 源外构建(始终应这样做)
cmake -S . -B build
cmake --build build

# 指定生成器
cmake -S . -B build -G Ninja
cmake --build build -- -j$(nproc)

# Debug 构建
cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build-debug

# Release 构建
cmake -S . -B build-release -DCMAKE_BUILD_TYPE=Release
cmake --build build-release

# 安装
cmake --install build --prefix /usr/local

构建类型:DebugReleaseRelWithDebInfoMinSizeRel

5. 外部依赖

find_package(系统已安装的库)

find_package(OpenSSL REQUIRED)
target_link_libraries(myapp PRIVATE OpenSSL::SSL OpenSSL::Crypto)

find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)

find_package(ZLIB REQUIRED)
target_link_libraries(myapp PRIVATE ZLIB::ZLIB)

FetchContent(下载并构建依赖)

include(FetchContent)

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0
)
FetchContent_MakeAvailable(googletest)

add_executable(mytest test/test_foo.cpp)
target_link_libraries(mytest PRIVATE GTest::gtest_main mylib)

pkg-config 回退

find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBFOO REQUIRED libfoo>=1.2)
target_link_libraries(myapp PRIVATE ${LIBFOO_LIBRARIES})
target_include_directories(myapp PRIVATE ${LIBFOO_INCLUDE_DIRS})

6. 按构建配置设置编译选项

target_compile_options(myapp PRIVATE
    $<$<CONFIG:Debug>:-g -Og -fsanitize=address>
    $<$<CONFIG:Release>:-O2 -DNDEBUG>
    $<$<CXX_COMPILER_ID:GNU>:-fanalyzer>
    $<$<CXX_COMPILER_ID:Clang>:-Weverything>
)

target_link_options(myapp PRIVATE
    $<$<CONFIG:Debug>:-fsanitize=address>
)

生成器表达式:$<条件:值> 在构建时求值。

7. 启用 Sanitizer

option(ENABLE_ASAN "启用 AddressSanitizer" OFF)

if(ENABLE_ASAN)
    target_compile_options(myapp PRIVATE -fsanitize=address -fno-omit-frame-pointer -g -O1)
    target_link_options(myapp PRIVATE -fsanitize=address)
endif()

构建命令:cmake -DENABLE_ASAN=ON -S . -B build-asan && cmake --build build-asan

8. 交叉编译工具链文件

# toolchain-aarch64.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER   aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_SYSROOT /opt/aarch64-sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
cmake -S . -B build-arm -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64.cmake

9. CMake Presets(CMake 3.20+)

{
  "version": 6,
  "configurePresets": [
    {
      "name": "release",
      "displayName": "Release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "debug",
      "displayName": "Debug",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "ENABLE_ASAN": "ON"
      }
    }
  ],
  "buildPresets": [
    { "name": "release", "configurePreset": "release" },
    { "name": "debug",   "configurePreset": "debug" }
  ]
}
cmake --preset release
cmake --build --preset release

10. 常见错误

错误 原因 解决方法
Could not find package Foo 包未安装或前缀路径有误 安装开发包;设置 CMAKE_PREFIX_PATH
No CMAKE_CXX_COMPILER 找不到 C++ 编译器 安装 g++/clang++;检查 PATH
target_link_libraries called with wrong number of arguments 缺少 PUBLIC/PRIVATE/INTERFACE 添加关键字
Cannot find source file 拼写错误或相对路径有误 检查相对于 CMakeLists.txt 的路径
generator expression 错误 $<> 语法有误 查阅 CMake 文档确认表达式名称

完整 CMakeLists.txt 模板见 references/templates.md

相关技能

  • 使用 skills/build-systems/ninja 了解 Ninja 生成器的详细信息
  • 使用 skills/build-systems/make 了解 Make 生成器
  • 使用 skills/compilers/cross-gcc 配置交叉编译工具链
  • 使用 skills/runtimes/sanitizers 了解 Sanitizer 集成的详细信息
Related skills

More from killvxk/low-level-dev-skills-zh

Installs
1
First Seen
Mar 21, 2026