步驟 1:基本起點

我該如何開始使用 CMake?此步驟將介紹 CMake 的一些基本語法、命令和變數。在介紹這些概念時,我們將完成三個練習並建立一個簡單的 CMake 專案。

此步驟中的每個練習都將從一些背景資訊開始。然後,會提供目標和有用的資源列表。「要編輯的檔案」區段中的每個檔案都位於 Step1 目錄中,並且包含一個或多個 TODO 註解。每個 TODO 代表要變更或新增的一兩行程式碼。這些 TODO 應按數字順序完成,首先完成 TODO 1,然後完成 TODO 2,依此類推。「入門」區段將提供一些有用的提示,並引導您完成練習。然後「建置和執行」區段將逐步說明如何建置和測試練習。最後,在每個練習的結尾,將討論預期的解決方案。

另請注意,本教學中的每個步驟都會以前一個步驟為基礎。因此,例如,Step2 的起始程式碼是 Step1 的完整解決方案。

練習 1 - 建置基本專案

最基本的 CMake 專案是從單一原始碼檔案建置的可執行檔。對於像這樣簡單的專案,只需要一個包含三個命令的 CMakeLists.txt 檔案。

注意:儘管 CMake 支援大寫、小寫和混合大小寫的命令,但首選小寫命令,並將在本教學中使用。

任何專案的最上層 CMakeLists.txt 都必須先使用 cmake_minimum_required() 命令指定最低 CMake 版本。這會建立原則設定,並確保後續的 CMake 函式以相容的 CMake 版本執行。

若要啟動專案,我們使用 project() 命令設定專案名稱。每個專案都必須呼叫此命令,且應在 cmake_minimum_required() 之後立即呼叫。稍後我們將看到,此命令也可用於指定其他專案層級的資訊,例如語言或版本號碼。

最後,add_executable() 命令會告知 CMake 使用指定的原始碼檔案建立可執行檔。

目標

了解如何建立簡單的 CMake 專案。

有用的資源

要編輯的檔案

  • CMakeLists.txt

入門

tutorial.cxx 的原始碼在 Help/guide/tutorial/Step1 目錄中提供,可用於計算數字的平方根。在此步驟中不需要編輯此檔案。

在同一目錄中,有一個 CMakeLists.txt 檔案,您將會完成該檔案。從 TODO 1 開始,並完成 TODO 3

建置和執行

完成 TODO 1TODO 3 之後,我們就可以建置和執行我們的專案了!首先,執行 cmake 可執行檔或 cmake-gui 來設定專案,然後使用您選擇的建置工具建置它。

例如,從命令列中,我們可以導覽至 CMake 原始碼樹狀結構的 Help/guide/tutorial 目錄,並建立建置目錄

mkdir Step1_build

接下來,導覽至該建置目錄並執行 cmake 來設定專案,並產生原生建置系統

cd Step1_build
cmake ../Step1

然後呼叫該建置系統來實際編譯/連結專案

cmake --build .

對於多重設定產生器 (例如 Visual Studio),請先導覽至適當的子目錄,例如

cd Debug

最後,嘗試使用新建立的 Tutorial

Tutorial 4294967296
Tutorial 10
Tutorial

注意:根據 Shell 的不同,正確的語法可能是 Tutorial./Tutorial.\Tutorial。為了簡潔起見,練習將全程使用 Tutorial

解決方案

如上所述,我們只需要一個三行的 CMakeLists.txt 即可開始運作。第一行是使用 cmake_minimum_required() 來設定 CMake 版本,如下所示

TODO 1:點擊以顯示/隱藏答案
TODO 1: CMakeLists.txt
cmake_minimum_required(VERSION 3.10)

建立基本專案的下一步是使用 project() 命令,如下所示,設定專案名稱

TODO 2:點擊以顯示/隱藏答案
TODO 2: CMakeLists.txt
project(Tutorial)

基本專案要呼叫的最後一個命令是 add_executable()。我們呼叫它的方式如下

TODO 3:點擊以顯示/隱藏答案
TODO 3: CMakeLists.txt
add_executable(Tutorial tutorial.cxx)

練習 2 - 指定 C++ 標準

CMake 有一些特殊的變數,這些變數是在幕後建立的,或是在專案程式碼設定時對 CMake 具有意義。許多這些變數都以 CMAKE_ 開頭。在為您的專案建立變數時,請避免使用此命名慣例。其中兩個特殊的使用者可設定變數是 CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIRED。這些可以一起使用來指定建置專案所需的 C++ 標準。

目標

新增需要 C++11 的功能。

有用的資源

要編輯的檔案

  • CMakeLists.txt

  • tutorial.cxx

入門

繼續編輯 Step1 目錄中的檔案。從 TODO 4 開始,完成到 TODO 6

首先,編輯 tutorial.cxx,加入需要 C++11 的功能。然後更新 CMakeLists.txt 以要求 C++11。

建置和執行

讓我們再次建置專案。由於我們已經為練習 1 建立了一個建置目錄並執行了 CMake,我們可以跳到建置步驟。

cd Step1_build
cmake --build .

現在我們可以嘗試使用新建立的 Tutorial,並使用與之前相同的指令。

Tutorial 4294967296
Tutorial 10
Tutorial

解決方案

首先,我們在 tutorial.cxx 中將 atof 替換為 std::stod,為我們的專案新增一些 C++11 的功能。如下所示:

待辦事項 4:點擊以顯示/隱藏答案
待辦事項 4:tutorial.cxx
  const double inputValue = std::stod(argv[1]);

要完成 待辦事項 5,只需移除 #include <cstdlib>

我們需要在 CMake 程式碼中明確聲明它應該使用正確的標誌。在 CMake 中啟用對特定 C++ 標準的支援的一種方法是使用 CMAKE_CXX_STANDARD 變數。在本教學中,將 CMakeLists.txt 檔案中的 CMAKE_CXX_STANDARD 變數設為 11,並將 CMAKE_CXX_STANDARD_REQUIRED 設為 True。請確保在呼叫 add_executable() 之前,新增 CMAKE_CXX_STANDARD 宣告。

待辦事項 6:點擊以顯示/隱藏答案
待辦事項 6:CMakeLists.txt
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

練習 3 - 新增版本號碼和設定的標頭檔

有時,讓在您的 CMakelists.txt 檔案中定義的變數也能在您的原始碼中使用可能會很有用。在這種情況下,我們想要列印專案版本。

達成此目的的一種方法是使用設定的標頭檔。我們建立一個輸入檔案,其中包含一個或多個要取代的變數。這些變數具有特殊的語法,看起來像 @VAR@。然後,我們使用 configure_file() 指令將輸入檔案複製到指定的輸出檔案,並將這些變數取代為 CMakelists.txt 檔案中 VAR 的目前值。

雖然我們可以 ​​直接在原始碼中編輯版本,但最好使用此功能,因為它可以建立單一的真值來源,並避免重複。

目標

定義並報告專案的版本號碼。

實用資源

要編輯的檔案

  • CMakeLists.txt

  • tutorial.cxx

開始使用

繼續編輯 Step1 中的檔案。從 待辦事項 7 開始,一直完成到 待辦事項 12。在此練習中,我們先在 CMakeLists.txt 中新增專案版本號碼。在同一個檔案中,使用 configure_file() 將指定的輸入檔案複製到輸出檔案,並取代輸入檔案內容中的一些變數值。

接下來,建立一個輸入標頭檔 TutorialConfig.h.in,定義版本號碼,它將接受從 configure_file() 傳遞的變數。

最後,更新 tutorial.cxx 以列印出其版本號碼。

建置並執行

讓我們再次建置專案。和之前一樣,我們已經建立了一個建置目錄並執行了 CMake,所以我們可以跳到建置步驟。

cd Step1_build
cmake --build .

驗證執行可執行檔時,現在會報告版本號碼,而無需任何引數。

解決方案

在此練習中,我們透過列印版本號碼來改進可執行檔。雖然我們可以完全在原始碼中執行此操作,但使用 CMakeLists.txt 可讓我們為版本號碼維護單一的資料來源。

首先,我們修改 CMakeLists.txt 檔案,使用 project() 指令來設定專案名稱和版本號碼。當呼叫 project() 指令時,CMake 會在幕後定義 Tutorial_VERSION_MAJORTutorial_VERSION_MINOR

待辦事項 7:點擊以顯示/隱藏答案
待辦事項 7:CMakeLists.txt
project(Tutorial VERSION 1.0)

然後,我們使用 configure_file() 來複製輸入檔案,並取代指定的 CMake 變數。

待辦事項 8:點擊以顯示/隱藏答案
待辦事項 8:CMakeLists.txt
configure_file(TutorialConfig.h.in TutorialConfig.h)

由於設定的檔案將寫入專案二進位目錄中,我們必須將該目錄新增至要搜尋的包含檔案的路徑清單中。

注意:在本教學中,我們將交替提及專案建置和專案二進位目錄。它們是相同的,不代表 bin/ 目錄。

我們使用 target_include_directories() 來指定可執行檔目標應該在何處尋找包含檔案。

待辦事項 9:點擊以顯示/隱藏答案
待辦事項 9:CMakeLists.txt
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

TutorialConfig.h.in 是要設定的輸入標頭檔。當從我們的 CMakeLists.txt 呼叫 configure_file() 時,@Tutorial_VERSION_MAJOR@@Tutorial_VERSION_MINOR@ 的值將被取代為 TutorialConfig.h 中專案的對應版本號碼。

待辦事項 10:點擊以顯示/隱藏答案
待辦事項 10:TutorialConfig.h.in
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

接下來,我們需要修改 tutorial.cxx 以包含設定的標頭檔 TutorialConfig.h

待辦事項 11:點擊以顯示/隱藏答案
待辦事項 11:tutorial.cxx
#include "TutorialConfig.h"

最後,我們透過如下更新 tutorial.cxx 來列印出可執行檔名稱和版本號碼。

待辦事項 12:點擊以顯示/隱藏答案
待辦事項 12:tutorial.cxx
  if (argc < 2) {
    // report version
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }