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.txt
在Step1
目錄中創建一個 文件,如下所示:
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_STANDARD
將CMakeLists.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
構建目錄進行構建。 .