CMakePackageConfigHelpers

用於建立設定檔的輔助函式,這些設定檔可被其他專案包含,以尋找並使用套件。

產生套件設定檔

configure_package_config_file

為專案建立設定檔

configure_package_config_file(<input> <output>
  INSTALL_DESTINATION <path>
  [PATH_VARS <var1> <var2> ... <varN>]
  [NO_SET_AND_CHECK_MACRO]
  [NO_CHECK_REQUIRED_COMPONENTS_MACRO]
  [INSTALL_PREFIX <path>]
  )

當為安裝專案或函式庫建立 <PackageName>Config.cmake<PackageName>-config.cmake 檔案時,應使用 configure_package_config_file() 取代一般的 configure_file() 命令。這有助於使產生的套件可重新定位,方法是避免在已安裝的 <PackageName>Config.cmake 檔案中硬式編碼路徑。

FooConfig.cmake 檔案中,可能有如下程式碼,使使用專案知道安裝目的地

set(FOO_INCLUDE_DIR   "@CMAKE_INSTALL_FULL_INCLUDEDIR@" )
set(FOO_DATA_DIR   "@CMAKE_INSTALL_PREFIX@/@RELATIVE_DATA_INSTALL_DIR@" )
set(FOO_ICONS_DIR   "@CMAKE_INSTALL_PREFIX@/share/icons" )
#...logic to determine installedPrefix from the own location...
set(FOO_CONFIG_DIR  "${installedPrefix}/@CONFIG_INSTALL_DIR@" )

以上顯示的所有四個選項都不夠。前三個硬式編碼了絕對目錄位置。第四種情況僅在確定 installedPrefix 的邏輯正確,且 CONFIG_INSTALL_DIR 包含相對路徑時才有效,而這在一般情況下無法保證。這導致產生的 FooConfig.cmake 檔案在 Windows 和 macOS 下效果不佳,因為使用者習慣在安裝時選擇二進制套件的安裝位置,而與在建置/cmake 時如何設定 CMAKE_INSTALL_PREFIX 無關。

使用 configure_package_config_file() 有幫助。如果使用正確,它會使產生的 FooConfig.cmake 檔案可重新定位。用法

  1. 依照您習慣的方式撰寫 FooConfig.cmake.in 檔案。

  2. 在頂端插入一行,僅包含字串 @PACKAGE_INIT@

  3. 不要使用 set(FOO_DIR "@SOME_INSTALL_DIR@"),而使用 set(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@") (這必須在 @PACKAGE_INIT@ 行之後)。

  4. 不要使用一般的 configure_file() 命令,而使用 configure_package_config_file()

<input><output> 引數是輸入和輸出檔案,與 configure_file() 中的方式相同。

提供給 INSTALL_DESTINATION<path> 必須是 FooConfig.cmake 檔案將安裝到的目的地。此路徑可以是絕對路徑,也可以是相對於 INSTALL_PREFIX 路徑的相對路徑。

作為 PATH_VARS 提供的變數 <var1><varN> 是包含安裝目的地的變數。對於每個變數,巨集將建立一個輔助變數 PACKAGE_<var...>。這些輔助變數必須在 FooConfig.cmake.in 檔案中使用,以設定已安裝的位置。它們由 configure_package_config_file() 計算,使其始終相對於套件的已安裝位置。這對於相對位置和絕對位置都有效。對於絕對位置,只有當絕對位置是 INSTALL_PREFIX 的子目錄時才有效。

在 3.30 版本中新增: 變數 PACKAGE_PREFIX_DIR 將始終在 @PACKAGE_INIT@ 行之後定義。它將保存基本安裝位置的值。通常,應使用透過 PATH_VARS 機制定義的變數,但 PACKAGE_PREFIX_DIR 可用於 PATH_VARS 無法輕鬆處理的情況,例如直接安裝到基本安裝位置而不是其子目錄的檔案。

注意

當產生的檔案的使用者使用 CMake 3.29 或更舊版本時,PACKAGE_PREFIX_DIR 的值可能會因呼叫 find_dependency()find_package() 而變更。如果專案依賴 PACKAGE_PREFIX_DIR,則專案有責任確保 PACKAGE_PREFIX_DIR 的值在任何此類呼叫或任何其他可能包含由 configure_package_config_file() 產生的其他檔案的呼叫中都保持不變。

在 3.1 版本中新增: 如果傳遞 INSTALL_PREFIX 引數,則會將其用作計算所有相對路徑的基本路徑。<path> 引數必須是絕對路徑。如果未傳遞此引數,則會改用 CMAKE_INSTALL_PREFIX 變數。當產生 FooConfig.cmake 檔案以從安裝樹狀結構中使用您的套件時,預設值是好的。當產生 FooConfig.cmake 檔案以從建置樹狀結構中使用您的套件時,應使用此選項。

預設情況下,configure_package_config_file() 還會在 FooConfig.cmake 檔案中產生兩個輔助巨集 set_and_check()check_required_components()

set_and_check() 應取代一般的 set() 命令,用於設定目錄和檔案位置。除了設定變數之外,它還會檢查引用的檔案或目錄是否實際存在,如果不存在則會發生嚴重錯誤。這可確保產生的 FooConfig.cmake 檔案不包含錯誤的參照。新增 NO_SET_AND_CHECK_MACRO 選項以防止在 FooConfig.cmake 檔案中產生 set_and_check() 巨集。

應在 FooConfig.cmake 檔案的結尾呼叫 check_required_components(<PackageName>)。此巨集會檢查是否已找到所有請求的非可選元件,如果不是這種情況,則會將 Foo_FOUND 變數設定為 FALSE,以便將套件視為未找到。它透過測試所有請求的必要元件的 Foo_<Component>_FOUND 變數來實現這一點。即使套件不提供任何元件,也應呼叫此巨集,以確保使用者不會錯誤地指定元件。新增 NO_CHECK_REQUIRED_COMPONENTS_MACRO 選項以防止在 FooConfig.cmake 檔案中產生 check_required_components() 巨集。

另請參閱 產生套件檔案的範例

產生套件版本檔案

write_basic_package_version_file

為專案建立版本檔案

write_basic_package_version_file(<filename>
  [VERSION <major.minor.patch>]
  COMPATIBILITY <AnyNewerVersion|SameMajorVersion|SameMinorVersion|ExactVersion>
  [ARCH_INDEPENDENT] )

寫入一個檔案,用作 <PackageName>ConfigVersion.cmake 檔案至 <filename>。請參閱 find_package() 的文件,以瞭解此類檔案的詳細資訊。

<filename> 是輸出檔案名稱,應位於建置樹中。<major.minor.patch> 是要安裝的專案的版本號碼。

如果沒有給定 VERSION,則會使用 PROJECT_VERSION 變數。如果尚未設定此變數,則會發生錯誤。

COMPATIBILITY 模式 AnyNewerVersion 表示,如果已安裝的套件版本較新或與請求的版本完全相同,則會被視為相容。此模式應適用於完全向下相容的套件,包括跨主要版本。如果改用 SameMajorVersion,則其行為與 AnyNewerVersion 不同,因為主要版本號碼必須與請求的版本相同,例如,如果請求的版本為 1.0,則版本 2.0 不會被視為相容。此模式應適用於保證在相同主要版本內向下相容的套件。如果使用 SameMinorVersion,則其行為與 SameMajorVersion 相同,但主要版本和次要版本都必須與請求的版本相同,例如,如果請求的版本為 0.1,則版本 0.2 不會相容。如果使用 ExactVersion,則僅當請求的版本與其自身的版本號碼完全匹配時(不考慮微調版本),套件才被視為相容。例如,套件的版本 1.2.3 僅在請求的版本為 1.2.3 時才被視為相容。此模式適用於不保證相容性的套件。如果您的專案有更精細的版本匹配規則,則需要編寫自己的自訂 <PackageName>ConfigVersion.cmake 檔案,而不是使用此巨集。

在 3.11 版本中新增: SameMinorVersion 相容性模式。

在 3.14 版本中新增: 如果給定 ARCH_INDEPENDENT,即使已安裝的套件是為與請求的架構不同的架構所建置,仍會被視為相容。否則,將會執行架構檢查,且僅當架構完全匹配時,套件才被視為相容。例如,如果套件是為 32 位元架構建置的,則僅當在 32 位元架構上使用時,該套件才被視為相容,除非給定 ARCH_INDEPENDENT,在這種情況下,該套件在任何架構上都被視為相容。

注意

ARCH_INDEPENDENT 適用於僅標頭的程式庫或沒有二進位檔案的類似套件。

在 3.19 版本中新增: COMPATIBILITYAnyNewerVersionSameMajorVersionSameMinorVersion 引數產生的版本檔案會處理版本範圍(如果指定了範圍)(請參閱 find_package() 命令以瞭解詳細資訊)。ExactVersion 模式與版本範圍不相容,如果指定了範圍,則會顯示作者警告。

在內部,此巨集會執行 configure_file() 來建立產生的版本檔案。根據 COMPATIBILITY,會使用對應的 BasicConfigVersion-<COMPATIBILITY>.cmake.in 檔案。請注意,這些檔案是 CMake 的內部檔案,您不應自行在其上呼叫 configure_file(),但它們可以用作建立更複雜的自訂 <PackageName>ConfigVersion.cmake 檔案的起點。

產生 Apple 平台選擇檔案

generate_apple_platform_selection_file

在 3.29 版本中新增。

建立 Apple 平台選擇檔案

generate_apple_platform_selection_file(<filename>
  INSTALL_DESTINATION <path>
  [INSTALL_PREFIX <path>]
  [MACOS_INCLUDE_FILE <file>]
  [IOS_INCLUDE_FILE <file>]
  [IOS_SIMULATOR_INCLUDE_FILE <file>]
  [IOS_CATALYST_INCLUDE_FILE <file>]
  [TVOS_INCLUDE_FILE <file>]
  [TVOS_SIMULATOR_INCLUDE_FILE <file>]
  [WATCHOS_INCLUDE_FILE <file>]
  [WATCHOS_SIMULATOR_INCLUDE_FILE <file>]
  [VISIONOS_INCLUDE_FILE <file>]
  [VISIONOS_SIMULATOR_INCLUDE_FILE <file>]
  [ERROR_VARIABLE <variable>]
  )

寫入一個包含 Apple 平台特定 .cmake 檔案的檔案,例如,用作 <PackageName>Config.cmake。這可以與 export(SETUP)XCFRAMEWORK_LOCATION 引數結合使用,以使用任何 Apple 平台建置的專案都可以使用的方式匯出套件。

INSTALL_DESTINATION <path>

呼叫者將透過例如 install(FILES) 安裝產生檔案的路徑。該路徑可以是相對於 INSTALL_PREFIX 的相對路徑,也可以是絕對路徑。

INSTALL_PREFIX <path>

呼叫者將安裝套件的路徑前綴。<path> 引數必須是絕對路徑。如果未傳遞此引數,則會改用 CMAKE_INSTALL_PREFIX 變數。

MACOS_INCLUDE_FILE <file>

如果平台為 macOS,則要包含的檔案。

IOS_INCLUDE_FILE <file>

如果平台為 iOS,則要包含的檔案。

IOS_SIMULATOR_INCLUDE_FILE <file>

如果平台為 iOS 模擬器,則要包含的檔案。

IOS_CATALYST_INCLUDE_FILE <file>

在 3.31 版本中新增。

如果平台為 iOS Catalyst,則要包含的檔案。

TVOS_INCLUDE_FILE <file>

如果平台為 tvOS,則要包含的檔案。

TVOS_SIMULATOR_INCLUDE_FILE <file>

如果平台為 tvOS 模擬器,則要包含的檔案。

WATCHOS_INCLUDE_FILE <file>

如果平台為 watchOS,則要包含的檔案。

WATCHOS_SIMULATOR_INCLUDE_FILE <file>

如果平台為 watchOS 模擬器,則要包含的檔案。

VISIONOS_INCLUDE_FILE <file>

如果平台為 visionOS,則要包含的檔案。

VISIONOS_SIMULATOR_INCLUDE_FILE <file>

如果平台為 visionOS 模擬器,則要包含的檔案。

ERROR_VARIABLE <variable>

如果使用專案是為不支援的平台所建置,則將 <variable> 設定為錯誤訊息。包含者可以使用此資訊來假裝找不到套件。如果未提供此選項,則預設行為是發出嚴重錯誤。

如果未指定任何可選的包含檔案,且使用專案是為其對應的平台所建置,則產生的檔案會認為該平台不受支援。行為由 ERROR_VARIABLE 選項決定。

產生 Apple 架構選擇檔案

generate_apple_architecture_selection_file

在 3.29 版本中新增。

建立 Apple 架構選擇檔案

generate_apple_architecture_selection_file(<filename>
  INSTALL_DESTINATION <path>
  [INSTALL_PREFIX <path>]
  [SINGLE_ARCHITECTURES <arch>...
   SINGLE_ARCHITECTURE_INCLUDE_FILES <file>...]
  [UNIVERSAL_ARCHITECTURES <arch>...
   UNIVERSAL_INCLUDE_FILE <file>]
  [ERROR_VARIABLE <variable>]
  )

寫入一個根據 CMAKE_OSX_ARCHITECTURES 包含 Apple 架構特定 .cmake 檔案的檔案,例如,用於從 Apple 特定的 <PackageName>Config.cmake 檔案中包含。

INSTALL_DESTINATION <path>

呼叫者將透過例如 install(FILES) 安裝產生檔案的路徑。該路徑可以是相對於 INSTALL_PREFIX 的相對路徑,也可以是絕對路徑。

INSTALL_PREFIX <path>

呼叫者將安裝套件的路徑前綴。<path> 引數必須是絕對路徑。如果未傳遞此引數,則會改用 CMAKE_INSTALL_PREFIX 變數。

SINGLE_ARCHITECTURES <arch>...

SINGLE_ARCHITECTURE_INCLUDE_FILES 項目提供的架構。

SINGLE_ARCHITECTURE_INCLUDE_FILES <file>...

架構特定檔案。當 CMAKE_OSX_ARCHITECTURES 包含與 SINGLE_ARCHITECTURES 的對應項目相符的單一架構時,將會載入其中一個檔案。

UNIVERSAL_ARCHITECTURES <arch>...

UNIVERSAL_INCLUDE_FILE 提供的架構。

清單可以包含 $(ARCHS_STANDARD) 以支援使用 Xcode 產生器進行使用,但架構也應始終個別列出。

UNIVERSAL_INCLUDE_FILE <file>

CMAKE_OSX_ARCHITECTURES 包含 UNIVERSAL_ARCHITECTURES 的(非嚴格)子集且不符合任何一個 SINGLE_ARCHITECTURES 時,要載入的檔案。

ERROR_VARIABLE <variable>

如果使用專案是為不支援的架構建置的,請將 <variable> 設定為錯誤訊息。包含器可以使用此資訊來假裝找不到套件。如果未提供此選項,預設行為是發出嚴重錯誤。

產生套件檔案範例

同時使用 configure_package_config_file()write_basic_package_version_file() 命令的範例

CMakeLists.txt
include(GNUInstallDirs)
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}/Foo
    CACHE PATH "Location of header files" )
set(SYSCONFIG_INSTALL_DIR ${CMAKE_INSTALL_SYSCONFDIR}/foo
    CACHE PATH "Location of configuration files" )
#...
include(CMakePackageConfigHelpers)
configure_package_config_file(FooConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo
  PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR)
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
  VERSION 1.2.3
  COMPATIBILITY SameMajorVersion )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Foo )
FooConfig.cmake.in
set(FOO_VERSION x.y.z)
...
@PACKAGE_INIT@
...
set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@")

check_required_components(Foo)