CMakePackageConfigHelpers: Add generate_apple_architecture_selection_file()

Add a helper to select architecture-specific implementations of a
package on an Apple-specific platform.

Fixes: #25516
This commit is contained in:
Brad King
2023-12-19 08:41:26 -05:00
parent b9f81ee9f9
commit 4ac5a2f866
13 changed files with 188 additions and 2 deletions

View File

@@ -0,0 +1,7 @@
package-dispatch-apple
----------------------
* The :module:`CMakePackageConfigHelpers` module gained a new
:command:`generate_apple_architecture_selection_file` function, which can be
used to generate a file that includes an architecture-specific implementation
of a package for an Apple platform.

View File

@@ -260,6 +260,59 @@ Generating an Apple Platform Selection File
project is built for their corresponding platform, an error will be thrown project is built for their corresponding platform, an error will be thrown
when including the generated file. when including the generated file.
.. command:: generate_apple_architecture_selection_file
.. versionadded:: 3.29
Create an Apple architecture selection file:
.. code-block:: cmake
generate_apple_architecture_selection_file(<filename>
INSTALL_DESTINATION <path>
[INSTALL_PREFIX <path>]
[SINGLE_ARCHITECTURES <archs>
SINGLE_ARCHITECTURE_CONFIG_FILES <files>]
[UNIVERSAL_ARCHITECTURES <archs>
UNIVERSAL_CONFIG_FILE <file>]
)
Writes a file for use as ``<PackageName>Config.cmake`` on Apple platforms
which can include an architecture-specific ``<PackageName>Config.cmake``
from a different directory based on :variable:`CMAKE_OSX_ARCHITECTURES`.
``INSTALL_DESTINATION <path>``
Path to which the file will be installed by the caller, e.g., via
:command:`install(FILES)`. The path may be either relative to the
``INSTALL_PREFIX`` or absolute.
``INSTALL_PREFIX <path>``
Path prefix to which the package will be installed by the caller.
The ``<path>`` argument must be an absolute path. If this argument
is not passed, the :variable:`CMAKE_INSTALL_PREFIX` variable will be
used instead.
``SINGLE_ARCHITECTURES <archs>``
A :ref:`semicolon-separated list <CMake Language Lists>` of
architectures provided by entries of
``SINGLE_ARCHITECTURE_CONFIG_FILES``.
``SINGLE_ARCHITECTURE_CONFIG_FILES <files>``
A :ref:`semicolon-separated list <CMake Language Lists>` of
architecture-specific files. One of them will be loaded
when :variable:`CMAKE_OSX_ARCHITECTURES` contains a single
architecture matching the corresponding entry of
``SINGLE_ARCHITECTURES``.
``UNIVERSAL_ARCHITECTURES <archs>``
A :ref:`semicolon-separated list <CMake Language Lists>` of
architectures provided by the ``UNIVERSAL_CONFIG_FILE``.
``UNIVERSAL_CONFIG_FILE <file>``
A file to load when :variable:`CMAKE_OSX_ARCHITECTURES` contains
a (non-strict) subset of the ``UNIVERSAL_ARCHITECTURES`` and
does not match any one of the ``SINGLE_ARCHITECTURES``.
Example Generating Package Files Example Generating Package Files
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -467,3 +520,77 @@ function(generate_apple_platform_selection_file _output_file)
NO_CHECK_REQUIRED_COMPONENTS_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO
) )
endfunction() endfunction()
function(generate_apple_architecture_selection_file _output_file)
set(_options)
set(_single
INSTALL_DESTINATION
INSTALL_PREFIX
SINGLE_ARCHITECTURES
SINGLE_ARCHITECTURE_CONFIG_FILES
UNIVERSAL_ARCHITECTURES
UNIVERSAL_CONFIG_FILE
)
set(_multi)
cmake_parse_arguments(PARSE_ARGV 0 _gasf "${_options}" "${_single}" "${_multi}")
if(NOT _gasf_INSTALL_DESTINATION)
message(FATAL_ERROR "No INSTALL_DESTINATION given to generate_apple_platform_selection_file()")
endif()
if(_gasf_INSTALL_PREFIX)
set(maybe_INSTALL_PREFIX INSTALL_PREFIX ${_gasf_INSTALL_PREFIX})
else()
set(maybe_INSTALL_PREFIX "")
endif()
list(LENGTH _gasf_SINGLE_ARCHITECTURES _gasf_SINGLE_ARCHITECTURES_len)
list(LENGTH _gasf_SINGLE_ARCHITECTURE_CONFIG_FILES _gasf_SINGLE_ARCHITECTURE_CONFIG_FILES_len)
if(NOT _gasf_SINGLE_ARCHITECTURES_len EQUAL _gasf_SINGLE_ARCHITECTURE_CONFIG_FILES_len)
message(FATAL_ERROR "SINGLE_ARCHITECTURES and SINGLE_ARCHITECTURE_CONFIG_FILES do not have the same number of entries.")
endif()
set(_branch_code "")
foreach(pair IN ZIP_LISTS _gasf_SINGLE_ARCHITECTURES _gasf_SINGLE_ARCHITECTURE_CONFIG_FILES)
set(arch "${pair_0}")
set(config_file "${pair_1}")
if(NOT IS_ABSOLUTE "${config_file}")
string(PREPEND config_file [[${PACKAGE_PREFIX_DIR}/]])
endif()
string(APPEND _branch_code
"\n"
"if(CMAKE_OSX_ARCHITECTURES STREQUAL \"${arch}\")\n"
" include(\"${config_file}\")\n"
" return()\n"
"endif()\n"
)
endforeach()
if(_gasf_UNIVERSAL_ARCHITECTURES AND _gasf_UNIVERSAL_CONFIG_FILE)
string(JOIN " " universal_archs "${_gasf_UNIVERSAL_ARCHITECTURES}")
set(config_file "${_gasf_UNIVERSAL_CONFIG_FILE}")
if(NOT IS_ABSOLUTE "${config_file}")
string(PREPEND config_file [[${PACKAGE_PREFIX_DIR}/]])
endif()
string(APPEND _branch_code
"\n"
"set(_cmake_apple_archs \"\${CMAKE_OSX_ARCHITECTURES}\")\n"
"list(REMOVE_ITEM _cmake_apple_archs ${universal_archs})\n"
"if(NOT _cmake_apple_archs)\n"
" include(\"${config_file}\")\n"
" return()\n"
"endif()\n"
)
elseif(_gasf_UNIVERSAL_ARCHITECTURES)
message(FATAL_ERROR "UNIVERSAL_CONFIG_FILE requires UNIVERSAL_ARCHITECTURES")
elseif(_gasf_UNIVERSAL_CONFIG_FILE)
message(FATAL_ERROR "UNIVERSAL_ARCHITECTURES requires UNIVERSAL_CONFIG_FILE")
endif()
configure_package_config_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Internal/AppleArchitectureSelection.cmake.in" "${_output_file}"
INSTALL_DESTINATION "${_gasf_INSTALL_DESTINATION}"
${maybe_INSTALL_PREFIX}
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
endfunction()

View File

@@ -0,0 +1,8 @@
@PACKAGE_INIT@
if(NOT CMAKE_OSX_ARCHITECTURES)
message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES must be explicitly set for this package")
endif()
@_branch_code@
message(FATAL_ERROR "Architecture not supported")

View File

@@ -7,12 +7,16 @@ endif()
function(apple_export platform system_name archs sysroot) function(apple_export platform system_name archs sysroot)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/apple-export-${platform}-build) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/apple-export-${platform}-build)
string(REPLACE ";" "\\;" archs "${archs}") string(REPLACE ";" "\\;" archs "${archs}")
if(select_archs)
string(REPLACE ";" "\\\\;" maybe_IOS_SIMULATOR_SELECT_ARCHS "-DIOS_SIMULATOR_SELECT_ARCHS=${select_archs}")
endif()
run_cmake_with_options(apple-export-${platform} run_cmake_with_options(apple-export-${platform}
"-DCMAKE_SYSTEM_NAME=${system_name}" "-DCMAKE_SYSTEM_NAME=${system_name}"
"-DCMAKE_OSX_ARCHITECTURES=${archs}" "-DCMAKE_OSX_ARCHITECTURES=${archs}"
"-DCMAKE_OSX_SYSROOT=${sysroot}" "-DCMAKE_OSX_SYSROOT=${sysroot}"
"-DCMAKE_INSTALL_PREFIX=${apple_install}" "-DCMAKE_INSTALL_PREFIX=${apple_install}"
${maybe_CMAKE_BUILD_TYPE} ${maybe_CMAKE_BUILD_TYPE}
${maybe_IOS_SIMULATOR_SELECT_ARCHS}
) )
set(RunCMake_TEST_NO_CLEAN 1) set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(apple-export-${platform}-build ${CMAKE_COMMAND} --build . --config Release) run_cmake_command(apple-export-${platform}-build ${CMAKE_COMMAND} --build . --config Release)
@@ -47,9 +51,11 @@ if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 12) if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 12)
set(macos_archs "x86_64;arm64") set(macos_archs "x86_64;arm64")
set(watch_sim_archs "x86_64") set(watch_sim_archs "x86_64")
set(select_archs "arm64;x86_64")
else() else()
set(macos_archs "x86_64") set(macos_archs "x86_64")
set(watch_sim_archs "i386") set(watch_sim_archs "i386")
set(select_archs "")
endif() endif()
if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 9) if(CMake_TEST_XCODE_VERSION VERSION_GREATER_EQUAL 9)
@@ -71,6 +77,12 @@ if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
endif() endif()
apple_export(watchos watchOS "${watch_archs}" watchos) apple_export(watchos watchOS "${watch_archs}" watchos)
apple_export(ios-simulator iOS "${macos_archs}" iphonesimulator) apple_export(ios-simulator iOS "${macos_archs}" iphonesimulator)
if(select_archs)
foreach(arch IN LISTS macos_archs)
apple_export(ios-simulator-${arch} iOS "${arch}" iphonesimulator)
endforeach()
endif()
apple_export(tvos-simulator tvOS "${macos_archs}" appletvsimulator) apple_export(tvos-simulator tvOS "${macos_archs}" appletvsimulator)
if(enable_visionos) if(enable_visionos)
apple_export(visionos-simulator visionOS "${macos_archs}" xrsimulator) apple_export(visionos-simulator visionOS "${macos_archs}" xrsimulator)
@@ -85,6 +97,11 @@ if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
endif() endif()
apple_import(watchos watchOS "${watch_archs}" watchos) apple_import(watchos watchOS "${watch_archs}" watchos)
apple_import(ios-simulator iOS "${macos_archs}" iphonesimulator) apple_import(ios-simulator iOS "${macos_archs}" iphonesimulator)
if(select_archs)
foreach(arch IN LISTS macos_archs)
apple_import(ios-simulator-${arch} iOS "${arch}" iphonesimulator)
endforeach()
endif()
apple_import(tvos-simulator tvOS "${macos_archs}" appletvsimulator) apple_import(tvos-simulator tvOS "${macos_archs}" appletvsimulator)
if(enable_visionos) if(enable_visionos)
apple_import(visionos-simulator visionOS "${macos_archs}" xrsimulator) apple_import(visionos-simulator visionOS "${macos_archs}" xrsimulator)

View File

@@ -6,13 +6,19 @@ install(TARGETS mylib EXPORT mylib-targets FILE_SET HEADERS ARCHIVE DESTINATION
install(EXPORT mylib-targets DESTINATION lib/${platform_name}/cmake/mylib) install(EXPORT mylib-targets DESTINATION lib/${platform_name}/cmake/mylib)
if(IOS_SIMULATOR_SELECT_ARCHS)
set(IOS_SIMULATOR_CONFIG_FILE lib/ios-simulator/cmake/mylib/mylib-select-arch.cmake)
else()
set(IOS_SIMULATOR_CONFIG_FILE lib/ios-simulator/cmake/mylib/mylib-targets.cmake)
endif()
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
generate_apple_platform_selection_file(mylib-config-install.cmake generate_apple_platform_selection_file(mylib-config-install.cmake
INSTALL_DESTINATION lib/cmake/mylib INSTALL_DESTINATION lib/cmake/mylib
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}
MACOS_CONFIG_FILE lib/macos/cmake/mylib/mylib-targets.cmake MACOS_CONFIG_FILE lib/macos/cmake/mylib/mylib-targets.cmake
IOS_CONFIG_FILE lib/ios/cmake/mylib/mylib-targets.cmake IOS_CONFIG_FILE lib/ios/cmake/mylib/mylib-targets.cmake
IOS_SIMULATOR_CONFIG_FILE lib/ios-simulator/cmake/mylib/mylib-targets.cmake IOS_SIMULATOR_CONFIG_FILE ${IOS_SIMULATOR_CONFIG_FILE}
TVOS_CONFIG_FILE lib/tvos/cmake/mylib/mylib-targets.cmake TVOS_CONFIG_FILE lib/tvos/cmake/mylib/mylib-targets.cmake
TVOS_SIMULATOR_CONFIG_FILE lib/tvos-simulator/cmake/mylib/mylib-targets.cmake TVOS_SIMULATOR_CONFIG_FILE lib/tvos-simulator/cmake/mylib/mylib-targets.cmake
VISIONOS_CONFIG_FILE lib/watchos/cmake/mylib/mylib-targets.cmake VISIONOS_CONFIG_FILE lib/watchos/cmake/mylib/mylib-targets.cmake

View File

@@ -0,0 +1,2 @@
set(platform_name ios-simulator-arm64)
include(apple-export-ios-simulator-common.cmake)

View File

@@ -0,0 +1,13 @@
include(apple-export-common.cmake)
if(IOS_SIMULATOR_SELECT_ARCHS)
generate_apple_architecture_selection_file(mylib-select-arch-install.cmake
INSTALL_DESTINATION lib/ios-simulator/cmake/mylib
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}
SINGLE_ARCHITECTURES "${IOS_SIMULATOR_SELECT_ARCHS}"
SINGLE_ARCHITECTURE_CONFIG_FILES "lib/ios-simulator-arm64/cmake/mylib/mylib-targets.cmake;lib/ios-simulator-x86_64/cmake/mylib/mylib-targets.cmake"
UNIVERSAL_ARCHITECTURES "${IOS_SIMULATOR_SELECT_ARCHS}"
UNIVERSAL_CONFIG_FILE "lib/ios-simulator/cmake/mylib/mylib-targets.cmake"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mylib-select-arch-install.cmake DESTINATION lib/ios-simulator/cmake/mylib RENAME mylib-select-arch.cmake)
endif()

View File

@@ -0,0 +1,2 @@
set(platform_name ios-simulator-x86_64)
include(apple-export-ios-simulator-common.cmake)

View File

@@ -1,2 +1,2 @@
set(platform_name ios-simulator) set(platform_name ios-simulator)
include(apple-export-common.cmake) include(apple-export-ios-simulator-common.cmake)

View File

@@ -0,0 +1 @@
loaded: '[^']*/Tests/RunCMake/CMakePackage/apple-install/lib/ios-simulator-arm64/cmake/mylib/mylib-targets.cmake'

View File

@@ -0,0 +1 @@
include(apple-import-common.cmake)

View File

@@ -0,0 +1 @@
loaded: '[^']*/Tests/RunCMake/CMakePackage/apple-install/lib/ios-simulator-x86_64/cmake/mylib/mylib-targets.cmake'

View File

@@ -0,0 +1 @@
include(apple-import-common.cmake)