步驟 2:新增程式庫¶
目前,我們已經了解如何使用 CMake 建立基本專案。在此步驟中,我們將學習如何在專案中建立和使用程式庫。我們還將了解如何讓程式庫的使用成為可選的。
練習 1 - 建立程式庫¶
若要在 CMake 中新增程式庫,請使用 add_library()
命令,並指定哪些來源檔案應構成程式庫。
我們可以將專案組織為一個或多個子目錄,而不是將所有來源檔案放在一個目錄中。在此情況下,我們將專門為程式庫建立一個子目錄。在這裡,我們可以新增一個新的 CMakeLists.txt
檔案和一個或多個來源檔案。在頂層的 CMakeLists.txt
檔案中,我們將使用 add_subdirectory()
命令將子目錄新增至建置。
建立程式庫後,會使用 target_include_directories()
和 target_link_libraries()
將其連接到我們的可執行目標。
目標¶
新增並使用程式庫。
實用資源¶
要編輯的檔案¶
CMakeLists.txt
tutorial.cxx
MathFunctions/CMakeLists.txt
開始使用¶
在此練習中,我們將在專案中新增一個程式庫,其中包含我們自己計算數字平方根的實作。然後,可執行檔可以使用此程式庫,而不是編譯器提供的標準平方根函式。
在本教學中,我們將把程式庫放入名為 MathFunctions
的子目錄中。此目錄已包含標頭檔案 MathFunctions.h
和 mysqrt.h
。它們各自的來源檔案 MathFunctions.cxx
和 mysqrt.cxx
也會提供。我們不需要修改任何這些檔案。mysqrt.cxx
有一個名為 mysqrt
的函式,其功能與編譯器的 sqrt
函式類似。MathFunctions.cxx
包含一個函式 sqrt
,用於隱藏 sqrt
的實作詳細資料。
從 Help/guide/tutorial/Step2
目錄中,從 TODO 1
開始,完成到 TODO 6
。
首先,填寫 MathFunctions
子目錄中的單行 CMakeLists.txt
。
接下來,編輯頂層的 CMakeLists.txt
。
最後,在 tutorial.cxx
中使用新建立的 MathFunctions
程式庫
建置並執行¶
執行 cmake
可執行檔或 cmake-gui
來設定專案,然後使用您選擇的建置工具來建置它。
以下是從命令列執行的樣子
mkdir Step2_build
cd Step2_build
cmake ../Step2
cmake --build .
嘗試使用新建立的 Tutorial
,並確保它仍然產生精確的平方根值。
解決方案¶
在 MathFunctions
目錄中的 CMakeLists.txt
檔案中,我們使用 add_library()
建立名為 MathFunctions
的程式庫目標。程式庫的來源檔案會作為引數傳遞給 add_library()
。這看起來像以下這行
TODO 1:點擊以顯示/隱藏答案
add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)
為了使用新的程式庫,我們將在頂層的 CMakeLists.txt
檔案中新增一個 add_subdirectory()
呼叫,以便建置程式庫。
TODO 2:點擊以顯示/隱藏答案
add_subdirectory(MathFunctions)
接下來,使用 target_link_libraries()
將新的程式庫目標連結到可執行目標。
TODO 3:點擊以顯示/隱藏答案
target_link_libraries(Tutorial PUBLIC MathFunctions)
最後,我們需要指定程式庫的標頭檔案位置。修改現有的 target_include_directories()
呼叫,將 MathFunctions
子目錄新增為包含目錄,以便可以找到 MathFunctions.h
標頭檔案。
TODO 4:點擊以顯示/隱藏答案
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)
現在讓我們使用我們的程式庫。在 tutorial.cxx
中,包含 MathFunctions.h
TODO 5:點擊以顯示/隱藏答案
#include "MathFunctions.h"
最後,將 sqrt
取代為包裝函式 mathfunctions::sqrt
。
TODO 6:點擊以顯示/隱藏答案
const double outputValue = mathfunctions::sqrt(inputValue);
練習 2 - 新增選項¶
現在,讓我們在 MathFunctions 程式庫中新增一個選項,允許開發人員選擇自訂的平方根實作或內建的標準實作。雖然對於本教學而言,確實沒有任何必要這樣做,但對於較大型的專案來說,這是一種常見的情況。
CMake 可以使用 option()
命令來做到這一點。這會給使用者一個變數,讓他們在設定 CMake 建置時可以變更。此設定會儲存在快取中,這樣使用者每次在建置目錄上執行 CMake 時就不需要設定值。
目標¶
新增一個選項,讓建置時不包含 MathFunctions
。
實用資源¶
要編輯的檔案¶
MathFunctions/CMakeLists.txt
MathFunctions/MathFunctions.cxx
開始入門¶
從練習 1 的結果檔案開始。完成 TODO 7
到 TODO 14
。
首先,使用 option()
命令在 MathFunctions/CMakeLists.txt
中建立一個變數 USE_MYMATH
。在同一個檔案中,使用該選項將編譯定義傳遞到 MathFunctions
函式庫。
然後,更新 MathFunctions.cxx
,根據 USE_MYMATH
來重新導向編譯。
最後,當 USE_MYMATH
開啟時,透過在 MathFunctions/CMakeLists.txt
的 USE_MYMATH
區塊內將 mysqrt.cxx
設為自己的函式庫,以防止編譯 mysqrt.cxx
。
建置與執行¶
由於我們已經從練習 1 設定了我們的建置目錄,我們可以透過簡單地呼叫以下內容來重新建置
cd ../Step2_build
cmake --build .
接下來,在幾個數字上執行 Tutorial
可執行檔,以驗證它是否仍然正確。
現在讓我們將 USE_MYMATH
的值更新為 OFF
。最簡單的方法是使用 cmake-gui
或 ccmake
(如果您在終端機中)。或者,如果您想從命令列變更選項,請嘗試
cmake ../Step2 -DUSE_MYMATH=OFF
現在,使用以下命令重新建置程式碼
cmake --build .
然後,再次執行可執行檔,以確保當 USE_MYMATH
設定為 OFF
時它仍然可以正常運作。哪個函數提供更好的結果,sqrt
還是 mysqrt
?
解答¶
第一步是在 MathFunctions/CMakeLists.txt
中新增一個選項。此選項會顯示在 cmake-gui
和 ccmake
中,預設值為 ON
,使用者可以變更。
TODO 7:點擊以顯示/隱藏解答
option(USE_MYMATH "Use tutorial provided math implementation" ON)
接下來,使用這個新選項來有條件地建置和連結包含 mysqrt
函數的函式庫。
建立一個 if()
陳述式,檢查 USE_MYMATH
的值。在 if()
區塊內,放置 target_compile_definitions()
命令,並帶有編譯定義 USE_MYMATH
。
TODO 8:點擊以顯示/隱藏解答
if (USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
endif()
當 USE_MYMATH
為 ON
時,會設定編譯定義 USE_MYMATH
。然後,我們可以使用此編譯定義來啟用或停用原始程式碼的區段。
對原始程式碼的相應變更相當簡單。在 MathFunctions.cxx
中,我們讓 USE_MYMATH
控制要使用哪個平方根函數
TODO 9:點擊以顯示/隱藏解答
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif
接下來,如果定義了 USE_MYMATH
,我們需要包含 mysqrt.h
。
TODO 10:點擊以顯示/隱藏解答
#ifdef USE_MYMATH
# include "mysqrt.h"
#endif
最後,現在我們正在使用 std::sqrt
,因此需要包含 cmath
。
TODO 11:點擊以顯示/隱藏解答
#include <cmath>
此時,如果 USE_MYMATH
為 OFF
,則不會使用 mysqrt.cxx
,但仍會編譯它,因為 MathFunctions
目標的來源下列出了 mysqrt.cxx
。
有幾種方法可以解決這個問題。第一種方法是使用 target_sources()
從 USE_MYMATH
區塊內新增 mysqrt.cxx
。另一種方法是在 USE_MYMATH
區塊內建立一個額外的函式庫,負責編譯 mysqrt.cxx
。為了本教學課程的緣故,我們將建立一個額外的函式庫。
首先,從 USE_MYMATH
內,建立一個名為 SqrtLibrary
的函式庫,其來源為 mysqrt.cxx
。
TODO 12:點擊以顯示/隱藏解答
add_library(SqrtLibrary STATIC
mysqrt.cxx
)
# TODO 6: Link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
接下來,當啟用 USE_MYMATH
時,我們將 SqrtLibrary
連結到 MathFunctions
。
TODO 13:點擊以顯示/隱藏解答
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
最後,我們可以從我們的 MathFunctions
函式庫來源清單中移除 mysqrt.cxx
,因為在包含 SqrtLibrary
時會將其提取進來。
TODO 14:點擊以顯示/隱藏解答
add_library(MathFunctions MathFunctions.cxx)
透過這些變更,現在對建置和使用 MathFunctions
函式庫的任何人來說,mysqrt
函數現在完全是選用的。使用者可以切換 USE_MYMATH
來操作在建置中使用的函式庫。