CMake
是一種跨平臺的免費開源軟件工具,用於使用與編譯器無關的方法來管理軟件的構建過程。在 Android Studio
上進行 NDK
開發默認就是使用 CMake
管理 C/C++
代碼,所以在學習 NDK
以前最好對 CMake
有必定的瞭解。php
本文主要以翻譯 CMake
的官方教程文檔爲主,加上本身的一些理解,該教程涵蓋了 CMake
的常見使用場景。因爲能力有限,翻譯部分採用機翻+人工校對,翻譯有問題的地方,說聲抱歉。html
開發環境:ios
示例程序地址c++
在上一步 「系統自檢」 中,除了在 TutorialConfig.h
中保存 HAVE_LOG
和 HAVE_EXP
值以外,還有更好的作法嗎?對於此示例,咱們將嘗試使用 target_compile_definitions
。git
首先,從 TutorialConfig.h.in
中刪除上一步的定義,在 mysqrt.cxx
中再也不包含 TutorialConfig.h
,移除上一步在 MathFunctions/CMakeLists.txt
中增長的額外包含。github
接下來,咱們能夠將 HAVE_LOG
和 HAVE_EXP
的檢查移至 MathFunctions/CMakeLists.txt
,而後添加將這些值指定爲 PRIVATE
編譯定義。shell
# does this system provide the log and exp functions?
# 該系統是否提供log和exp函數?
include(CheckSymbolExists)
set(CMAKE_REQUIRED_LIBRARIES "m")
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
複製代碼
完成這些更新後,在項目根目錄運行命令編譯項目和生成可執行文件:bash
cmake -B cmake-build-debug
cmake --build cmake-build-debug
複製代碼
在項目根目錄運行生成的可執行文件:ide
./cmake-build-debug/Tutorial 2
複製代碼
終端輸出:函數
Computing sqrt of 2 to be 1.41421 using log and exp
The square root of 2 is 1.41421
複製代碼
假設,出於本教程的目的,咱們決定再也不使用平臺日誌和exp函數,而是但願生成一個可在 mysqrt
函數中使用的預計算值表。在本節中,咱們將在構建過程當中建立表,而後將該表編譯到咱們的應用程序中。
首先,讓咱們取消對 MathFunctions/CMakeLists.txt
中的 log
和 exp
函數的檢查。而後從 mysqrt.cxx
中刪除對 HAVE_LOG
和 HAVE_EXP
的檢查。同時,咱們能夠刪除 #include <cmath>
。
在 MathFunctions
子目錄中,提供了一個名爲 MakeTable.cxx
的新源文件來生成表。
// A simple program that builds a sqrt table
#include <cmath>
#include <fstream>
#include <iostream>
int main(int argc, char *argv[]) {
// make sure we have enough arguments
if (argc < 2) {
return 1;
}
std::ofstream fout(argv[1], std::ios_base::out);
const bool fileOpen = fout.is_open();
if (fileOpen) {
fout << "double sqrtTable[] = {" << std::endl;
for (int i = 0; i < 10; ++i) {
fout << sqrt(static_cast<double>(i)) << "," << std::endl;
}
// close the table with a zero
fout << "0};" << std::endl;
fout.close();
}
return fileOpen ? 0 : 1; // return 0 if wrote the file
}
複製代碼
咱們能夠看到生成的表不是簡單的文本,而是一段C++代碼。而且該文件的文件名是由參數傳入決定的。
下一步是將適當的命令添加到 MathFunctions/CMakeLists.txt
文件中,以構建MakeTable
可執行文件,而後在構建過程當中運行它。須要一些命令來完成此操做。
首先,在 MathFunctions/CMakeLists.txt
的頂部,添加 MakeTable
的可執行文件,就像添加任何其餘可執行文件同樣。
# first we add the executable that generates the table
# 首先,咱們添加生成表的可執行文件
add_executable(MakeTable MakeTable.cxx)
複製代碼
而後,咱們添加一個自定義命令,該命令指定如何經過運行 MakeTable
來產生 Table.h
。
# add the command to generate the source code
# 添加命令以生成源代碼
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
複製代碼
接下來,咱們必須讓 CMake
知道 mysqrt.cxx
依賴生成的文件 Table.h
。這是經過將生成的 Table.h
添加到庫 MathFunctions
的源列表中來完成的。
# add the main library
# 添加主庫
add_library(MathFunctions
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
複製代碼
咱們還必須將當前的二進制目錄添加到包含目錄列表中,以便 mysqrt.cxx
能夠找到幷包含 Table.h
。
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
# 說明與咱們連接的任何人都須要包含當前源目錄才能找到 MathFunctions.h,而咱們不須要。
# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the
# Table.h include is an implementation detail
# state that we depend on our binary dir to find Table.h
# 聲明咱們依賴Tutorial_BINARY_DIR但消費者不依賴,由於包含Table.h是一個實現細節,咱們依賴二進制目錄來查找Table.h
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
複製代碼
如今,使用生成的表。首先,修改 mysqrt.cxx
以包含 Table.h
。接下來,咱們能夠重寫 mysqrt
函數以使用該表:
double mysqrt(double x) {
if (x <= 0) {
return 0;
}
double result = x;
if (x >= 1 && x < 10) {
std::cout << "Use the table to help find an initial value " << std::endl;
result = sqrtTable[static_cast<int>(x)];
}
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
return result;
}
複製代碼
在項目根目錄運行命令編譯項目和生成可執行文件:
cmake -B cmake-build-debug
cmake --build cmake-build-debug
複製代碼
在項目根目錄運行生成的可執行文件:
./cmake-build-debug/Tutorial 2
複製代碼
終端輸出:
Use the table to help find an initial value
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
Computing sqrt of 2 to be 1.41421
The square root of 2 is 1.41421
複製代碼
在項目根目錄運行生成的可執行文件:
./cmake-build-debug/Tutorial 12
複製代碼
終端輸出:
Computing sqrt of 12 to be 6.5
Computing sqrt of 12 to be 4.17308
Computing sqrt of 12 to be 3.52433
Computing sqrt of 12 to be 3.46462
Computing sqrt of 12 to be 3.4641
Computing sqrt of 12 to be 3.4641
Computing sqrt of 12 to be 3.4641
Computing sqrt of 12 to be 3.4641
Computing sqrt of 12 to be 3.4641
Computing sqrt of 12 to be 3.4641
The square root of 12 is 3.4641
複製代碼
接下來,假設咱們想將項目分發給其餘人,以便他們可使用它。咱們但願在各類平臺上提供二進制和源代碼分發。這與咱們以前在 「安裝」 示例進行的安裝有些不一樣,在以前安裝中,咱們根據源代碼構建的二進制文件進行安裝。
在此示例中,咱們將構建支持二進制安裝和程序包管理功能的安裝程序包。爲此,咱們將使用 CPack
建立平臺特定的安裝程序。具體來講,咱們須要在頂級 CMakeLists.txt
文件的底部添加幾行。
# setup installer
# 設置安裝程序
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include(CPack)
複製代碼
這就是所有,咱們首先包含 InstallRequiredSystemLibraries
,該模塊將包含項目在當前平臺所需的任何運行時庫。
接下來,咱們將一些項目信息設置給 CPack
變量,好比項目的許可證和版本信息。本示例中 License.txt
內容以下:
This is a License file.
複製代碼
最後,咱們包含 CPack
模塊,該模塊將使用這些變量和當前系統的其餘一些屬性來設置安裝程序。
在項目根目錄運行命令編譯項目:
cmake -B cmake-build-debug
複製代碼
在項目根目錄運行命令構建二進制發行版:
cd cmake-build-debug
cpack
複製代碼
在項目根目錄下生成了文件:
.
├── ...
├── Tutorial-1.0-Darwin.sh
├── Tutorial-1.0-Darwin.tar.gz
└── ...
複製代碼
注意:要指定生成器,請使用 -G
選項。對於多配置構建,請使用 -C
指定配置。例如:
cpack -G ZIP -C Debug
複製代碼
在項目根目錄運行命令構建源代碼分發:
cd cmake-build-debug
cpack --config CPackSourceConfig.cmake
複製代碼
在項目根目錄下生成了文件:
.
├── ...
├── Tutorial-1.0-Source.tar.Z
├── Tutorial-1.0-Source.tar.bz2
├── Tutorial-1.0-Source.tar.gz
├── Tutorial-1.0-Source.tar.xz
└── ...
複製代碼
咱們已經在 "測試" 示例中爲咱們的項目定義了許多測試。如今,咱們只須要運行這些測試並將其提交到儀表板便可。爲了包括對儀表板的支持,咱們在頂層 CMakeLists.txt
中包含了 CTest
模塊。
將如下內容:
# enable testing
# 啓用測試
enable_testing()
複製代碼
替換爲:
# enable dashboard scripting
# 啓用儀表板腳本
include(CTest)
複製代碼
CTest
模塊將自動調用 enable_testing()
,所以咱們能夠將其從 CMake
文件中刪除。咱們還須要在頂級目錄中建立一個 CTestConfig.cmake
文件,在該文件中咱們能夠指定項目的名稱以及提交儀表板的位置。
set(CTEST_PROJECT_NAME "CMakeTutorial")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial")
set(CTEST_DROP_SITE_CDASH TRUE)
複製代碼
CTest
將在運行時讀入該文件。
在項目根目錄運行命令編譯項目:
cmake -B cmake-build-debug
複製代碼
在項目根目錄運行命令生成儀表板:
cd cmake-build-debug
ctest –D Experimental
# 或者:ctest -VV –D Experimental
複製代碼
注意:對於多配置生成器(例如Visual Studio),必須指定配置類型:
ctest [-VV] -C Debug –D Experimental
複製代碼
或者從 IDE中
構建 Experimental
目標。
ctest
將構建和測試項目,並將結果提交給Kitware公共儀表板。儀表板的結果將被上傳到Kitware的公共儀表板:my.cdash.org/index.php?p…,以下圖所示: