CMake教程(一)

CMake 是一個跨平臺的安裝(編譯)工具,可以用簡單的語句來描述所有平臺的安裝(編譯過程)。他能夠輸出各種各樣的makefile 或者 project 文件,能測試編譯器所支持的 C++ 特性,類似 UNIX 下的 automake 。只是 CMake 的組態檔取名爲 CMakeLists.txt。Cmake 並不直接建構出最終的軟件,而是產生標準的建構檔(如 Unix 的 Makefile 或 Windows Visual C++ 的 projects/workspaces),然後再依一般的建構方式使用。這使得熟悉某個集成開發環境(IDE)的開發者可以用標準的方式建構他的軟件,這種可以使用各平臺的原生建構系統的能力是 CMake 和 SCons 等其他類似系統的區別之處。

CMake 教程提供了逐步指南,涵蓋了 CMake 可以解決的常見構建系統問題。瞭解示例項目中各個主題如何協同工作將非常有幫助。教程文檔和示例的源代碼可以在 CMake 源代碼樹的Help/guide/tutorial目錄中找到 。每個步驟都有其自己的子目錄,其中包含可以用作起點的代碼。教程示例是漸進式的,因此每個步驟都爲上一步提供了完整的解決方案。

一個基本的出發點 (Step1)

最基本的項目是從源代碼文件構建的可執行文件。對於簡單的項目,只需三行CMakeLists.txt文件。這將是本教程的起點。CMakeLists.txtStep1目錄中創建一個 文件,如下所示:

cmake_minimum_required(VERSION 3.10)

# set the project name
project(Tutorial)

# add the executable
add_executable(Tutorial tutorial.cxx)

請注意,此示例在CMakeLists.txt文件中使用小寫命令。CMake 支持大寫,小寫和大小寫混合命令。Step1目錄中tutorial.cxx提供的源代碼,可用於計算數字的平方根。

添加一個版本號並配置頭文件

我們將添加的第一個功能是爲我們的可執行文件和項目提供版本號。雖然我們可以在源代碼中專門執行此操作,但使用 CMakeLists.txt可以提供更大的靈活性。

首先,修改CMakeLists.txt文件以使用project() 命令設置項目名稱和版本號。

cmake_minimum_required(VERSION 3.10)

# set the project name and version
project(Tutorial VERSION 1.0)

然後,配置頭文件以將版本號傳遞給源代碼:

configure_file(TutorialConfig.h.in TutorialConfig.h)

由於已配置的文件將被寫入二進制樹,因此我們必須將該目錄添加到路徑列表中以搜索包含文件。將以下行添加到CMakeLists.txt文件的末尾:

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

因爲配置文件將會寫入到構建目錄中,所以我們將這個目錄添加到包含文件的搜索路徑中。在源代碼中添加 TutorialConfig.h.in 文件:

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

當 CMake 生成這個頭文件時,@Tutorial_VERSION_MAJOR@@Tutorial_VERSION_MINOR@ 的值將會由 CMakeLists.txt 中對應的值替換。接下來我們將頭文件包含到 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;
  }

指定C++標準

接下來, 向我們的項目中添加一些 C++ 11 功能。

  const double inputValue = std::stod(argv[1]);

我們將需要在 CMake 代碼中明確聲明應使用正確的標誌。在 CMake 中啓用對特定 C++ 標準的支持的最簡單方法是使用CMAKE_CXX_STANDARD變量。對於本教程,請設置CMAKE_CXX_STANDARDCMakeLists.txt文件中的變量設置爲11並把CMAKE_CXX_STANDARD_REQUIRED 改爲True:

cmake_minimum_required(VERSION 3.10)

# set the project name and version
project(Tutorial VERSION 1.0)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

構建和測試

運行 cmake 可執行文件或 cmake-gui 配置項目,然後使用您選擇的構建工具進行構建。

例如,從命令行我們可以導航到Help/guide/tutorialCMake源代碼樹的目錄並運行以下命令:

mkdir Step1_build
cd Step1_build
cmake ../Step1
cmake --build .

導航到構建 Tutorial 的目錄(可能是make目錄或Debug或Release構建配置子目錄),然後運行以下命令:

Tutorial 4294967296
Tutorial 10
Tutorial

添加一個庫 (Step 2)

現在,我們將庫添加到我們的項目中。該庫將包含我們自己的實現,用於計算數字的平方根。然後可執行文件可以使用此庫,而不是使用編譯器提供的標準平方根函數。

在本教程中,我們將庫放入名爲的子目錄中 MathFunctions 。該目錄已經包含一個頭文件 MathFunctions.h 和一個源文件mysqrt.cxx。源文件具有一個mysqrt功能,該功能提供與編譯器sqrt功能相似的功能。

本教程中將這個庫放到名爲 MathFunctions 的子文件夾中,這個子文件夾需要包含一個 CMakeLists.txt 文件,文件中有如下一行:

add_library(MathFunctions mysqrt.cxx)

爲了利用新庫,我們將添加一個 add_subdirectory() 調用頂級 CMakeLists.txt 文件,以便構建庫。我們將新庫添加到可執行文件,並添加 MathFunctions 爲包含目錄,以便可以找到頭文件 mqsqrt.h。現在,頂級 CMakeLists.txt 文件的最後幾行應如下所示:

# add the MathFunctions library
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC MathFunctions)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/MathFunctions"
                          )

現在讓我們將 MathFunctions 庫設爲可選。雖然對於本教程而言確實沒有任何必要,但是對於較大的項目,這是常見的情況。第一步是向頂層 CMakeLists.txt 文件添加一個選項 。

option(USE_MYMATH "Use tutorial provided math implementation" ON)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)

此選項將顯示在 cmake-gui 和 ccmake 用戶可以更改的默認值 ON。此設置將存儲在緩存中,因此用戶無需在每次在構建目錄上運行 CMake 時都設置該值。

下一個更改是使建立和鏈接 MathFunctions 庫成爲條件。爲此,我們將頂級 CMakeLists.txt 文件的末尾更改爲如下所示:

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()

# add the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           ${EXTRA_INCLUDES}
                           )

請注意,使用變量EXTRA_LIBS來收集所有可選庫,以便以後鏈接到可執行文件中。該變量 EXTRA_INCLUDES類似地用於可選的頭文件。當處理許多可選組件時,這是一種經典方法,我們將在下一步中介紹現代方法。

對源代碼的相應更改非常簡單。首先,如果需要,請在 tutorial.cxx 中包含 MathFunctions.h 頭文件:

#ifdef USE_MYMATH
#  include "MathFunctions.h"
#endif

然後,在同一文件中,USE_MYMATH控制使用哪個平方根函數:

#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif

在源代碼中我們同樣使用了 USE_MYMATH 變量。通過在 TutorialConfig.h.in 中添加如下配置,Cmake 將這個變量引入到源代碼中:

#cmakedefine USE_MYMATH

添加庫的使用要求(Step 3)

使用要求可以更好地控制庫或可執行文件的鏈接幷包含行,同時還可以更好地控制 CMake 內部目標的傳遞屬性。利用使用需求的主要命令是:

target_compile_definitions()
target_compile_options()
target_include_directories()
target_link_libraries()

讓我們從添加庫(Step 2)中重構代碼,以使用現代 CMake 使用需求方法。我們首先聲明,鏈接到 MathFunctions 的任何人都需要包括當前源目錄,而 MathFunctions 本身不需要。因此這可能成爲INTERFACE使用要求。

記住INTERFACE是指消費者需要的東西,而生產者則不需要。將以下行添加到 MathFunctions/CMakeLists.txt 的末尾 :

target_include_directories(MathFunctions
          INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
          )

現在我們已經爲math_functions指定了使用要求,我們可以安全地從頂級 CMakeLists.txt 中刪除EXTRA_INCLUDES變量的使用:

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
endif()

以及這裏:

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

完成後,運行 cmake 可執行文件或 cmake-gui 配置項目,然後使用您選擇的構建工具或通過cmake --build構建目錄進行構建。 .

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章