步驟 11:新增匯出組態

在教學的安裝 測試期間,我們新增了讓 CMake 安裝專案的程式庫和標頭檔的功能。在封裝 安裝程式期間,我們新增了封裝此資訊的功能,以便將其散佈給其他人。

下一步是新增必要的資訊,以便其他 CMake 專案可以使用我們的專案,無論是從建置目錄、本機安裝還是封裝。

第一步是更新我們的 install(TARGETS) 命令,不僅指定 DESTINATION,還指定 EXPORTEXPORT 關鍵字會產生一個 CMake 檔案,其中包含從安裝樹狀結構匯入安裝命令中列出的所有目標的程式碼。因此,讓我們繼續明確地 EXPORT MathFunctions 程式庫,方法是更新 MathFunctions/CMakeLists.txt 中的 install 命令,使其看起來像這樣

MathFunctions/CMakeLists.txt
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 的底部來完成

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 位置。這表示轉換 target_include_directories()MathFunctions 的呼叫,使其看起來像這樣

MathFunctions/CMakeLists.txt
target_include_directories(MathFunctions
                           INTERFACE
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
                            $<INSTALL_INTERFACE:include>
                           )

更新完成後,我們可以重新執行 CMake 並驗證它不再發出警告。

此時,我們已經讓 CMake 正確封裝了所需的目標資訊,但我們仍然需要產生一個 MathFunctionsConfig.cmake,以便 CMake find_package() 命令可以找到我們的專案。因此,讓我們繼續在專案的頂層新增一個名為 Config.cmake.in 的新檔案,內容如下

Config.cmake.in

@PACKAGE_INIT@

include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )

然後,為了正確設定和安裝該檔案,請將以下內容新增到頂層 CMakeLists.txt 的底部

CMakeLists.txt
install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)

接下來,我們執行 configure_package_config_file()。此命令將設定提供的檔案,但與標準 configure_file() 方式有一些具體差異。為了正確使用此函數,輸入檔案應該只有一行文字 @PACKAGE_INIT@,以及所需的內容。該變數將被替換為一個程式碼區塊,該區塊將設定的值轉換為相對路徑。這些新的值可以使用相同的名稱來引用,但在前面加上 PACKAGE_ 前綴。

CMakeLists.txt
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 相容,這表示此版本或任何更高版本都與請求的版本相容。

CMakeLists.txt
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
  COMPATIBILITY AnyNewerVersion
)

最後,設定要安裝的兩個產生檔案

CMakeLists.txt
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
  DESTINATION lib/cmake/MathFunctions
  )

此時,我們已經為我們的專案產生了一個可重新定位的 CMake 組態,該組態可以在專案安裝或封裝後使用。如果我們也希望從建置目錄中使用我們的專案,我們只需要將以下內容新增到頂層 CMakeLists.txt 的底部

CMakeLists.txt
export(EXPORT MathFunctionsTargets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)

透過此匯出呼叫,我們現在產生一個 MathFunctionsTargets.cmake,允許建置目錄中設定的 MathFunctionsConfig.cmake 被其他專案使用,而無需安裝它。