cmake

cmake

熱門

CMake 建置系統技能,適用於 C/C++ 專案。當需要編寫或重構 CMakeLists.txt、設定 out-of-source 建置、選擇產生器(Ninja、Make、VS)、使用 target_link_libraries 管理目標與相依性、透過 find_package 或 FetchContent 整合外部套件、啟用 sanitizers、設定交叉編譯工具鏈檔案,或匯出 CMake 套件時使用。當查詢涉及 CMakeLists.txt、cmake 設定錯誤、目標屬性、安裝規則、CPack 或 CMake Presets 時啟動。

188星標
25分支
更新於 2026/6/27
SKILL.md
唯讀
名稱
cmake
描述

CMake 建置系統技能,適用於 C/C++ 專案。當需要編寫或重構 CMakeLists.txt、設定 out-of-source 建置、選擇產生器(Ninja、Make、VS)、使用 target_link_libraries 管理目標與相依性、透過 find_package 或 FetchContent 整合外部套件、啟用 sanitizers、設定交叉編譯工具鏈檔案,或匯出 CMake 套件時使用。當查詢涉及 CMakeLists.txt、cmake 設定錯誤、目標屬性、安裝規則、CPack 或 CMake Presets 時啟動。

CMake

目的

引導代理程式使用現代(以目標為優先)的 CMake 來建置 C/C++ 專案:out-of-source 建置、相依性管理、產生器選擇,以及與 CI 和 IDE 的整合。

觸發時機

  • 「如何為我的專案撰寫 CMakeLists.txt?」
  • 「如何使用 CMake 加入外部函式庫?」
  • 「CMake 找不到我的套件/函式庫」
  • 「如何在 CMake 中啟用 sanitizers?」
  • 「如何使用 CMake 進行交叉編譯?」
  • 「如何使用 CMake Presets?」

工作流程

1. 現代 CMake 原則

  • 定義目標,而非變數。使用 target_* 指令。
  • 使用 PUBLICPRIVATEINTERFACE 控制屬性傳播。
  • 絕不要使用 include_directories()link_libraries()(舊式)。
  • 最低 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. 設定與建置

# Out-of-source 建置(務必這樣做)
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>
)

產生器運算式:$<condition:value> 在建置時求值。

7. 啟用 sanitizers

option(ENABLE_ASAN "Enable 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 整合的詳細資訊