使用者互動指南

簡介

當軟體套件使用基於 CMake 的建置系統提供其軟體原始碼時,該軟體的消費者需要執行 CMake 使用者互動工具才能建置它。

行為良好的基於 CMake 的建置系統不會在原始碼目錄中建立任何輸出,因此通常,使用者會執行源外建置並在那裡執行建置。首先,必須指示 CMake 產生合適的建置系統,然後使用者呼叫建置工具來處理該產生的建置系統。產生的建置系統特定於用於產生它的機器,並且不可重新散佈。每個提供的原始軟體套件的消費者都需要使用 CMake 來產生特定於其系統的建置系統。

產生的建置系統通常應視為唯讀。CMake 檔案作為主要產物應完整指定建置系統,並且在產生建置系統後,例如不應有任何理由在 IDE 中手動填寫屬性。CMake 會定期重寫產生的建置系統,因此使用者的修改將會被覆寫。

本手冊中描述的功能和使用者介面可透過提供 CMake 檔案供所有基於 CMake 的建置系統使用。

CMake 工具在處理提供的 CMake 檔案時可能會向使用者報告錯誤,例如報告編譯器不受支援,或者編譯器不支援所需的編譯選項,或者找不到相依性。這些錯誤必須由使用者透過選擇不同的編譯器、安裝 相依性或指示 CMake 在哪裡找到它們等來解決。

命令列 cmake 工具

使用軟體原始碼的全新副本時,cmake(1) 的簡單但典型的用法是建立一個建置目錄並在那裡呼叫 cmake

$ cd some_software-1.4.2
$ mkdir build
$ cd build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/opt/the/prefix
$ cmake --build .
$ cmake --build . --target install

建議在與原始碼不同的目錄中建置,因為這樣可以保持原始碼目錄的原始狀態,允許使用多個工具鏈建置單個原始碼,並允許透過簡單地刪除建置目錄來輕鬆清除建置產物。

CMake 工具可能會報告警告,這些警告是針對軟體提供者的,而不是針對軟體消費者的。此類警告以「此警告適用於專案開發人員」結尾。使用者可以透過將 -Wno-dev 旗標傳遞給 cmake(1) 來停用此類警告。

cmake-gui 工具

更習慣於 GUI 介面的使用者可以使用 cmake-gui(1) 工具來呼叫 CMake 並產生建置系統。

必須先填寫原始碼和二進位目錄。始終建議為原始碼和建置使用不同的目錄。

Choosing source and binary directories

產生建置系統

可以使用多種使用者介面工具從 CMake 檔案產生建置系統。ccmake(1)cmake-gui(1) 工具會引導使用者設定各種必要的選項。cmake(1) 工具可以呼叫以在命令列上指定選項。本手冊描述可以使用任何使用者介面工具設定的選項,儘管每個工具設定選項的模式都不同。

命令列環境

當使用命令列建置系統(例如 MakefilesNinja)呼叫 cmake(1) 時,必須使用正確的建置環境,以確保建置工具可用。CMake 必須能夠找到適當的 建置 工具、編譯器、連結器和其他需要的工具。

在 Linux 系統上,適當的工具通常在系統範圍的位置提供,並且可以透過系統套件管理器輕鬆安裝。也可以使用使用者提供的或其他安裝在非預設位置的工具鏈。

當交叉編譯時,某些平台可能需要設定環境變數或提供腳本來設定環境。

Visual Studio 隨附多個命令提示字元和 vcvarsall.bat 腳本,用於設定命令列建置系統的正確環境。雖然在使用 Visual Studio 產生器時並非絕對必要使用相應的命令列環境,但這樣做沒有任何缺點。

當使用 Xcode 時,可能會安裝多個 Xcode 版本。要使用哪一個版本可以透過多種不同的方式選擇,但最常見的方法是

  • 在 Xcode IDE 的偏好設定中設定預設版本。

  • 透過 xcode-select 命令列工具設定預設版本。

  • 在執行 CMake 和建置工具時,透過設定 DEVELOPER_DIR 環境變數來覆寫預設版本。

為了方便起見,cmake-gui(1) 提供環境變數編輯器。

命令列 -G 選項

CMake 預設根據平台選擇產生器。通常,預設產生器足以讓使用者繼續建置軟體。

使用者可以使用 -G 選項覆寫預設產生器

$ cmake .. -G Ninja

cmake --help 的輸出包含 產生器 的列表,供使用者選擇。請注意,產生器名稱區分大小寫。

在類 Unix 系統(包括 Mac OS X)上,預設使用 Unix Makefiles 產生器。該產生器的一個變體也可以在 Windows 的各種環境中使用,例如 NMake MakefilesMinGW Makefiles 產生器。這些產生器會產生一個 Makefile 變體,可以使用 makegmakenmake 或類似工具執行。有關目標環境和工具的更多資訊,請參閱個別產生器的說明文件。

Ninja 產生器可在所有主要平台上使用。ninja 是一個構建工具,其使用案例類似於 make,但重點在效能和效率。

在 Windows 上,可以使用 cmake(1) 為 Visual Studio IDE 產生解決方案。Visual Studio 版本可以使用 IDE 的產品名稱指定,其中包含四位數的年份。還為其他方式提供了別名,Visual Studio 版本有時會以這些方式來稱呼,例如對應於 VisualC++ 編譯器產品版本的兩位數字,或是兩者的組合。

$ cmake .. -G "Visual Studio 2019"
$ cmake .. -G "Visual Studio 16"
$ cmake .. -G "Visual Studio 16 2019"

Visual Studio 產生器可以針對不同的架構。可以使用 -A 選項指定目標架構。

cmake .. -G "Visual Studio 2019" -A x64
cmake .. -G "Visual Studio 16" -A ARM
cmake .. -G "Visual Studio 16 2019" -A ARM64

在 Apple 上,可以使用 Xcode 產生器為 Xcode IDE 產生專案檔案。

某些 IDE(例如 KDevelop4、QtCreator 和 CLion)對基於 CMake 的構建系統有原生支援。這些 IDE 提供使用者介面,用於選擇要使用的底層產生器,通常是在 Makefile 或基於 Ninja 的產生器之間進行選擇。

請注意,在第一次調用 CMake 之後,無法使用 -G 變更產生器。若要變更產生器,必須刪除建置目錄,並從頭開始建置。

產生 Visual Studio 專案和解決方案檔案時,在初始執行 cmake(1) 時,可以使用其他幾個選項。

Visual Studio 工具組可以使用 cmake -T 選項指定。

$ # Build with the clang-cl toolset
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T ClangCL
$ # Build targeting Windows XP
$ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp

雖然 -A 選項指定 _目標_ 架構,但 -T 選項可以用來指定所用工具鏈的詳細資訊。例如,可以提供 -Thost=x64 來選擇主機工具的 64 位元版本。以下說明如何使用 64 位元工具,以及如何針對 64 位元目標架構進行建置:

$ cmake .. -G "Visual Studio 16 2019" -A x64 -Thost=x64

在 cmake-gui 中選擇產生器

「Configure」按鈕會觸發一個新對話方塊,以選擇要使用的 CMake 產生器。

Configuring a generator

命令列上可用的所有產生器在 cmake-gui(1) 中也可用。

Choosing a generator

在選擇 Visual Studio 產生器時,還有其他選項可用於設定要產生的架構。

Choosing an architecture for Visual Studio generators

設定建置變數

軟體專案通常需要在調用 CMake 時於命令列上設定變數。下表列出了一些最常用的 CMake 變數。

變數

意義

CMAKE_PREFIX_PATH

要搜尋 相依套件 的路徑

CMAKE_MODULE_PATH

要搜尋其他 CMake 模組的路徑

CMAKE_BUILD_TYPE

建置組態,例如 DebugRelease,決定除錯/最佳化旗標。這僅適用於單一組態的建置系統,例如 MakefileNinja。多重組態的建置系統(例如 Visual Studio 和 Xcode 的建置系統)會忽略此設定。

CMAKE_INSTALL_PREFIX

使用 install 建置目標將軟體安裝到的位置

CMAKE_TOOLCHAIN_FILE

包含交叉編譯資料(例如 工具鏈 系統根)的檔案。

BUILD_SHARED_LIBS

是否為沒有類型的 add_library() 命令建置共享程式庫而不是靜態程式庫

CMAKE_EXPORT_COMPILE_COMMANDS

產生一個 compile_commands.json 檔案,以便與基於 clang 的工具搭配使用

CMAKE_EXPORT_BUILD_DATABASE

產生一個 build_database.json 檔案,以便與基於 clang 的工具搭配使用

其他專案特定的變數可用於控制建置,例如啟用或停用專案的元件。

CMake 沒有提供在不同提供的建置系統之間如何命名此類變數的慣例,但具有前綴 CMAKE_ 的變數通常是指 CMake 本身提供的選項,不應在第三方選項中使用,第三方選項應改為使用自己的前綴。cmake-gui(1) 工具可以顯示由其前綴定義的群組中的選項,因此第三方確保他們使用自我一致的前綴是有意義的。

在命令列上設定變數

CMake 變數可以在建立初始建置時,於命令列上設定。

$ mkdir build
$ cd build
$ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Debug

或在後續調用 cmake(1) 時設定。

$ cd build
$ cmake . -DCMAKE_BUILD_TYPE=Debug

可以使用 -U 旗標來取消設定 cmake(1) 命令列上的變數。

$ cd build
$ cmake . -UMyPackage_DIR

最初在命令列上建立的 CMake 建置系統可以使用 cmake-gui(1) 修改,反之亦然。

cmake(1) 工具允許指定一個檔案,使用 -C 選項來填入初始快取。這對於簡化重複需要相同快取項目的命令和指令碼非常有用。

使用 cmake-gui 設定變數

可以使用「Add Entry」按鈕在 cmake-gui 中設定變數。這會觸發一個新對話方塊來設定變數的值。

Editing a cache entry

可以使用 cmake-gui(1) 使用者介面的主視圖來編輯現有的變數。

CMake 快取

執行 CMake 時,它需要尋找編譯器、工具和相依性的位置。它還需要能夠一致地重新產生建置系統,以使用相同的編譯/連結旗標和相依性路徑。此類參數也需要由使用者設定,因為它們是特定於使用者系統的路徑和選項。

當 CMake 首次執行時,它會在建置目錄中產生一個 CMakeCache.txt 檔案,其中包含此類工件的鍵值對。使用者可以透過執行 cmake-gui(1)ccmake(1) 工具來檢視或編輯快取檔案。這些工具提供了互動式介面,用於重新設定提供的軟體,並在編輯快取值後重新產生建置系統。每個快取條目可能都有一個相關的簡短說明文字,顯示在使用者介面工具中。

快取條目也可能有一個類型,表示它應如何在使用者介面中呈現。例如,類型為 BOOL 的快取條目可以在使用者介面中透過核取方塊進行編輯,STRING 可以在文字欄位中編輯,而 FILEPATH 雖然類似於 STRING,但也應提供一種使用檔案對話方塊來定位檔案系統路徑的方法。類型為 STRING 的條目可以提供一個允許值的限制列表,這些值會在 cmake-gui(1) 使用者介面中的下拉選單中提供(請參閱 STRINGS 快取屬性)。

隨附軟體套件的 CMake 檔案也可以使用 option() 命令來定義布林切換選項。此命令會建立一個具有說明文字和預設值的快取條目。此類快取條目通常是特定於提供的軟體,並影響建置的組態,例如是否建置測試和範例、是否啟用異常處理等。

預設值

CMake 可以理解一個檔案 CMakePresets.json 及其使用者特定的對應檔案 CMakeUserPresets.json,用於儲存常用設定的預設值。這些預設值可以設定建置目錄、產生器、快取變數、環境變數和其他命令列選項。所有這些選項都可以由使用者覆寫。 CMakePresets.json 格式的完整詳細資訊列在 cmake-presets(7) 手冊中。

在命令列上使用預設值

當使用 cmake(1) 命令列工具時,可以使用 --preset 選項來調用預設值。如果指定 --preset,則不需要產生器和建置目錄,但可以指定它們來覆寫預設值。例如,如果您有以下 CMakePresets.json 檔案

{
  "version": 1,
  "configurePresets": [
    {
      "name": "ninja-release",
      "binaryDir": "${sourceDir}/build/${presetName}",
      "generator": "Ninja",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ]
}

並且您執行以下命令

cmake -S /path/to/source --preset=ninja-release

這會在 /path/to/source/build/ninja-release 中產生一個建置目錄,使用 Ninja 產生器,並將 CMAKE_BUILD_TYPE 設定為 Release

如果您想查看可用的預設值列表,可以執行

cmake -S /path/to/source --list-presets

這將列出 /path/to/source/CMakePresets.json/path/to/source/CMakeUsersPresets.json 中可用的預設值,而不會產生建置樹。

在 cmake-gui 中使用預設值

如果專案有可用的預設值,無論是透過 CMakePresets.json 還是 CMakeUserPresets.json,預設值列表將會出現在 cmake-gui(1) 中,在來源目錄和二進位目錄之間的一個下拉選單中。選擇預設值會設定二進位目錄、產生器、環境變數和快取變數,但在選擇預設值後,所有這些選項都可以被覆寫。

調用建置系統

在產生建置系統後,可以透過調用特定的建置工具來建置軟體。對於 IDE 產生器,這可能涉及將產生的專案檔案載入 IDE 以調用建置。

CMake 知道調用建置所需的特定建置工具,因此一般而言,若要從命令列在產生後建置建置系統或專案,可以在建置目錄中調用以下命令

$ cmake --build .

--build 旗標啟用了 cmake(1) 工具的特定操作模式。它會調用與 generator 相關聯的 CMAKE_MAKE_PROGRAM 命令,或使用者設定的建置工具。

--build 模式也接受參數 --target 來指定要建置的特定目標,例如特定程式庫、可執行檔或自訂目標,或特定特殊目標,例如 install

$ cmake --build . --target myexe

--build 模式在多組態產生器的情況下也接受 --config 參數,以指定要建置的特定組態

$ cmake --build . --target myexe --config Release

如果產生器產生特定於組態的建置系統,且該組態是在使用 CMAKE_BUILD_TYPE 變數調用 cmake 時選擇的,則 --config 選項無效。

某些建置系統會省略建置期間調用的命令列詳細資訊。可以使用 --verbose 旗標來顯示這些命令列

$ cmake --build . --target myexe --verbose

--build 模式也可以將特定的命令列選項傳遞給底層建置工具,方法是在 -- 之後列出它們。這對於指定建置工具的選項很有用,例如在失敗的任務後繼續建置,而 CMake 沒有提供高階使用者介面。

對於所有產生器,可以在調用 CMake 後執行底層建置工具。例如,在使用 Unix Makefiles 產生器產生後可以執行 make 來調用建置,或在使用 Ninja 產生器產生後執行 ninja 等。IDE 建置系統通常提供用於建置專案的命令列工具,也可以調用這些工具。

選擇目標

在 CMake 檔案中描述的每個可執行檔和程式庫都是一個建置目標,並且建置系統可以描述自訂目標,無論是供內部使用還是供使用者使用,例如建立文件。

CMake 為所有提供 CMake 檔案的建置系統提供了一些內建目標。

all

預設目標由 MakefileNinja 產生器使用。它會建置建置系統中的所有目標,但那些被其 EXCLUDE_FROM_ALL 目標屬性或 EXCLUDE_FROM_ALL 目錄屬性排除的目標除外。對於 Xcode 和 Visual Studio 產生器,此目的會使用名稱 ALL_BUILD

help

列出可供建置的目標。當使用 Unix MakefilesNinja 產生器時,此目標可用,且確切的輸出與工具相關。

clean

刪除已建置的物件檔案和其他輸出檔案。基於 Makefile 的產生器會為每個目錄建立一個 clean 目標,以便可以清理個別目錄。Ninja 工具提供其自身的細微 -t clean 系統。

test

執行測試。僅當 CMake 檔案提供基於 CTest 的測試時,此目標才會自動可用。另請參閱 執行測試

install

安裝軟體。僅當軟體使用 install() 命令定義安裝規則時,此目標才會自動可用。另請參閱 軟體安裝

package

建立二進位套件。僅當 CMake 檔案提供基於 CPack 的套件時,此目標才會自動可用。

package_source

建立原始碼套件。僅當 CMake 檔案提供基於 CPack 的套件時,此目標才會自動可用。

對於基於 Makefile 的系統,會提供二進位建置目標的 /fast 變體。/fast 變體用於建置指定的目標,而不考慮其依賴項。不會檢查依賴項,且如果過期,也不會重建依賴項。由於 Ninja 產生器在依賴項檢查方面速度足夠快,因此不會為該產生器提供此類目標。

基於 Makefile 的系統還提供建置目標來預處理、組譯和編譯特定目錄中的個別檔案。

$ make foo.cpp.i
$ make foo.cpp.s
$ make foo.cpp.o

檔案副檔名已建置到目標的名稱中,因為可能存在另一個名稱相同但副檔名不同的檔案。不過,也會提供沒有檔案副檔名的建置目標。

$ make foo.i
$ make foo.s
$ make foo.o

在包含 foo.cfoo.cpp 的建置系統中,建置 foo.i 目標將會預處理這兩個檔案。

指定建置程式

--build 模式叫用的程式由 CMAKE_MAKE_PROGRAM 變數決定。對於大多數產生器,不需要設定特定的程式。

產生器

預設的 make 程式

替代方案

XCode

xcodebuild

Unix Makefiles

make

NMake Makefiles

nmake

jom

NMake Makefiles JOM

jom

nmake

MinGW Makefiles

mingw32-make

MSYS Makefiles

make

Ninja

ninja

Visual Studio

msbuild

Watcom WMake

wmake

jom 工具能夠讀取 NMake 風格的 makefile 並行建置,而 nmake 工具始終會循序建置。在使用 NMake Makefiles 產生器產生之後,使用者可以執行 jom 而非 nmake--build 模式也會在使用 NMake Makefiles 產生器時,如果 CMAKE_MAKE_PROGRAM 設定為 jom,則會使用 jom。為方便起見,提供 NMake Makefiles JOM 產生器,以正常方式尋找 jom,並將其用作 CMAKE_MAKE_PROGRAM。為了完整起見,nmake 是一種替代工具,可以處理 NMake Makefiles JOM 產生器的輸出,但這樣做是一種悲觀的作法。

軟體安裝

可以在 CMake 快取中設定 CMAKE_INSTALL_PREFIX 變數,以指定安裝所提供軟體的位置。如果所提供的軟體具有使用 install() 命令指定的安裝規則,則它們會將成品安裝到該前置詞中。在 Windows 上,預設的安裝位置對應於 ProgramFiles 系統目錄,該目錄可能與架構相關。在 Unix 主機上,/usr/local 是預設的安裝位置。

CMAKE_INSTALL_PREFIX 變數始終參考目標檔案系統上的安裝前置詞。

在交叉編譯或封裝案例中,當 sysroot 為唯讀或 sysroot 應保持原始狀態時,可以將 CMAKE_STAGING_PREFIX 變數設定為實際安裝檔案的位置。

以下命令

$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local \
  -DCMAKE_SYSROOT=$HOME/root \
  -DCMAKE_STAGING_PREFIX=/tmp/package
$ cmake --build .
$ cmake --build . --target install

會將檔案安裝到主機上的路徑,例如 /tmp/package/lib/libfoo.so。主機上的 /usr/local 位置不受影響。

某些提供的軟體可能會指定 uninstall 規則,但 CMake 預設不會自行產生此類規則。

執行測試

ctest(1) 工具隨 CMake 發行版一起提供,用於執行所提供的測試並報告結果。提供 test 建置目標來執行所有可用的測試,但 ctest(1) 工具允許細微控制要執行的測試、如何執行測試以及如何報告結果。在建置目錄中執行 ctest(1) 等同於執行 test 目標

$ ctest

可以傳遞正規表示式,以僅執行符合該表示式的測試。若要僅執行名稱中包含 Qt 的測試

$ ctest -R Qt

也可以透過正規表示式排除測試。若要僅執行名稱中不包含 Qt 的測試

$ ctest -E Qt

可以透過將 -j 引數傳遞給 ctest(1) 來並行執行測試

$ ctest -R Qt -j8

或者,可以設定環境變數 CTEST_PARALLEL_LEVEL,以避免需要傳遞 -j

預設情況下,ctest(1) 不會印出測試的輸出。命令列參數 -V (或 --verbose) 啟用詳細模式,以印出所有測試的輸出。--output-on-failure 選項只會印出失敗測試的輸出。環境變數 CTEST_OUTPUT_ON_FAILURE 可以設定為 1,作為傳遞 --output-on-failure 選項給 ctest(1) 的替代方案。