Просмотр исходного кода

FindPython: add support for multiple searches in same directory

In some situations, like cross-compilation, it can be required to search for
the host python interpreter as well as the cross-compilation development
artifacts.
By managing different prefixes for the artifacts, multiple and independent
searches can be achieved.
Marc Chevrier 1 год назад
Родитель
Сommit
9b0510fa57

+ 7 - 0
Help/release/dev/FindPython-ARTIFACTS-PREFIX.rst

@@ -0,0 +1,7 @@
+FindPython-ARTIFACTS-PREFIX
+---------------------------
+
+* The :module:`FindPython`, :module:`FindPython2`, and :module:`FindPython3`
+  modules gained the possibility to do multiple calls in the same directory by
+  using, respectively, the variables ``Python_ARTIFACTS_PREFIX``,
+  ``Python2_ARTIFACTS_PREFIX``, and ``Python3_ARTIFACTS_PREFIX``.

+ 74 - 39
Modules/FindPython.cmake

@@ -559,6 +559,31 @@ can be controlled with the following variable:
   * If set to ``FALSE`` or undefined: Enable multiple version/component
     requirements.
 
+``Python_ARTIFACTS_PREFIX``
+  .. versionadded:: 3.32
+
+  Define a custom prefix which will be used for the definition of all the
+  result variables, targets, and commands. By using this variable, this module
+  supports multiple calls in the same directory with different
+  version/component requirements.
+  For example, in case of cross-compilation, development components are needed
+  but the native python interpreter can also be required:
+
+  .. code-block:: cmake
+
+    find_package(Python COMPONENTS Development)
+
+    set(Python_ARTIFACTS_PREFIX "_HOST")
+    find_package(Python COMPONENTS Interpreter)
+
+    # Here Python_HOST_EXECUTABLE and Python_HOST::Interpreter artifacts are defined
+
+  .. note::
+
+    For consistency with standard behavior of modules, the various standard
+    ``_FOUND`` variables (i.e. without the custom prefix) are also defined by
+    each call to the :command:`find_package` command.
+
 Commands
 ^^^^^^^^
 
@@ -600,78 +625,86 @@ If the library type is not specified, ``MODULE`` is assumed.
 cmake_policy(PUSH)
 # numbers and boolean constants
 cmake_policy (SET CMP0012 NEW)
+# foreach loop variable scope
+cmake_policy (SET CMP0124 NEW)
 
 
-set (_PYTHON_PREFIX Python)
-unset (_Python_REQUIRED_VERSION_MAJOR)
-unset (_Python_REQUIRED_VERSIONS)
+set (_PYTHON_BASE Python)
+if(${_PYTHON_BASE}_ARTIFACTS_PREFIX)
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}${${_PYTHON_BASE}_ARTIFACTS_PREFIX}")
+else()
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}")
+endif()
+
+unset (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+unset (_${_PYTHON_PREFIX}_REQUIRED_VERSIONS)
 
 if (Python_FIND_VERSION_RANGE)
   # compute list of major versions
-  foreach (_Python_MAJOR IN ITEMS 3 2)
-    if (_Python_MAJOR VERSION_GREATER_EQUAL Python_FIND_VERSION_MIN_MAJOR
-        AND ((Python_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND _Python_MAJOR VERSION_LESS_EQUAL Python_FIND_VERSION_MAX)
-        OR (Python_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND _Python_MAJOR VERSION_LESS Python_FIND_VERSION_MAX)))
-      list (APPEND _Python_REQUIRED_VERSIONS ${_Python_MAJOR})
+  foreach (version_major IN ITEMS 3 2)
+    if (version_major VERSION_GREATER_EQUAL Python_FIND_VERSION_MIN_MAJOR
+        AND ((Python_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND version_major VERSION_LESS_EQUAL Python_FIND_VERSION_MAX)
+        OR (Python_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND version_major VERSION_LESS Python_FIND_VERSION_MAX)))
+      list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VERSIONS ${version_major})
     endif()
   endforeach()
-  list (LENGTH _Python_REQUIRED_VERSIONS _Python_VERSION_COUNT)
-  if (_Python_VERSION_COUNT EQUAL 0)
-    unset (_Python_REQUIRED_VERSIONS)
-  elseif (_Python_VERSION_COUNT EQUAL 1)
-    set (_Python_REQUIRED_VERSION_MAJOR ${_Python_REQUIRED_VERSIONS})
+  list (LENGTH _${_PYTHON_PREFIX}_REQUIRED_VERSIONS _${_PYTHON_PREFIX}_VERSION_COUNT)
+  if (_${_PYTHON_PREFIX}_VERSION_COUNT EQUAL 0)
+    unset (_${_PYTHON_PREFIX}_REQUIRED_VERSIONS)
+  elseif (_${_PYTHON_PREFIX}_VERSION_COUNT EQUAL 1)
+    set (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR ${_${_PYTHON_PREFIX}_REQUIRED_VERSIONS})
   endif()
 elseif (DEFINED Python_FIND_VERSION)
-  set (_Python_REQUIRED_VERSION_MAJOR ${Python_FIND_VERSION_MAJOR})
+  set (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR ${Python_FIND_VERSION_MAJOR})
 else()
-  set (_Python_REQUIRED_VERSIONS 3 2)
+  set (_${_PYTHON_PREFIX}_REQUIRED_VERSIONS 3 2)
 endif()
 
-if (_Python_REQUIRED_VERSION_MAJOR)
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
   include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
-elseif (_Python_REQUIRED_VERSIONS)
+elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSIONS)
   # iterate over versions in quiet and NOT required modes to avoid multiple
   # "Found" messages and prematurally failure.
-  set (_Python_QUIETLY ${Python_FIND_QUIETLY})
-  set (_Python_REQUIRED ${Python_FIND_REQUIRED})
+  set (_${_PYTHON_PREFIX}_QUIETLY ${Python_FIND_QUIETLY})
+  set (_${_PYTHON_PREFIX}_REQUIRED ${Python_FIND_REQUIRED})
   set (Python_FIND_QUIETLY TRUE)
   set (Python_FIND_REQUIRED FALSE)
 
-  set (_Python_REQUIRED_VERSION_LAST 2)
+  set (_${_PYTHON_PREFIX}_REQUIRED_VERSION_LAST 2)
 
-  unset (_Python_INPUT_VARS)
-  foreach (_Python_ITEM IN ITEMS Python_EXECUTABLE Python_COMPILER Python_LIBRARY
-                                 Python_INCLUDE_DIR Python_NumPy_INCLUDE_DIR)
-    if (NOT DEFINED ${_Python_ITEM})
-      list (APPEND _Python_INPUT_VARS ${_Python_ITEM})
+  unset (_${_PYTHON_PREFIX}_INPUT_VARS)
+  foreach (item IN ITEMS Python_EXECUTABLE Python_COMPILER Python_LIBRARY
+                         Python_INCLUDE_DIR Python_NumPy_INCLUDE_DIR)
+    if (NOT DEFINED ${item})
+      list (APPEND _${_PYTHON_PREFIX}_INPUT_VARS ${item})
     endif()
   endforeach()
 
-  foreach (_Python_REQUIRED_VERSION_MAJOR IN LISTS _Python_REQUIRED_VERSIONS)
-    set (Python_FIND_VERSION ${_Python_REQUIRED_VERSION_MAJOR})
+  foreach (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR IN LISTS _${_PYTHON_PREFIX}_REQUIRED_VERSIONS)
+    set (Python_FIND_VERSION ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR})
     include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
     if (Python_FOUND OR
-        _Python_REQUIRED_VERSION_MAJOR EQUAL _Python_REQUIRED_VERSION_LAST)
+        _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_LAST)
       break()
     endif()
     # clean-up INPUT variables not set by the user
-    foreach (_Python_ITEM IN LISTS _Python_INPUT_VARS)
-      unset (${_Python_ITEM})
+    foreach (item IN LISTS _${_PYTHON_PREFIX}_INPUT_VARS)
+      unset (${item})
     endforeach()
     # clean-up some CACHE variables to ensure look-up restart from scratch
-    foreach (_Python_ITEM IN LISTS _Python_CACHED_VARS)
-      unset (${_Python_ITEM} CACHE)
+    foreach (item IN LISTS _${_PYTHON_PREFIX}_CACHED_VARS)
+      unset (${item} CACHE)
     endforeach()
   endforeach()
 
   unset (Python_FIND_VERSION)
 
-  set (Python_FIND_QUIETLY ${_Python_QUIETLY})
-  set (Python_FIND_REQUIRED ${_Python_REQUIRED})
+  set (Python_FIND_QUIETLY ${_${_PYTHON_PREFIX}_QUIETLY})
+  set (Python_FIND_REQUIRED ${_${_PYTHON_PREFIX}_REQUIRED})
   if (Python_FIND_REQUIRED OR NOT Python_FIND_QUIETLY)
     # call again validation command to get "Found" or error message
     find_package_handle_standard_args (Python HANDLE_COMPONENTS HANDLE_VERSION_RANGE
-                                              REQUIRED_VARS ${_Python_REQUIRED_VARS}
+                                              REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}
                                               VERSION_VAR Python_VERSION)
   endif()
 else()
@@ -687,12 +720,14 @@ else()
                                             REASON_FAILURE_MESSAGE "Version range specified \"${Python_FIND_VERSION_RANGE}\" does not include supported versions")
 endif()
 
-if (COMMAND __Python_add_library)
-  macro (Python_add_library)
-    __Python_add_library (Python ${ARGV})
-  endmacro()
+if (COMMAND __${_PYTHON_PREFIX}_add_library AND NOT COMMAND ${_PYTHON_PREFIX}_add_library)
+  cmake_language(EVAL CODE
+    "macro (${_PYTHON_PREFIX}_add_library)
+      __${_PYTHON_PREFIX}_add_library (${_PYTHON_PREFIX} \${ARGV})
+    endmacro()")
 endif()
 
+unset (_PYTHON_BASE)
 unset (_PYTHON_PREFIX)
 
 cmake_policy(POP)

+ 109 - 103
Modules/FindPython/Support.cmake

@@ -45,10 +45,10 @@ include (${CMAKE_CURRENT_LIST_DIR}/../FindPackageHandleStandardArgs.cmake)
 # helper commands
 #
 macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG)
-  if (${_PYTHON_PREFIX}_FIND_REQUIRED)
+  if (${_PYTHON_BASE}_FIND_REQUIRED)
     message (FATAL_ERROR "${_PYTHON_MSG}")
   else()
-    if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY)
+    if (NOT ${_PYTHON_BASE}_FIND_QUIETLY)
       message(STATUS "${_PYTHON_MSG}")
     endif ()
   endif()
@@ -532,7 +532,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
     endif()
   endif()
 
-  if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND _${_PYTHON_PREFIX}_EXECUTABLE
+  if ("Interpreter" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS AND _${_PYTHON_PREFIX}_EXECUTABLE
       AND NOT CMAKE_CROSSCOMPILING)
     if (NAME STREQUAL "PREFIX")
       execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))"
@@ -1003,9 +1003,9 @@ function (_PYTHON_VALIDATE_INTERPRETER)
     endif()
   endif()
 
-  if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-        OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-        OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+        OR "Development.SABIModule" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+        OR "Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
       AND NOT CMAKE_CROSSCOMPILING)
     # In this case, interpreter must have same architecture as environment
     execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
@@ -1371,7 +1371,7 @@ endfunction()
 
 
 function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
-  if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  if ("Development.${module}" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
     if (module STREQUAL "SABIModule"
         AND "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_LESS "3.2")
       # Stable API was introduced in version 3.2
@@ -1401,23 +1401,23 @@ function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
 endfunction()
 
 
-if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
   # range must include internal major version
-  if (${_PYTHON_PREFIX}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR
-      OR ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
-          AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
-        OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
-          AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)))
-    _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_RANGE}\", but expected version range must include major version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+  if (${_PYTHON_BASE}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR
+      OR ((${_PYTHON_BASE}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
+          AND ${_PYTHON_BASE}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+        OR (${_PYTHON_BASE}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
+          AND ${_PYTHON_BASE}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)))
+    _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \"${${_PYTHON_BASE}_FIND_VERSION_RANGE}\", but expected version range must include major version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
 
     cmake_policy(POP)
     return()
   endif()
 else()
-  if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR
-      AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+  if (DEFINED ${_PYTHON_BASE}_FIND_VERSION_MAJOR
+      AND NOT ${_PYTHON_BASE}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
     # If major version is specified, it must be the same as internal major version
-    _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+    _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_BASE}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
 
     cmake_policy(POP)
     return()
@@ -1426,42 +1426,42 @@ endif()
 
 
 # handle components
-if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter)
-  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE)
+if (NOT ${_PYTHON_BASE}_FIND_COMPONENTS)
+  set (${_PYTHON_BASE}_FIND_COMPONENTS Interpreter)
+  set (${_PYTHON_BASE}_FIND_REQUIRED_Interpreter TRUE)
 endif()
-if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development.Module")
+if ("NumPy" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
+  list (APPEND ${_PYTHON_BASE}_FIND_COMPONENTS "Interpreter" "Development.Module")
 endif()
-if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Development.Module" "Development.Embed")
+if ("Development" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
+  list (APPEND ${_PYTHON_BASE}_FIND_COMPONENTS "Development.Module" "Development.Embed")
 endif()
-list (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.SABIModule Development.Embed NumPy)
-  set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE)
+list (REMOVE_DUPLICATES ${_PYTHON_BASE}_FIND_COMPONENTS)
+foreach (component IN ITEMS Interpreter Compiler Development Development.Module Development.SABIModule Development.Embed NumPy)
+  set (${_PYTHON_PREFIX}_${component}_FOUND FALSE)
 endforeach()
-if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)
-  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE)
-  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed TRUE)
+if (${_PYTHON_BASE}_FIND_REQUIRED_Development)
+  set (${_PYTHON_BASE}_FIND_REQUIRED_Development.Module TRUE)
+  set (${_PYTHON_BASE}_FIND_REQUIRED_Development.Embed TRUE)
 endif()
 
 unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
 unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
 unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
 unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
-if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Development.Module" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
   if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$")
     list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "LIBRARY")
   endif()
   list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "INCLUDE_DIR")
 endif()
-if ("Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Development.SABIModule" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
   if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$")
     list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS "SABI_LIBRARY")
   endif()
   list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS "INCLUDE_DIR")
 endif()
-if ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
   list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS "LIBRARY" "INCLUDE_DIR")
 endif()
 set (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS})
@@ -1472,29 +1472,29 @@ list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
 set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS})
 unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
 
-if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
   unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
-  foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
-    if ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
-          AND _${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MIN)
-        AND ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
-            AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MAX)
-          OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
-            AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION_MAX)))
-      list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
+  foreach (version IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
+    if ((${_PYTHON_BASE}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
+          AND version VERSION_GREATER_EQUAL ${_PYTHON_BASE}_FIND_VERSION_MIN)
+        AND ((${_PYTHON_BASE}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
+            AND version VERSION_LESS_EQUAL ${_PYTHON_BASE}_FIND_VERSION_MAX)
+          OR (${_PYTHON_BASE}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
+            AND version VERSION_LESS ${_PYTHON_BASE}_FIND_VERSION_MAX)))
+      list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${version})
     endif()
   endforeach()
 else()
-  if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
-    if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+  if (${_PYTHON_BASE}_FIND_VERSION_COUNT GREATER 1)
+    if (${_PYTHON_BASE}_FIND_VERSION_EXACT)
       set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT")
-      set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR})
+      set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_BASE}_FIND_VERSION_MAJOR}.${${_PYTHON_BASE}_FIND_VERSION_MINOR})
     else()
       unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
       # add all compatible versions
-      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
-        if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}")
-          list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
+      foreach (version IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
+        if (version VERSION_GREATER_EQUAL "${${_PYTHON_BASE}_FIND_VERSION_MAJOR}.${${_PYTHON_BASE}_FIND_VERSION_MINOR}")
+          list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${version})
         endif()
       endforeach()
     endif()
@@ -1553,9 +1553,9 @@ endif()
 unset (_${_PYTHON_PREFIX}_REGISTRY_VIEW)
 if (CMAKE_SIZEOF_VOID_P)
   math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
-  if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-      OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-      OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  if ("Development.Module" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+      OR "Development.SABIModule" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+      OR "Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
     # In this case, search only for 64bit or 32bit
     set (_${_PYTHON_PREFIX}_REGISTRY_VIEW REGISTRY_VIEW ${_${_PYTHON_PREFIX}_ARCH})
     if (WIN32 AND (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM"
@@ -1772,7 +1772,7 @@ if (CMAKE_HOST_WIN32)
 endif()
 
 function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
-  if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  if ("Development.${module}" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
     string (TOUPPER "${module}" id)
     set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:")
     if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
@@ -1787,12 +1787,12 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
     string (MD5 signature "${signature}")
     if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE)
       if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
-        if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-          _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
-        elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+        if (${_PYTHON_BASE}_FIND_VERSION_EXACT)
+          _python_validate_library (VERSION ${${_PYTHON_BASE}_FIND_VERSION} EXACT CHECK_EXISTS)
+        elseif (${_PYTHON_BASE}_FIND_VERSION_RANGE)
           _python_validate_library (IN_RANGE CHECK_EXISTS)
-        elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
-          _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+        elseif (DEFINED ${_PYTHON_BASE}_FIND_VERSION)
+          _python_validate_library (VERSION ${${_PYTHON_BASE}_FIND_VERSION} CHECK_EXISTS)
         else()
           _python_validate_library (CHECK_EXISTS)
         endif()
@@ -1801,12 +1801,12 @@ function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
           _python_validate_sabi_library (CHECK_EXISTS)
       endif()
       if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
-        if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-          _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
-        elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+        if (${_PYTHON_BASE}_FIND_VERSION_EXACT)
+          _python_validate_include_dir (VERSION ${${_PYTHON_BASE}_FIND_VERSION} EXACT CHECK_EXISTS)
+        elseif (${_PYTHON_BASE}_FIND_VERSION_RANGE)
           _python_validate_include_dir (IN_RANGE CHECK_EXISTS)
-        elseif (${_PYTHON_PREFIX}_FIND_VERSION)
-          _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+        elseif (${_PYTHON_BASE}_FIND_VERSION)
+          _python_validate_include_dir (VERSION ${${_PYTHON_BASE}_FIND_VERSION} CHECK_EXISTS)
         else()
           _python_validate_include_dir (CHECK_EXISTS)
         endif()
@@ -1882,11 +1882,11 @@ endif()
 
 
 # first step, search for the interpreter
-if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Interpreter" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
   list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE
                                               _${_PYTHON_PREFIX}_EXECUTABLE_DEBUG
                                               _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
-  if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter)
+  if (${_PYTHON_BASE}_FIND_REQUIRED_Interpreter)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE)
   endif()
 
@@ -1903,12 +1903,12 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
     string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
     if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
       # check version validity
-      if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-        _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
-      elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_EXACT)
+        _python_validate_interpreter (VERSION ${${_PYTHON_BASE}_FIND_VERSION} EXACT CHECK_EXISTS)
+      elseif (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         _python_validate_interpreter (IN_RANGE CHECK_EXISTS)
-      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
-        _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+      elseif (DEFINED ${_PYTHON_BASE}_FIND_VERSION)
+        _python_validate_interpreter (VERSION ${${_PYTHON_BASE}_FIND_VERSION} CHECK_EXISTS)
       else()
         _python_validate_interpreter (CHECK_EXISTS)
       endif()
@@ -1936,10 +1936,10 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
       _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
 
       set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
-      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
-      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
-        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+      elseif (DEFINED ${_PYTHON_BASE}_FIND_VERSION)
+        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_BASE}_FIND_VERSION})
       endif()
 
       while (TRUE)
@@ -2053,7 +2053,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
     else()
       # look-up for various versions and locations
       set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
-      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
       endif()
 
@@ -2383,9 +2383,9 @@ endif()
 
 
 # second step, search for compiler (IronPython)
-if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Compiler" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
   list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER)
-  if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler)
+  if (${_PYTHON_BASE}_FIND_REQUIRED_Compiler)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER)
   endif()
 
@@ -2400,12 +2400,12 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
     string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}")
     if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)
       # check version validity
-      if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-        _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS)
-      elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_EXACT)
+        _python_validate_compiler (VERSION ${${_PYTHON_BASE}_FIND_VERSION} EXACT CHECK_EXISTS)
+      elseif (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         _python_validate_compiler (IN_RANGE CHECK_EXISTS)
-      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
-        _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+      elseif (DEFINED ${_PYTHON_BASE}_FIND_VERSION)
+        _python_validate_compiler (VERSION ${${_PYTHON_BASE}_FIND_VERSION} CHECK_EXISTS)
       else()
         _python_validate_compiler (CHECK_EXISTS)
       endif()
@@ -2443,10 +2443,10 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
                               VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
 
       set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
-      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE)
-      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
-        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_PREFIX}_FIND_VERSION})
+      elseif (DEFINED ${_PYTHON_BASE}_FIND_VERSION)
+        list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${${_PYTHON_BASE}_FIND_VERSION})
       endif()
 
       while (TRUE)
@@ -2541,7 +2541,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
     else()
       # try using root dir and registry
       set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
-      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+      if (${_PYTHON_BASE}_FIND_VERSION_RANGE)
         list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
       endif()
 
@@ -2553,7 +2553,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
 
         _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
                                    IMPLEMENTATIONS IronPython
-                                   VERSION ${_${_PYTHON_PREFIX}_FIND_VERSION}
+                                   VERSION ${_${_PYTHON_PREFIX}_VERSION}
                                    COMPILER)
 
         _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS
@@ -2737,7 +2737,7 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
 endif()
 
 # third step, search for the development artifacts
-if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)
+if (${_PYTHON_BASE}_FIND_REQUIRED_Development.Module)
   if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
   endif()
@@ -2745,7 +2745,7 @@ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
   endif()
 endif()
-if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.SABIModule)
+if (${_PYTHON_BASE}_FIND_REQUIRED_Development.SABIModule)
   if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_SABI_LIBRARIES)
   endif()
@@ -2753,7 +2753,7 @@ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.SABIModule)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
   endif()
 endif()
-if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed)
+if (${_PYTHON_BASE}_FIND_REQUIRED_Development.Embed)
   if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
   endif()
@@ -2763,9 +2763,9 @@ if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed)
 endif()
 list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS)
 ## Development environment is not compatible with IronPython interpreter
-if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-      OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-      OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if (("Development.Module" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+      OR "Development.SABIModule" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
+      OR "Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS)
     AND ((${_PYTHON_PREFIX}_Interpreter_FOUND
         AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
       OR NOT ${_PYTHON_PREFIX}_Interpreter_FOUND))
@@ -3610,11 +3610,11 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
       set (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED FALSE)
       foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Module SABIModule Embed)
         string (TOUPPER "${_${_PYTHON_PREFIX}_COMPONENT}" _${_PYTHON_PREFIX}_ID)
-        if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+        if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
             AND "LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
           set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED TRUE)
         endif()
-        if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+        if ("Development.${_${_PYTHON_PREFIX}_COMPONENT}" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
             AND "SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
           set (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED TRUE)
         endif()
@@ -3876,7 +3876,7 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
     endif()
   endif()
 
-  if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+  if ("Development" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
       AND ${_PYTHON_PREFIX}_Development.Module_FOUND
       AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
     set (${_PYTHON_PREFIX}_Development_FOUND TRUE)
@@ -3963,10 +3963,10 @@ if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
                             _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE)
 endif()
 
-if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy)
+if (${_PYTHON_BASE}_FIND_REQUIRED_NumPy)
   list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS)
 endif()
-if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND)
+if ("NumPy" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND)
   list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
 
   if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
@@ -4079,16 +4079,22 @@ foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development
   endif()
 endforeach()
 
-find_package_handle_standard_args (${_PYTHON_PREFIX}
+foreach (component IN ITEMS Interpreter Compiler Development Development.Module Development.SABIModule Development.Embed NumPy)
+  set(${_PYTHON_BASE}_${component}_FOUND ${${_PYTHON_PREFIX}_${component}_FOUND})
+endforeach()
+
+find_package_handle_standard_args (${_PYTHON_BASE}
                                    REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}
                                    VERSION_VAR ${_PYTHON_PREFIX}_VERSION
                                    HANDLE_VERSION_RANGE
                                    HANDLE_COMPONENTS
                                    REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}")
 
+set(${_PYTHON_PREFIX}_FOUND ${${_PYTHON_BASE}_FOUND})
+
 # Create imported targets and helper functions
 if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
-  if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+  if ("Interpreter" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
       AND ${_PYTHON_PREFIX}_Interpreter_FOUND)
     if(NOT TARGET ${_PYTHON_PREFIX}::Interpreter)
       add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED)
@@ -4112,7 +4118,7 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
     endif()
   endif()
 
-  if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+  if ("Compiler" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
       AND ${_PYTHON_PREFIX}_Compiler_FOUND
       AND NOT TARGET ${_PYTHON_PREFIX}::Compiler)
     add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED)
@@ -4120,11 +4126,11 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
                   PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}")
   endif()
 
-  if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+  if (("Development.Module" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
         AND ${_PYTHON_PREFIX}_Development.Module_FOUND)
-      OR ("Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+      OR ("Development.SABIModule" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
         AND ${_PYTHON_PREFIX}_Development.SABIModule_FOUND)
-      OR ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+      OR ("Development.Embed" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS
         AND ${_PYTHON_PREFIX}_Development.Embed_FOUND))
 
     macro (__PYTHON_IMPORT_LIBRARY __name)
@@ -4362,7 +4368,7 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
     endfunction()
   endif()
 
-  if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND
+  if ("NumPy" IN_LIST ${_PYTHON_BASE}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND
       AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module)
     add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED)
     set_property (TARGET ${_PYTHON_PREFIX}::NumPy

+ 38 - 6
Modules/FindPython2.cmake

@@ -440,6 +440,31 @@ can be controlled with the following variable:
   * If set to ``FALSE`` or undefined: Enable multiple version/component
     requirements.
 
+``Python2_ARTIFACTS_PREFIX``
+  .. versionadded:: 3.32
+
+  Define a custom prefix which will be used for the definition of all the
+  result variables, targets, and commands. By using this variable, this module
+  supports multiple calls in the same directory with different
+  version/component requirements.
+  For example, in case of cross-compilation, development components are needed
+  but the native python interpreter can also be required:
+
+  .. code-block:: cmake
+
+    find_package(Python2 COMPONENTS Development)
+
+    set(Python2_ARTIFACTS_PREFIX "_HOST")
+    find_package(Python2 COMPONENTS Interpreter)
+
+    # Here Python2_HOST_EXECUTABLE and Python2_HOST::Interpreter artifacts are defined
+
+  .. note::
+
+    For consistency with standard behavior of modules, the various standard
+    ``_FOUND`` variables (i.e. without the custom prefix) are also defined by
+    each call to the :command:`find_package` command.
+
 Commands
 ^^^^^^^^
 
@@ -460,16 +485,23 @@ If library type is not specified, ``MODULE`` is assumed.
 #]=======================================================================]
 
 
-set (_PYTHON_PREFIX Python2)
+set (_PYTHON_BASE Python2)
+if(${_PYTHON_BASE}_ARTIFACTS_PREFIX)
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}${${_PYTHON_BASE}_ARTIFACTS_PREFIX}")
+else()
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}")
+endif()
 
-set (_Python2_REQUIRED_VERSION_MAJOR 2)
+set (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR 2)
 
 include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
 
-if (COMMAND __Python2_add_library)
-  macro (Python2_add_library)
-    __Python2_add_library (Python2 ${ARGV})
-  endmacro()
+if (COMMAND __${_PYTHON_PREFIX}_add_library AND NOT COMMAND ${_PYTHON_PREFIX}_add_library)
+  cmake_language(EVAL CODE
+    "macro (${_PYTHON_PREFIX}_add_library)
+       __${_PYTHON_PREFIX}_add_library (${_PYTHON_PREFIX} \${ARGV})
+     endmacro()")
 endif()
 
+unset (_PYTHON_BASE)
 unset (_PYTHON_PREFIX)

+ 38 - 6
Modules/FindPython3.cmake

@@ -557,6 +557,31 @@ can be controlled with the following variable:
   * If set to ``FALSE`` or undefined: Enable multiple version/component
     requirements.
 
+``Python3_ARTIFACTS_PREFIX``
+  .. versionadded:: 3.32
+
+  Define a custom prefix which will be used for the definition of all the
+  result variables, targets, and commands. By using this variable, this module
+  supports multiple calls in the same directory with different
+  version/component requirements.
+  For example, in case of cross-compilation, development components are needed
+  but the native python interpreter can also be required:
+
+  .. code-block:: cmake
+
+    find_package(Python3 COMPONENTS Development)
+
+    set(Python3_ARTIFACTS_PREFIX "_HOST")
+    find_package(Python3 COMPONENTS Interpreter)
+
+    # Here Python3_HOST_EXECUTABLE and Python3_HOST::Interpreter artifacts are defined
+
+  .. note::
+
+    For consistency with standard behavior of modules, the various standard
+    ``_FOUND`` variables (i.e. without the custom prefix) are also defined by
+    each call to the :command:`find_package` command.
+
 Commands
 ^^^^^^^^
 
@@ -595,16 +620,23 @@ If the library type is not specified, ``MODULE`` is assumed.
 #]=======================================================================]
 
 
-set (_PYTHON_PREFIX Python3)
+set (_PYTHON_BASE Python3)
+if(${_PYTHON_BASE}_ARTIFACTS_PREFIX)
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}${${_PYTHON_BASE}_ARTIFACTS_PREFIX}")
+else()
+  set(_PYTHON_PREFIX "${_PYTHON_BASE}")
+endif()
 
-set (_Python3_REQUIRED_VERSION_MAJOR 3)
+set (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR 3)
 
 include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake)
 
-if (COMMAND __Python3_add_library)
-  macro (Python3_add_library)
-    __Python3_add_library (Python3 ${ARGV})
-  endmacro()
+if (COMMAND __${_PYTHON_PREFIX}_add_library AND NOT COMMAND ${_PYTHON_PREFIX}_add_library)
+  cmake_language(EVAL CODE
+    "macro (${_PYTHON_PREFIX}_add_library)
+      __${_PYTHON_PREFIX}_add_library (${_PYTHON_PREFIX} \${ARGV})
+    endmacro()")
 endif()
 
+unset (_PYTHON_BASE)
 unset (_PYTHON_PREFIX)

+ 24 - 0
Tests/FindPython/ArtifactsPrefix/CMakeLists.txt

@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.31)
+
+project(TestArtifactsPrefix C)
+
+set(Python_ARTIFACTS_PREFIX "_V2")
+find_package (Python 2 EXACT REQUIRED)
+
+if(NOT Python_V2_FOUND OR NOT Python_FOUND)
+  message(FATAL_ERROR "Python v2 interpreter not found.")
+endif()
+if(NOT Python_V2_VERSION_MAJOR VERSION_EQUAL 2)
+  message(FATAL_ERROR "Python v2 interpreter: wrong major version.")
+endif()
+
+
+set(Python_ARTIFACTS_PREFIX "_V3")
+find_package (Python 3 EXACT REQUIRED)
+
+if(NOT Python_V3_FOUND OR NOT Python_FOUND)
+  message(FATAL_ERROR "Python v3 interpreter not found.")
+endif()
+if(NOT Python_V3_VERSION_MAJOR VERSION_EQUAL 3)
+  message(FATAL_ERROR "Python v3 interpreter: wrong major version.")
+endif()

+ 15 - 0
Tests/FindPython/CMakeLists.txt

@@ -523,6 +523,21 @@ if(CMake_TEST_FindPython2 OR CMake_TEST_FindPython3)
                APPEND PROPERTY LABELS Python2 Python3)
 endif()
 
+if(CMake_TEST_FindPython2 AND CMake_TEST_FindPython3)
+  add_test(NAME FindPython.ArtifactsPrefix COMMAND
+    ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/FindPython/ArtifactsPrefix"
+    "${CMake_BINARY_DIR}/Tests/FindPython/ArtifactsPrefix"
+    ${build_generator_args}
+    --build-project TestArtifactsPrefix
+    --build-options ${build_options}
+    --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+    )
+
+  set_property(TEST FindPython.ArtifactsPrefix
+               APPEND PROPERTY LABELS Python2 Python3)
+endif()
 
 if(CMake_TEST_FindPython2_SABIModule)
   add_test(NAME FindPython.Python2.Development.SABIModule COMMAND

+ 40 - 0
Tests/FindPython/Python/CMakeLists.txt

@@ -38,3 +38,43 @@ else()
            COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python
            -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
 endif()
+
+
+#
+# New search with user's prefix
+#
+foreach(item IN ITEMS FOUND Development_FOUND Development.Module_FOUND Development.Embed_FOUND)
+  unset(Python_${item})
+endforeach()
+
+set(Python_ARTIFACTS_PREFIX "_TEST")
+find_package(Python ${Python_REQUESTED_VERSION} REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python_TEST_FOUND OR NOT Python_FOUND)
+  message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION} (TEST prefix)")
+endif()
+if (NOT Python_TEST_Development.Module_FOUND OR NOT Python_Development.Module_FOUND)
+  message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}, COMPONENT 'Development.Module' (TEST prefix)")
+endif()
+if (NOT Python_TEST_Development.Embed_FOUND OR NOT Python_Development.Embed_FOUND)
+  message (FATAL_ERROR "Failed to find Python ${Python_REQUESTED_VERSION}, COMPOENENT 'Development.Embed' (TEST prefix)")
+endif()
+
+if(NOT TARGET Python_TEST::Interpreter)
+  message(SEND_ERROR "Python_TEST::Interpreter not found")
+endif()
+
+if(NOT TARGET Python_TEST::Python)
+  message(SEND_ERROR "Python_TEST::Python not found")
+endif()
+if(NOT TARGET Python_TEST::Module)
+  message(SEND_ERROR "Python_TEST::Module not found")
+endif()
+
+if (Python_REQUESTED_VERSION)
+  Python_TEST_add_library (TEST_spam${Python_REQUESTED_VERSION} MODULE ../TEST_spam.c)
+  target_compile_definitions (TEST_spam${Python_REQUESTED_VERSION} PRIVATE PYTHON${Python_REQUESTED_VERSION})
+
+  add_test (NAME python_TEST_spam${Python_REQUESTED_VERSION}
+            COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:TEST_spam${Python_REQUESTED_VERSION}>"
+            "${Python_INTERPRETER}" -c "import TEST_spam${Python_REQUESTED_VERSION}; TEST_spam${Python_REQUESTED_VERSION}.system(\"cd\")")
+endif()

+ 41 - 0
Tests/FindPython/Python2/CMakeLists.txt

@@ -45,3 +45,44 @@ add_test(NAME findpython2_script
          COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python2
          -DPython2_FIND_STRATEGY=${Python2_FIND_STRATEGY}
          -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+
+
+#
+# New search with user's prefix
+#
+foreach(item IN ITEMS FOUND Development_FOUND Development.Module_FOUND Development.Embed_FOUND)
+  unset(Python2_${item})
+endforeach()
+
+set(Python2_ARTIFACTS_PREFIX "_TEST")
+find_package(Python2 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python2_TEST_FOUND OR NOT Python2_FOUND)
+  message (FATAL_ERROR "Failed to find Python 2 (TEST prefix)")
+endif()
+if (NOT Python2_TEST_Development_FOUND OR NOT Python2_Development_FOUND)
+  message (FATAL_ERROR "Failed to find Python 2 'Development' component (TEST prefix)")
+endif()
+if (NOT Python2_TEST_Development.Module_FOUND OR NOT Python2_Development.Module_FOUND)
+  message (FATAL_ERROR "Failed to find Python 2 'Development.Module' component (TEST prefix)")
+endif()
+if (NOT Python2_TEST_Development.Embed_FOUND OR NOT Python2_Development.Embed_FOUND)
+  message (FATAL_ERROR "Failed to find Python 2 'Development.Embed' component (TEST prefix)")
+endif()
+
+if(NOT TARGET Python2_TEST::Interpreter)
+  message(SEND_ERROR "Python2_TEST::Interpreter not found")
+endif()
+
+if(NOT TARGET Python2_TEST::Python)
+  message(SEND_ERROR "Python2_TEST::Python not found")
+endif()
+if(NOT TARGET Python2_TEST::Module)
+  message(SEND_ERROR "Python2_TEST::Module not found")
+endif()
+
+Python2_TEST_add_library (TEST_spam2 MODULE ../TEST_spam.c)
+target_compile_definitions (TEST_spam2 PRIVATE PYTHON2)
+
+add_test (NAME python2_TEST_spam2
+          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:TEST_spam2>"
+          "${Python2_INTERPRETER}" -c "import TEST_spam2; TEST_spam2.system(\"cd\")")

+ 41 - 0
Tests/FindPython/Python3/CMakeLists.txt

@@ -102,3 +102,44 @@ add_test(NAME python3_find_invalid_abi
          -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
          "-DPython3_FIND_ABI=${Python3_INVALID_ABI}"
          -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+
+
+#
+# New search with user's prefix
+#
+foreach(item IN ITEMS FOUND Development_FOUND Development.Module_FOUND Development.Embed_FOUND)
+  unset(Python3_${item})
+endforeach()
+
+set(Python3_ARTIFACTS_PREFIX "_TEST")
+find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
+if (NOT Python3_TEST_FOUND OR NOT Python3_FOUND)
+  message (FATAL_ERROR "Failed to find Python 3 (TEST prefix)")
+endif()
+if (NOT Python3_TEST_Development_FOUND OR NOT Python3_Development_FOUND)
+  message (FATAL_ERROR "Failed to find Python 3 'Development' component (TEST prefix)")
+endif()
+if (NOT Python3_TEST_Development.Module_FOUND OR NOT Python3_Development.Module_FOUND)
+  message (FATAL_ERROR "Failed to find Python 3 'Development.Module' component (TEST prefix)")
+endif()
+if (NOT Python3_TEST_Development.Embed_FOUND OR NOT Python3_Development.Embed_FOUND)
+  message (FATAL_ERROR "Failed to find Python 3 'Development.Embed' component (TEST prefix)")
+endif()
+
+if(NOT TARGET Python3_TEST::Interpreter)
+  message(SEND_ERROR "Python3_TEST::Interpreter not found")
+endif()
+
+if(NOT TARGET Python3_TEST::Python)
+  message(SEND_ERROR "Python3_TEST::Python not found")
+endif()
+if(NOT TARGET Python3_TEST::Module)
+  message(SEND_ERROR "Python3_TEST::Module not found")
+endif()
+
+Python3_TEST_add_library (TEST_spam3 MODULE ../TEST_spam.c)
+target_compile_definitions (TEST_spam3 PRIVATE PYTHON3)
+
+add_test (NAME python3_TEST_spam3
+          COMMAND "${CMAKE_COMMAND}" -E env "PYTHONPATH=$<TARGET_FILE_DIR:TEST_spam3>"
+          "${Python3_TEST_INTERPRETER}" -c "import TEST_spam3; TEST_spam3.system(\"cd\")")

+ 41 - 0
Tests/FindPython/TEST_spam.c

@@ -0,0 +1,41 @@
+#define Py_LIMITED_API 3
+#include <Python.h>
+
+static PyObject* spam_system(PyObject* self, PyObject* args)
+{
+  const char* command;
+  int sts;
+
+  if (!PyArg_ParseTuple(args, "s", &command))
+    return NULL;
+  sts = system(command);
+  /* return PyLong_FromLong(sts); */
+  return Py_BuildValue("i", sts);
+}
+
+static PyMethodDef SpamMethods[] = {
+  { "system", spam_system, METH_VARARGS, "Execute a shell command." },
+  { NULL, NULL, 0, NULL } /* Sentinel */
+};
+
+#if defined(PYTHON2)
+PyMODINIT_FUNC initTEST_spam2(void)
+{
+  (void)Py_InitModule("TEST_spam2", SpamMethods);
+}
+#endif
+
+#if defined(PYTHON3)
+static struct PyModuleDef spammodule = {
+  PyModuleDef_HEAD_INIT, "TEST_spam3", /* name of module */
+  NULL,                                /* module documentation, may be NULL */
+  -1, /* size of per-interpreter state of the module,
+         or -1 if the module keeps state in global variables. */
+  SpamMethods
+};
+
+PyMODINIT_FUNC PyInit_TEST_spam3(void)
+{
+  return PyModule_Create(&spammodule);
+}
+#endif