跳到正文

Wiki

CMakePresets與構建安裝

約 16 分鐘閱讀

本文由簡體中文內容確定性轉換,並受版本化術語表保護。

CMakePresets.json 用來儲存常用的 CMake 配置。它解決的問題是:不要每次都手寫一長串 cmake -S ... -B ... -G ... -D... 命令。

本模板的 CMakePresets.json 如下:

{
  "version": 6,
  "cmakeMinimumRequired": {
    "major": 3,
    "minor": 25,
    "patch": 0
  },
  "configurePresets": [
    {
      "name": "linux-debug",
      "displayName": "Linux Debug",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/linux-debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
        "CMAKE_INSTALL_PREFIX": "${sourceDir}/install/linux-debug"
      }
    },
    {
      "name": "linux-release",
      "displayName": "Linux Release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/linux-release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
        "CMAKE_INSTALL_PREFIX": "${sourceDir}/install/linux-release"
      }
    }
  ],
  "buildPresets": [
    {
      "name": "linux-debug",
      "configurePreset": "linux-debug"
    },
    {
      "name": "linux-release",
      "configurePreset": "linux-release"
    }
  ]
}

1.根欄位

1.1.version

"version": 6

表示 CMakePresets.json 檔案格式版本,不是專案版本。

可以填什麼:

含義
123、... CMake preset 檔案格式版本
6 本模板使用的版本,適合 CMake 3.25 及以上

注意:

  1. 這裡不是 cmake_template 的版本號。
  2. 如果想相容更老的 CMake,要降低 version,但某些欄位可能不能再用。
  3. 如果本機 CMake 很新,也不一定要用最高 preset 版本;夠用即可。

1.2.cmakeMinimumRequired

"cmakeMinimumRequired": {
  "major": 3,
  "minor": 25,
  "patch": 0
}

表示讀取這個 preset 檔案所需的最低 CMake 版本。

可以填什麼:

欄位 示例 含義
major 3 主版本號
minor 25 次版本號
patch 0 補丁版本號

這個模板要求 CMake >= 3.25,是因為頂層 CMakeLists.txt 也寫了:

cmake_minimum_required(VERSION 3.25)

二者最好保持一致。

2.configurePresets

configurePresets 是"配置階段"的 preset。

配置階段對應命令:

cmake --preset linux-debug

它等價於告訴 CMake:

  1. 使用哪個生成器。
  2. 構建目錄在哪裡。
  3. 構建型別是什麼。
  4. 安裝目錄在哪裡。
  5. 是否生成 compile_commands.json

2.1.name

"name": "linux-debug"

preset 的機器可讀名稱。

可以填什麼:

寫法 說明
linux-debug 本模板 Debug preset
linux-release 本模板 Release preset
debug 也可以,但不如 linux-debug 清楚
gcc-debug 如果區分編譯器,可以這樣命名
clang-debug 如果新增 Clang preset,可以這樣命名

要求:

  1. 同一個數組裡不能重名。
  2. buildPresets 裡的 configurePreset 要引用這裡的名字。
  3. 命令列使用的就是這個名字。

示例:

cmake --preset linux-debug

2.2.displayName

"displayName": "Linux Debug"

給人看的名字,主要用於 IDE 顯示,例如 VSCode CMake Tools 的 preset 列表。

可以填什麼:

寫法 說明
Linux Debug 清晰
Linux Release 清晰
Debug 可以,但不區分平臺
Fedora GCC Debug 如果 preset 很多,可以寫更具體

這個欄位不影響實際構建邏輯。

2.3.generator

"generator": "Ninja"

指定 CMake 要生成什麼構建系統檔案。

Linux 常見可選值:

說明
Ninja 推薦,速度快,輸出乾淨,適合 VSCode CMake Tools
Unix Makefiles 傳統 Makefile 工作流
Ninja Multi-Config 多配置 Ninja,可同時管理 Debug / Release

本模板只支援 Linux,並且使用 Ninja,所以固定寫:

"generator": "Ninja"

如果使用 Unix Makefiles,構建命令仍然可以用:

cmake --build --preset linux-debug

但底層就不是 Ninja 了。

2.4.binaryDir

"binaryDir": "${sourceDir}/build/linux-debug"

指定構建目錄。

可以填什麼:

寫法 說明
${sourceDir}/build/linux-debug 推薦,構建產物留在專案內的 build 子目錄
${sourceDir}/build/debug 也可以,但不如 linux-debug 清楚
/tmp/my-build 可以放到專案外,但不適合作為模板預設值

常見宏:

含義
${sourceDir} 專案原始碼根目錄
${presetName} 當前 preset 名稱
${sourceParentDir} 原始碼根目錄的父目錄

也可以寫成:

"binaryDir": "${sourceDir}/build/${presetName}"

這樣 linux-debug 會自動生成到:

build/linux-debug

本模板顯式寫出目錄,是為了讓初學時更直觀。

2.5.cacheVariables

"cacheVariables": {
  "CMAKE_BUILD_TYPE": "Debug",
  "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
  "CMAKE_INSTALL_PREFIX": "${sourceDir}/install/linux-debug"
}

cacheVariables 等價於命令列中的 -D 引數。

例如:

"CMAKE_BUILD_TYPE": "Debug"

等價於:

-DCMAKE_BUILD_TYPE=Debug

3.常用 cache 變數

3.1.CMAKE_BUILD_TYPE

"CMAKE_BUILD_TYPE": "Debug"

單配置生成器中使用的構建型別。NinjaUnix Makefiles 都屬於常見的單配置生成器。

可以填什麼:

作用
Debug 除錯構建,通常帶 -g,最佳化較少
Release 釋出構建,通常開啟最佳化
RelWithDebInfo 最佳化 + 除錯資訊
MinSizeRel 最佳化體積

常用選擇:

場景 推薦
寫程式碼、除錯斷點 Debug
釋出、效能測試 Release
效能測試但還想保留符號 RelWithDebInfo
嵌入式或體積敏感 MinSizeRel

3.2.CMAKE_EXPORT_COMPILE_COMMANDS

"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"

是否生成 compile_commands.json

可以填什麼:

作用
ON 生成 compile_commands.json
OFF 不生成

compile_commands.json 記錄每個原始檔真實的編譯命令。clangd、VSCode、很多靜態分析工具都會用它來獲得 include 路徑、巨集定義、編譯標準等資訊。

建議模板裡固定開啟:

"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"

3.2.1.讓 clangd 找到 compile_commands.json

僅僅生成 compile_commands.json,不代表 clangd 一定能自動找到它。

在 VSCode 中使用這種方式前,需要安裝 LLVM 官方的 clangd 擴充套件。 CMake Tools 負責配置、構建和選擇 target,clangd 則負責程式碼補全、 跳轉定義、語義檢查等編輯功能,它們不是同一個擴充套件。

這個模板把 Debug 構建目錄設定為:

build/linux-debug/

因此執行:

cmake --preset linux-debug

之後,編譯資料庫位於:

build/linux-debug/compile_commands.json

clangd 預設會從當前原始檔所在目錄逐級向上尋找 compile_commands.json。它通常能找到專案根目錄或 build/ 直屬目錄 中的資料庫,但不一定會繼續搜尋 build/linux-debug/ 這樣的多層 preset 目錄。

如果 clangd 沒有找到資料庫,它會進入 fallback 模式,只用少量預設 引數分析原始檔。這時即使 CMake 可以正常編譯,VSCode 中仍可能出現:

  1. 專案標頭檔案顯示找不到。
  2. Eigen、OpenCV 等第三方庫顯示找不到。
  3. C++ 標準識別錯誤,例如工程使用 C++23,clangd 卻按照 C++17 分析。
  4. 跳轉定義、自動補全和錯誤提示不準確。

推薦在專案根目錄建立 .clangd

CompileFlags:
  CompilationDatabase: build/linux-debug

目錄結構會變成:

.
├── .clangd
├── CMakeLists.txt
├── CMakePresets.json
├── build/
│   └── linux-debug/
│       └── compile_commands.json
└── src/

CompilationDatabase 使用相對於 .clangd 所在目錄的路徑,所以不要 寫某個使用者電腦上的絕對路徑。這個檔案只儲存專案通用配置,可以提交到 Git。

注意,.clangd 不會生成編譯資料庫。第一次使用工程,或者修改了 CMakeLists.txt、編譯選項、依賴和 preset 後,仍然要重新執行:

cmake --preset linux-debug

或者在 VSCode CMake Tools 中選擇 linux-debug 並點選 Configure。

如果 .clangd 建立後沒有立即生效,可以在 VSCode 命令面板執行:

clangd: Restart language server

也可以關閉並重新開啟當前 .cpp 檔案。

如果同時安裝了 Microsoft C/C++ 擴充套件,並且編輯器出現兩套重複的錯誤 提示,可以保留該擴充套件提供的 GDB 除錯功能,同時關閉它的 IntelliSense, 讓 clangd 獨立負責程式碼分析。這屬於個人 VSCode 設定,不需要寫入 CMake 模板。

3.2.2.檢查 clangd 是否真的生效

在 VSCode 中開啟:

查看 -> 输出 -> clangd

正常情況下應當看到類似內容:

Loaded compilation database from .../build/linux-debug/compile_commands.json
Compile command from CDB is: ...

如果看到:

Failed to find compilation database
command clangd fallback

說明 clangd 仍然沒有讀到編譯資料庫。依次檢查:

  1. VSCode 開啟的是否為專案根目錄。
  2. .clangd 是否位於專案根目錄。
  3. 是否已經執行過 cmake --preset linux-debug
  4. build/linux-debug/compile_commands.json 是否真實存在。
  5. .clangd 中的目錄名是否與 binaryDir 完全一致。

如果系統終端中可以直接使用 clangd,還可以檢查單個原始檔:

clangd --check=src/main.cpp

輸出中應當顯示它載入了 build/linux-debug/compile_commands.json, 並使用 CMake 生成的 include 路徑、巨集定義和 C++ 標準。

3.2.3.使用 Release 資料庫

如果希望 clangd 按照 Release 配置分析,可以改成:

CompileFlags:
  CompilationDatabase: build/linux-release

並先生成對應資料庫:

cmake --preset linux-release

日常開發通常使用 build/linux-debug 即可。不要同時讓 .clangd 指向 一個尚未生成或已經過期的構建目錄。

3.3.CMAKE_INSTALL_PREFIX

"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/linux-debug"

指定安裝目錄。

可以填什麼:

寫法 說明
${sourceDir}/install/linux-debug 本模板 Debug 安裝目錄
${sourceDir}/install/linux-release 本模板 Release 安裝目錄
/usr/local 系統級安裝路徑,需要許可權,不適合作為模板預設
/opt/my_project 系統級或部署路徑

本模板把安裝目錄放在專案內,是為了方便學習和刪除。

安裝後執行:

./install/linux-debug/bin/cmake_template

4.buildPresets

buildPresets 是"構建階段"的 preset。

構建階段對應命令:

cmake --build --preset linux-debug

本模板寫法:

"buildPresets": [
  {
    "name": "linux-debug",
    "configurePreset": "linux-debug"
  },
  {
    "name": "linux-release",
    "configurePreset": "linux-release"
  }
]

4.1.name

"name": "linux-debug"

構建 preset 名稱。

一般建議和對應的 configure preset 同名,這樣命令比較一致:

cmake --preset linux-debug
cmake --build --preset linux-debug

4.2.configurePreset

"configurePreset": "linux-debug"

表示這個 build preset 使用哪個 configure preset 生成的構建目錄。

可以填什麼:

說明
linux-debug 使用 Debug 構建目錄
linux-release 使用 Release 構建目錄

必須對應 configurePresets 中已經存在的 name

5.常見可擴充套件欄位

初學時可以先不用,但以後可能會見到。

5.1.description

給 preset 新增更長的說明。

"description": "Debug build for Linux using Ninja"

5.2.hidden

隱藏某個 preset,不直接給使用者選擇,通常用於繼承。

"hidden": true

5.3.inherits

繼承另一個 preset,減少重複。

{
  "name": "linux-debug",
  "inherits": "linux-base",
  "cacheVariables": {
    "CMAKE_BUILD_TYPE": "Debug"
  }
}

5.4.environment

設定環境變數。

"environment": {
  "CC": "/usr/bin/gcc",
  "CXX": "/usr/bin/g++"
}

一般不建議模板預設寫死編譯器,除非你的專案明確要求某個工具鏈。

5.5.targets

指定預設構建哪些 target。

"targets": ["cmake_template"]

如果不寫,預設構建全部 target。

5.6.jobs

指定並行編譯數量。

"jobs": 8

不寫時由底層構建工具決定。

6.為什麼沒有 installPresets

很多人會猜測可以寫:

cmake --install --preset linux-debug

但常見 CMake preset 檔案並不使用這個根欄位。這個模板採用更通用的安裝命令:

cmake --install build/linux-debug

安裝命令需要傳入構建目錄,因為安裝規則是在 configure 階段生成到構建目錄裡的。

7.VSCode CMake Tools 工作流

安裝 VSCode 的 CMake Tools 擴充套件後,它會自動識別 CMakePresets.json

這一節把命令列操作和 VSCode 圖形介面操作對應起來。

7.1.開啟 CMake 面板

用 VSCode 開啟工程根目錄後,點選左側邊欄的 CMake

如果 CMake Tools 正常識別工程,你會看到 preset、Configure、Build、執行 target 等入口。

7.2.Configure

命令列:

cmake --preset linux-debug

在 VSCode 圖形介面中,對應的是:

  1. 點選 Configure。
  2. 選擇 Linux Debug

alt text

這一步會讀取:

CMakePresets.json
CMakeLists.txt

並生成:

build/linux-debug/

如果你改了 CMakeLists.txt、新增了原始檔、修改了第三方依賴,通常需要重新 Configure。

7.3.Build

命令列:

cmake --build --preset linux-debug

在 VSCode 圖形介面中,CMake Tools 會在 Configure 後識別對應的 build preset。

alt text

然後點選左下角或 CMake 面板裡的 Build 按鈕:

alt text

這一步會編譯 .cpp 檔案,並生成 build 目錄裡的執行檔和動態庫。

本模板的 Debug 執行檔通常在:

build/linux-debug/src/cmake_template

如果你只是修改了普通 .cpp 程式碼,一般只需要重新 Build,不一定要重新 Configure。

7.4.執行 build 目錄裡的程式

命令列:

./build/linux-debug/src/cmake_template

在 VSCode 圖形介面中,對應的是:

  1. 選擇執行/除錯 target。
  2. 選擇 cmake_template
  3. 點選執行按鈕。

alt text

alt text

執行後,終端裡會看到程式輸出。

alt text

如果你要斷點除錯,就點選 CMake Tools 提供的 Debug 按鈕;如果只是直接執行程式,就點選 Launch 按鈕。

除了上面的操作入口,VSCode 底部狀態列中,Build 按鈕旁邊也有 DebugLaunch 快捷按鈕。選擇好 cmake_template target 並完成構建後,可以直接點選這裡執行或除錯程式。

alt text

7.5.Install

命令列:

cmake --install build/linux-debug

在 VSCode 圖形介面中,可以按 Ctrl+Shift+P 開啟命令面板,然後輸入:

CMake: Install

alt text

如果當前選擇的是 linux-debug preset,它等同於:

cmake --install build/linux-debug

安裝後的程式在:

install/linux-debug/bin/cmake_template

日常寫程式碼、執行、除錯,一般直接使用 build 目錄裡的程式:

build/linux-debug/src/cmake_template

只有在驗證安裝佈局、標頭檔案安裝、動態庫 RPATH 或準備釋出程式時,才需要 install。

7.6.對應關係總結

你想做的事 命令列 VSCode CMake Tools
配置工程 cmake --preset linux-debug 選擇 Linux Debug 後點擊 Configure
編譯工程 cmake --build --preset linux-debug 點選 Build
執行 build 產物 ./build/linux-debug/src/cmake_template 選擇 cmake_template target 後點擊執行按鈕
除錯 build 產物 用 GDB 除錯 build/linux-debug/src/cmake_template 選擇 cmake_template target 後點擊 Debug 按鈕
安裝工程 cmake --install build/linux-debug 命令面板執行 CMake: Install

這樣不需要手寫 .vscode/tasks.json,也不需要額外準備 VSCode 除錯配置檔案。

8.執行與除錯注意事項

CMake Tools 可以直接執行或除錯當前選擇的可執行 target,所以不需要手寫額外的執行指令碼。

如果要除錯,建議安裝 Microsoft C/C++ 擴充套件和 GDB,因為 CMake Tools 負責選擇 target,真正的 C/C++ 偵錯程式仍然需要 GDB/LLDB 支援。

如果你只改了 .cpp 程式碼,一般重新 Build 後再執行或除錯即可。

如果你改了 CMakeLists.txt、新增原始檔、改依賴,建議先 Configure,再 Build,然後再執行或除錯。

8.1.為什麼不寫 tasks.json

舊模板常用 .vscode/tasks.json 寫一長串命令:

cmake ..
make install
source setup.bash
run app

這個模板不這樣做。原因是構建、執行和除錯入口都可以交給 CMake Tools 管理,命令列流程則由 CMakePresets.json 固化。

這樣職責更清楚:

檔案 負責
CMakePresets.json configure/build 引數
VSCode CMake Tools 選擇 preset、Configure、Build、執行和除錯 target
CMakeLists.txt target、依賴、安裝規則

8.2.需要安裝 gdb

Ubuntu/Debian:

sudo apt install gdb

Fedora:

sudo dnf install gdb

9.常見錯誤

9.1.忘記安裝 Ninja

報錯可能類似:

CMake was unable to find a build program corresponding to "Ninja"

解決:

sudo apt install ninja-build

或:

sudo dnf install ninja-build

9.2.preset 名稱寫錯

錯誤命令:

cmake --preset debug

如果檔案裡沒有 debug 這個 preset,就會失敗。

檢視可用 preset:

cmake --list-presets

9.3.build 前沒有 configure

如果第一次直接執行:

cmake --build --preset linux-debug

可能會因為構建目錄還沒有生成而失敗。

正確順序:

cmake --preset linux-debug
cmake --build --preset linux-debug