步驟 1:基本起點

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

此步驟中的每個練習都將從一些背景資訊開始。然後,提供目標和有用的資源列表。「Files to Edit」區段中的每個檔案都位於「Step1」目錄中,並包含一個或多個「TODO」註解。每個「TODO」代表要變更或新增的一行或兩行程式碼。「TODO」旨在按數字順序完成,首先完成「TODO 1」,然後完成「TODO 2」,依此類推。「Getting Started」區段將提供一些有用的提示,並引導您完成練習。「Build and Run」區段將逐步引導您完成建置和測試練習。「Build and Run」區段將逐步引導您完成建置和測試練習。最後,在每個練習結束時,將討論預期的解決方案。

另請注意,本教學中的每個步驟都建立在下一個步驟的基礎上。因此,舉例來說,「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 1」到「TODO 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」中用「std::stod」取代「atof」,為我們的專案新增一些 C++11 功能。它看起來像這樣

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

要完成「TODO 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 宣告。

TODO 6:點擊以顯示/隱藏答案
TODO 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

  • TutorialConfig.h.in

開始入門

繼續編輯「Step1」中的檔案。從「TODO 7」開始,並完成「TODO 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_MAJOR」和「Tutorial_VERSION_MINOR」。

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

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

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

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

注意: 在本教學中,我們將交替使用專案建置和專案二進位目錄。這些是相同的,並非指「bin/」目錄。

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

TODO 9:點擊以顯示/隱藏答案
TODO 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」中專案的對應版本號碼。

TODO 10:點擊以顯示/隱藏答案
TODO 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」。

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

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

TODO 12:點擊以顯示/隱藏答案
TODO 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;
  }