步驟 11:新增匯出組態¶
在教學的安裝 與 測試
期間,我們新增了讓 CMake 安裝專案的函式庫與標頭檔的功能。在封裝 安裝程式
期間,我們新增了將這些資訊封裝起來以便分發給其他人的功能。
下一步是加入必要的資訊,讓其他 CMake 專案可以使用我們的專案,無論是從建置目錄、本機安裝還是封裝時。
第一步是更新我們的install(TARGETS)
指令,不僅要指定一個 DESTINATION
,還要指定一個 EXPORT
。EXPORT
關鍵字會產生一個 CMake 檔案,其中包含從安裝樹匯入 install 指令中列出的所有目標的程式碼。因此,讓我們繼續明確地 EXPORT
MathFunctions
函式庫,方法是將 MathFunctions/CMakeLists.txt
中的 install
指令更新為如下所示
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
EXPORT MathFunctionsTargets
DESTINATION lib)
# install include headers
install(FILES MathFunctions.h DESTINATION include)
既然我們已經匯出 MathFunctions
,我們也需要明確地安裝產生的 MathFunctionsTargets.cmake
檔案。這可以透過在最上層 CMakeLists.txt
的底部新增以下內容來完成
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
此時,您應該嘗試執行 CMake。如果一切都設定正確,您將會看到 CMake 會產生一個類似以下的錯誤
Target "MathFunctions" INTERFACE_INCLUDE_DIRECTORIES property contains
path:
"/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions"
which is prefixed in the source directory.
CMake 告訴您,在產生匯出資訊時,它將匯出一個與目前機器本質上相關的路徑,並且在其他機器上將無效。解決方案是更新 MathFunctions
的 target_include_directories()
,以便理解當從建置目錄以及從安裝/封裝中使用時,它需要不同的 INTERFACE
位置。這意味著要將 MathFunctions
的 target_include_directories()
呼叫轉換成如下所示
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
一旦更新完成,我們可以重新執行 CMake 並驗證它不再發出警告。
此時,我們已讓 CMake 正確地封裝所需的目標資訊,但我們仍然需要產生一個 MathFunctionsConfig.cmake
,以便 CMake 的 find_package()
指令可以找到我們的專案。因此,讓我們繼續在專案的最上層新增一個名為 Config.cmake.in
的檔案,其內容如下
@PACKAGE_INIT@
include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
然後,為了正確配置並安裝該檔案,請將以下內容新增至最上層 CMakeLists.txt
的底部
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
include(CMakePackageConfigHelpers)
接下來,我們執行 configure_package_config_file()
。此指令會配置提供的檔案,但與標準的 configure_file()
方式有一些特定的差異。為了正確使用此函式,輸入檔案除了所需的內容之外,還應該有一行文字 @PACKAGE_INIT@
。該變數將被替換為一段程式碼,該程式碼將設定的值轉換為相對路徑。這些新值可以使用相同的名稱來參考,但要在前面加上 PACKAGE_
字首。
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
include(CMakePackageConfigHelpers)
# generate the config file that includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION "lib/cmake/MathFunctions"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
接下來是 write_basic_package_version_file()
。此指令會寫入一個檔案,該檔案由 find_package()
使用,用於記錄所需套件的版本和相容性。在這裡,我們使用 Tutorial_VERSION_*
變數,並表示它與 AnyNewerVersion
相容,這表示此版本或任何更高版本都與請求的版本相容。
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
COMPATIBILITY AnyNewerVersion
)
最後,將兩個產生的檔案設定為要安裝
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
DESTINATION lib/cmake/MathFunctions
)
此時,我們已經為我們的專案產生了一個可重新定位的 CMake 組態,該組態可以在專案安裝或封裝後使用。如果我們希望我們的專案也可以從建置目錄中使用,我們只需將以下內容新增至最上層 CMakeLists.txt
的底部
export(EXPORT MathFunctionsTargets
FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)
透過這個匯出呼叫,我們現在產生一個 MathFunctionsTargets.cmake
,允許其他專案使用建置目錄中已設定的 MathFunctionsConfig.cmake
,而無需安裝。