]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cmake: update FindPython3 module
authorKefu Chai <tchaikov@gmail.com>
Mon, 14 Aug 2023 15:27:42 +0000 (23:27 +0800)
committerKefu Chai <tchaikov@gmail.com>
Thu, 17 Aug 2023 02:16:45 +0000 (10:16 +0800)
* use the one shiped by the latest CMake (ab379e5054aa792df9572078dcf95bddd75f7661)
* use the new policy to use the new find strategy.
* accomodate the vanilla FindPython3 module to Ceph by:
  - dropping the `cmake_policy()` calls which set the policy not supported
    by 3.16.
  - `include (FindPackageHandleStandardArgs)` without specifying the
    relative path.
  - dropping the `HANDLE_VERSION_RANGE` from `FindPackageHandleStandardArgs()` call.
    this option was introduced by CMake v3.19, see
    https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html
    but Ubuntu focal comes with CMake 3.16, which is our minimal required CMake version.

the new FindPython3 module from CMake:

* enables us to find the recent Python intepreter and development files up to
  CPython 3.13.
* finds intepreter with the new `Python_FIND_STRATEGY`. the old and default
  strategy always finds the most recent version with all specified name
  and in all locations. so, if /usr/bin/python exists, it would accept, even
  if it is  a symlink to python3.9 and what we want is python3.6. while
  the new policy stops at the one which satisfies the constraints.
  simpler this way and less error prone.

Fixes: https://tracker.ceph.com/issues/62428
Signed-off-by: Kefu Chai <tchaikov@gmail.com>
CMakeLists.txt
COPYING
cmake/modules/FindPython/Support.cmake
cmake/modules/FindPython3.cmake

index 1778a7202649afa6b313a44302b9d0a00a626931..78881cb0188d20ecfb30ac5552ba93919c65d583 100644 (file)
@@ -14,6 +14,7 @@ cmake_policy(SET CMP0065 NEW)
 cmake_policy(SET CMP0074 NEW)
 cmake_policy(SET CMP0075 NEW)
 cmake_policy(SET CMP0093 NEW)
+cmake_policy(SET CMP0094 NEW)
 foreach(policy CMP0127 CMP0135)
   if(POLICY ${policy})
     cmake_policy(SET ${policy} NEW)
diff --git a/COPYING b/COPYING
index 373b9976b3e575418c39ec6a8047bcd61ade8ba4..bd0b22f6bce49da2655b90b8f6c0d6a0c2c1ce40 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -9,7 +9,7 @@ License: LGPL-2.1 or LGPL-3 (see COPYING-LGPL2.1 and COPYING-LGPL3)
 
 Files: cmake/modules/FindPython*
 Copyright:
-    Copyright 2000-2020 Kitware, Inc. and Contributors
+    Copyright 2000-2023 Kitware, Inc. and Contributors
 License: BSD 3-clause
 
 Files: cmake/modules/FindLTTngUST.cmake
index fb362bfe21cf3def3f463aef510dd9324b9a17fd..5e1d6f62ecc64b1680b666a027120c5984d00e59 100644 (file)
@@ -5,31 +5,35 @@
 # This file is a "template" file used by various FindPython modules.
 #
 
-cmake_policy (VERSION 3.5)
-
 #
 # Initial configuration
 #
+
+cmake_policy(PUSH)
+# list supports empty elements
+cmake_policy (SET CMP0007 NEW)
+# numbers and boolean constants
+cmake_policy (SET CMP0012 NEW)
+# IN_LIST operator
+cmake_policy (SET CMP0057 NEW)
+
 if (NOT DEFINED _PYTHON_PREFIX)
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
 endif()
 if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
 endif()
-if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 3)
-  set(_${_PYTHON_PREFIX}_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
-elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 2)
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3")
+  set(_${_PYTHON_PREFIX}_VERSIONS 3.12 3.11 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
+elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "2")
   set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
 else()
   message (FATAL_ERROR "FindPython: INTERNAL ERROR")
 endif()
 
 get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE)
-if (NOT DEFINED _${_PYTHON_PREFIX}_CMAKE_ROLE)
-  # CMake 3.14 introduced CMAKE_ROLE
-  set(_${_PYTHON_PREFIX}_CMAKE_ROLE "PROJECT")
-endif()
 
+include (FindPackageHandleStandardArgs)
 
 #
 # helper commands
@@ -46,70 +50,868 @@ macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG)
   set (${_PYTHON_PREFIX}_FOUND FALSE)
   string (TOUPPER "${_PYTHON_PREFIX}" _${_PYTHON_PREFIX}_UPPER_PREFIX)
   set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE)
-  return()
+endmacro()
+
+
+function (_PYTHON_ADD_REASON_FAILURE module message)
+  if (_${_PYTHON_PREFIX}_${module}_REASON_FAILURE)
+    string (LENGTH "${_${_PYTHON_PREFIX}_${module}_REASON_FAILURE}" length)
+    math (EXPR length "${length} + 10")
+    string (REPEAT " " ${length} shift)
+    set_property (CACHE _${_PYTHON_PREFIX}_${module}_REASON_FAILURE PROPERTY VALUE "${_${_PYTHON_PREFIX}_${module}_REASON_FAILURE}\n${shift}${message}")
+  else()
+    set_property (CACHE _${_PYTHON_PREFIX}_${module}_REASON_FAILURE PROPERTY VALUE "${message}")
+  endif()
+endfunction()
+
+
+function (_PYTHON_MARK_AS_INTERNAL)
+  foreach (var IN LISTS ARGV)
+    if (DEFINED CACHE{${var}})
+      set_property (CACHE ${var} PROPERTY TYPE INTERNAL)
+    endif()
+  endforeach()
+endfunction()
+
+
+macro (_PYTHON_SELECT_LIBRARY_CONFIGURATIONS _PYTHON_BASENAME)
+  if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+    set(${_PYTHON_BASENAME}_LIBRARY_RELEASE "${_PYTHON_BASENAME}_LIBRARY_RELEASE-NOTFOUND")
+  endif()
+  if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+    set(${_PYTHON_BASENAME}_LIBRARY_DEBUG "${_PYTHON_BASENAME}_LIBRARY_DEBUG-NOTFOUND")
+  endif()
+
+  get_property(_PYTHON_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+  if (${_PYTHON_BASENAME}_LIBRARY_DEBUG AND ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND
+      NOT ${_PYTHON_BASENAME}_LIBRARY_DEBUG STREQUAL ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND
+      (_PYTHON_isMultiConfig OR CMAKE_BUILD_TYPE))
+    # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+    # single-config generators, set optimized and debug libraries
+    set (${_PYTHON_BASENAME}_LIBRARIES "")
+    foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+      list( APPEND ${_PYTHON_BASENAME}_LIBRARIES optimized "${_PYTHON_libname}")
+    endforeach()
+    foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+      list( APPEND ${_PYTHON_BASENAME}_LIBRARIES debug "${_PYTHON_libname}")
+    endforeach()
+  elseif (${_PYTHON_BASENAME}_LIBRARY_RELEASE)
+    set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_RELEASE}")
+  elseif (${_PYTHON_BASENAME}_LIBRARY_DEBUG)
+    set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_DEBUG}")
+  else()
+    set (${_PYTHON_BASENAME}_LIBRARIES "${_PYTHON_BASENAME}_LIBRARY-NOTFOUND")
+  endif()
 endmacro()
 
 
 macro (_PYTHON_FIND_FRAMEWORKS)
-  set (${_PYTHON_PREFIX}_FRAMEWORKS)
-  if (APPLE)
+  if (CMAKE_HOST_APPLE OR APPLE)
+    file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _pff_CMAKE_FRAMEWORK_PATH)
     set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH}
-                    $ENV{CMAKE_FRAMEWORK_PATH}
-                    ~/Library/Frameworks
-                    /usr/local/Frameworks
-                    ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+                         ${_pff_CMAKE_FRAMEWORK_PATH}
+                         ~/Library/Frameworks
+                         /usr/local/Frameworks
+                         /opt/homebrew/Frameworks
+                         ${CMAKE_SYSTEM_FRAMEWORK_PATH})
     list (REMOVE_DUPLICATES _pff_frameworks)
-    foreach (_pff_framework IN LISTS _pff_frameworks)
-      if (EXISTS ${_pff_framework}/Python.framework)
-        list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python.framework)
+    foreach (_pff_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+      unset (_${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS)
+      if (_pff_implementation STREQUAL "CPython")
+        foreach (_pff_framework IN LISTS _pff_frameworks)
+          if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework)
+          endif()
+          if (EXISTS ${_pff_framework}/Python.framework)
+            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python.framework)
+          endif()
+        endforeach()
+      elseif (_pff_implementation STREQUAL "IronPython")
+        foreach (_pff_framework IN LISTS _pff_frameworks)
+          if (EXISTS ${_pff_framework}/IronPython.framework)
+            list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/IronPython.framework)
+          endif()
+        endforeach()
       endif()
     endforeach()
+    unset (_pff_implementation)
     unset (_pff_frameworks)
     unset (_pff_framework)
   endif()
 endmacro()
 
-function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS _PYTHON_VERSION)
-  set (_PYTHON_FRAMEWORK_PATHS)
-  foreach (_PYTHON_FRAMEWORK IN LISTS ${_PYTHON_PREFIX}_FRAMEWORKS)
-    list (APPEND _PYTHON_FRAMEWORK_PATHS
-          "${_PYTHON_FRAMEWORK}/Versions/${_PYTHON_VERSION}")
+function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGF "" "" "IMPLEMENTATIONS;VERSION")
+
+  if (NOT _PGF_IMPLEMENTATIONS)
+    set (_PGF_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+  endif()
+
+  set (framework_paths)
+
+  foreach (implementation IN LISTS _PGF_IMPLEMENTATIONS)
+    if (implementation STREQUAL "CPython")
+      foreach (version IN LISTS _PGF_VERSION)
+        foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)
+          if (EXISTS "${framework}/Versions/${version}")
+            list (APPEND framework_paths "${framework}/Versions/${version}")
+          endif()
+        endforeach()
+      endforeach()
+    elseif (implementation STREQUAL "IronPython")
+      foreach (version IN LISTS _PGF_VERSION)
+        foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS)
+          # pick-up all available versions
+          file (GLOB versions LIST_DIRECTORIES true RELATIVE "${framework}/Versions/"
+                              "${framework}/Versions/${version}*")
+          list (SORT versions ORDER DESCENDING)
+          list (TRANSFORM versions PREPEND "${framework}/Versions/")
+          list (APPEND framework_paths ${versions})
+        endforeach()
+      endforeach()
+    endif()
   endforeach()
-  set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${_PYTHON_FRAMEWORK_PATHS} PARENT_SCOPE)
+
+  set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${framework_paths} PARENT_SCOPE)
 endfunction()
 
+function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGR "" "" "IMPLEMENTATIONS;VERSION")
 
-function (_PYTHON_VALIDATE_INTERPRETER)
-  if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
+  if (NOT _PGR_IMPLEMENTATIONS)
+    set (_PGR_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+  endif()
+
+  set (registries)
+
+  foreach (implementation IN LISTS _PGR_IMPLEMENTATIONS)
+    if (implementation STREQUAL "CPython")
+      foreach (version IN LISTS _PGR_VERSION)
+        string (REPLACE "." "" version_no_dots ${version})
+        list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths)
+        list (APPEND registries ${reg_paths})
+        if (version VERSION_GREATER_EQUAL "3.5")
+          # cmake_host_system_information is not usable in bootstrap
+          get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME)
+          string (REPLACE "bit" "" arch "${arch}")
+          if (arch IN_LIST _${_PYTHON_PREFIX}_ARCH)
+            list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath])
+          endif()
+        else()
+          list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath])
+        endif()
+        list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths)
+        list (APPEND registries ${reg_paths})
+        list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths)
+        list (APPEND registries ${reg_paths})
+        list (APPEND registries [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath])
+        list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths)
+        list (APPEND registries ${reg_paths})
+      endforeach()
+    elseif (implementation STREQUAL "IronPython")
+      foreach (version  IN LISTS _PGR_VERSION)
+        list (APPEND registries [HKEY_LOCAL_MACHINE/SOFTWARE/IronPython/${version}/InstallPath])
+      endforeach()
+    endif()
+  endforeach()
+
+  set (${_PYTHON_PGR_REGISTRY_PATHS} "${registries}" PARENT_SCOPE)
+endfunction()
+
+
+function (_PYTHON_GET_ABIFLAGS _PGABIFLAGS)
+  set (abiflags)
+  list (GET _${_PYTHON_PREFIX}_FIND_ABI 0 pydebug)
+  list (GET _${_PYTHON_PREFIX}_FIND_ABI 1 pymalloc)
+  list (GET _${_PYTHON_PREFIX}_FIND_ABI 2 unicode)
+
+  if (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ANY")
+    set (abiflags "mu" "m" "u" "")
+  elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ON")
+    set (abiflags "mu" "u")
+  elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "OFF")
+    set (abiflags "m" "")
+  elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY")
+    set (abiflags "mu" "m")
+  elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ON")
+    set (abiflags "mu")
+  elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "OFF")
+    set (abiflags "m")
+  elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY")
+    set (abiflags "u" "")
+  elseif (pymalloc STREQUAL "OFF" AND unicode STREQUAL "ON")
+    set (abiflags "u")
+  endif()
+
+  if (pydebug STREQUAL "ON")
+    if (abiflags)
+      list (TRANSFORM abiflags PREPEND "d")
+    else()
+      set (abiflags "d")
+    endif()
+  elseif (pydebug STREQUAL "ANY")
+    if (abiflags)
+      set (flags "${abiflags}")
+      list (TRANSFORM flags PREPEND "d")
+      list (APPEND abiflags "${flags}")
+    else()
+      set (abiflags "" "d")
+    endif()
+  endif()
+
+  set (${_PGABIFLAGS} "${abiflags}" PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGPS "INTERPRETER;COMPILER;LIBRARY;INCLUDE" "" "IMPLEMENTATIONS;VERSION")
+
+  if (NOT _PGPS_IMPLEMENTATIONS)
+    set (_PGPS_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+  endif()
+
+  if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)
+    set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}")
+  else()
+    set (abi "mu" "m" "u" "")
+  endif()
+
+  set (path_suffixes)
+
+  foreach (implementation IN LISTS _PGPS_IMPLEMENTATIONS)
+    if (implementation STREQUAL "CPython")
+      if (_PGPS_INTERPRETER)
+        list (APPEND path_suffixes bin Scripts)
+      else()
+        foreach (version IN LISTS _PGPS_VERSION)
+          if (_PGPS_LIBRARY)
+            if (CMAKE_LIBRARY_ARCHITECTURE)
+              list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE})
+            endif()
+            list (APPEND path_suffixes lib libs)
+
+            if (CMAKE_LIBRARY_ARCHITECTURE)
+              set (suffixes "${abi}")
+              if (suffixes)
+                list (TRANSFORM suffixes PREPEND "lib/python${version}/config-${version}")
+                list (TRANSFORM suffixes APPEND "-${CMAKE_LIBRARY_ARCHITECTURE}")
+              else()
+                set (suffixes "lib/python${version}/config-${version}-${CMAKE_LIBRARY_ARCHITECTURE}")
+              endif()
+              list (APPEND path_suffixes ${suffixes})
+            endif()
+            set (suffixes "${abi}")
+            if (suffixes)
+              list (TRANSFORM suffixes PREPEND "lib/python${version}/config-${version}")
+            else()
+              set (suffixes "lib/python${version}/config-${version}")
+            endif()
+            list (APPEND path_suffixes ${suffixes})
+          elseif (_PGPS_INCLUDE)
+            set (suffixes "${abi}")
+            if (suffixes)
+              list (TRANSFORM suffixes PREPEND "include/python${version}")
+            else()
+              set (suffixes "include/python${version}")
+            endif()
+            list (APPEND path_suffixes ${suffixes} include)
+          endif()
+        endforeach()
+      endif()
+    elseif (implementation STREQUAL "IronPython")
+      if (_PGPS_INTERPRETER OR _PGPS_COMPILER)
+        foreach (version IN LISTS _PGPS_VERSION)
+          list (APPEND path_suffixes "share/ironpython${version}")
+        endforeach()
+        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+      endif()
+    elseif (implementation STREQUAL "PyPy")
+      if (_PGPS_INTERPRETER)
+        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES})
+      elseif (_PGPS_LIBRARY)
+        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES})
+      elseif (_PGPS_INCLUDE)
+        foreach (version IN LISTS _PGPS_VERSION)
+          list (APPEND path_suffixes lib/pypy${version}/include pypy${version}/include)
+        endforeach()
+        list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES})
+      endif()
+    endif()
+  endforeach()
+  list (REMOVE_DUPLICATES path_suffixes)
+
+  set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGN "POSIX;INTERPRETER;COMPILER;CONFIG;LIBRARY;WIN32;DEBUG" "" "IMPLEMENTATIONS;VERSION")
+
+  if (NOT _PGN_IMPLEMENTATIONS)
+    set (_PGN_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS})
+  endif()
+
+  set (names)
+
+  foreach (implementation IN LISTS _PGN_IMPLEMENTATIONS)
+    if (implementation STREQUAL "CPython")
+      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "FIRST")
+        list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+      endif()
+      foreach (version IN LISTS _PGN_VERSION)
+        if (_PGN_WIN32)
+          string (REPLACE "." "" version_no_dots ${version})
+
+          set (name python${version_no_dots})
+          if (_PGN_DEBUG)
+            string (APPEND name "_d")
+          endif()
+
+          list (APPEND names "${name}")
+        endif()
+
+        if (_PGN_POSIX)
+          if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)
+            set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}")
+          else()
+            if (_PGN_INTERPRETER OR _PGN_CONFIG)
+              set (abi "")
+            else()
+              set (abi "mu" "m" "u" "")
+            endif()
+          endif()
+
+          if (abi)
+            if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+              set (abinames "${abi}")
+              list (TRANSFORM abinames PREPEND "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}")
+              list (TRANSFORM abinames APPEND "-config")
+              list (APPEND names ${abinames})
+            endif()
+            set (abinames "${abi}")
+            list (TRANSFORM abinames PREPEND "python${version}")
+            if (_PGN_CONFIG)
+              list (TRANSFORM abinames APPEND "-config")
+            endif()
+            list (APPEND names ${abinames})
+          else()
+            unset (abinames)
+            if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+              set (abinames "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}")
+            endif()
+            list (APPEND abinames "python${version}")
+            if (_PGN_CONFIG)
+              list (TRANSFORM abinames APPEND "-config")
+            endif()
+            list (APPEND names ${abinames})
+          endif()
+        endif()
+      endforeach()
+      if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "LAST")
+        list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python)
+      endif()
+    elseif (implementation STREQUAL "IronPython")
+      if (_PGN_INTERPRETER)
+        if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+          # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used
+          foreach (version IN LISTS _PGN_VERSION)
+            list (APPEND names "ipy${version}")
+          endforeach()
+        endif()
+        list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES})
+      elseif (_PGN_COMPILER)
+        list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES})
+      endif()
+    elseif (implementation STREQUAL "PyPy")
+      if (_PGN_INTERPRETER)
+        list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_NAMES})
+      elseif (_PGN_LIBRARY)
+        if (_PGN_WIN32)
+          foreach (version IN LISTS _PGN_VERSION)
+            string (REPLACE "." "" version_no_dots ${version})
+            set (name "python${version_no_dots}")
+            if (_PGN_DEBUG)
+              string (APPEND name "_d")
+            endif()
+            list (APPEND names "${name}")
+          endforeach()
+        endif()
+
+        if (_PGN_POSIX)
+          foreach(version IN LISTS _PGN_VERSION)
+            list (APPEND names "pypy${version}-c")
+          endforeach()
+        endif()
+
+        list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_LIB_NAMES})
+      endif()
+    endif()
+  endforeach()
+
+  set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME)
+  unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE)
+
+  if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI|SOSABI)$")
+    return()
+  endif()
+
+  if (NAME STREQUAL "SOSABI")
+    # assume some default
+    if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN")
+      set (_values "")
+    else()
+      set (_values "abi${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}")
+    endif()
+  elseif (_${_PYTHON_PREFIX}_CONFIG)
+    if (NAME STREQUAL "SOABI")
+      set (config_flag "--extension-suffix")
+    else()
+      set (config_flag "--${NAME}")
+    endif()
+    string (TOLOWER "${config_flag}" config_flag)
+    execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} ${config_flag}
+                     RESULT_VARIABLE _result
+                     OUTPUT_VARIABLE _values
+                     ERROR_QUIET
+                     OUTPUT_STRIP_TRAILING_WHITESPACE)
+    if (_result)
+      unset (_values)
+    else()
+      if (NAME STREQUAL "INCLUDES")
+        # do some clean-up
+        string (REGEX MATCHALL "(-I|-iwithsysroot)[ ]*[^ ]+" _values "${_values}")
+        string (REGEX REPLACE "(-I|-iwithsysroot)[ ]*" "" _values "${_values}")
+        list (REMOVE_DUPLICATES _values)
+      elseif (NAME STREQUAL "SOABI")
+        # clean-up: remove prefix character and suffix
+        if (_values MATCHES "^(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+          set(_values "")
+        else()
+          string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+        endif()
+      endif()
+    endif()
+  endif()
+
+  if (_${_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]))"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _values
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      else()
+        list (REMOVE_DUPLICATES _values)
+      endif()
+    elseif (NAME STREQUAL "INCLUDES")
+      if (WIN32)
+        set (_scheme "nt")
+      else()
+        set (_scheme "posix_prefix")
+      endif()
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _values
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      else()
+        list (REMOVE_DUPLICATES _values)
+      endif()
+    elseif (NAME STREQUAL "SOABI")
+      # first step: compute SOABI form EXT_SUFFIX config variable
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')\nexcept Exception:\n   from distutils import sysconfig;sys.stdout.write(sysconfig.get_config_var('EXT_SUFFIX') or '')"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _values
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      else()
+        if (_values)
+          # clean-up: remove prefix character and suffix
+          if (_values MATCHES "^(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+            set(_values "")
+          else()
+            string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+          endif()
+        endif()
+      endif()
+
+      # second step: use SOABI or SO config variables as fallback
+      if (NOT _values)
+        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('SOABI') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n   from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('SO') or '']))"
+          RESULT_VARIABLE _result
+          OUTPUT_VARIABLE _soabi
+          ERROR_QUIET
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+        if (_result)
+          unset (_values)
+        else()
+          foreach (_item IN LISTS _soabi)
+            if (_item)
+              set (_values "${_item}")
+              break()
+            endif()
+          endforeach()
+          if (_values)
+            # clean-up: remove prefix character and suffix
+            if (_values MATCHES "^(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$")
+              set(_values "")
+            else()
+              string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}")
+            endif()
+          endif()
+        endif()
+      endif()
+    elseif (NAME STREQUAL "SOSABI")
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\nimport re\nimport importlib.machinery\nsys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _values
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      else()
+        string (REGEX REPLACE "^\\.(.+)\\.[^.]+$" "\\1" _values "${_values}")
+      endif()
+    else()
+      set (config_flag "${NAME}")
+      if (NAME STREQUAL "CONFIGDIR")
+        set (config_flag "LIBPL")
+      endif()
+      execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                               "import sys\ntry:\n   import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n   from distutils import sysconfig\n   sys.stdout.write(sysconfig.get_config_var('${config_flag}'))"
+                       RESULT_VARIABLE _result
+                       OUTPUT_VARIABLE _values
+                       ERROR_QUIET
+                       OUTPUT_STRIP_TRAILING_WHITESPACE)
+      if (_result)
+        unset (_values)
+      endif()
+    endif()
+  endif()
+
+  if (NAME STREQUAL "ABIFLAGS" OR NAME STREQUAL "SOABI" OR NAME STREQUAL "SOSABI")
+    set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
+    return()
+  endif()
+
+  if (NOT _values OR _values STREQUAL "None")
     return()
   endif()
 
-  if (ARGC EQUAL 1)
-    set (expected_version ${ARGV0})
+  if (NAME STREQUAL "LIBS")
+    # do some clean-up
+    string (REGEX MATCHALL "-(l|framework)[ ]*[^ ]+" _values "${_values}")
+    # remove elements relative to python library itself
+    list (FILTER _values EXCLUDE REGEX "-lpython")
+    list (REMOVE_DUPLICATES _values)
+  endif()
+
+  if (WIN32 AND NAME MATCHES "^(PREFIX|CONFIGDIR|INCLUDES)$")
+    file (TO_CMAKE_PATH "${_values}" _values)
+  endif()
+
+  set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE)
+endfunction()
+
+function (_PYTHON_GET_VERSION)
+  cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;SABI_LIBRARY;INCLUDE" "PREFIX" "")
+
+  unset (${_PGV_PREFIX}VERSION PARENT_SCOPE)
+  unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE)
+  unset (${_PGV_PREFIX}VERSION_MINOR PARENT_SCOPE)
+  unset (${_PGV_PREFIX}VERSION_PATCH PARENT_SCOPE)
+  unset (${_PGV_PREFIX}ABI PARENT_SCOPE)
+
+  if (_PGV_LIBRARY)
+    # retrieve version and abi from library name
+    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      get_filename_component (library_name "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" NAME)
+      # extract version from library name
+      if (library_name MATCHES "python([23])([0-9]+)")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      elseif (library_name MATCHES "python([23])\\.([0-9]+)([dmu]*)")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_3}" PARENT_SCOPE)
+      elseif (library_name MATCHES "pypy([23])\\.([0-9]+)-c")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      elseif (library_name MATCHES "pypy(3)?-c")
+        set (version "${CMAKE_MATCH_1}")
+        # try to pick-up a more precise version from the path
+        get_filename_component (library_dir "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+        if (library_dir MATCHES "/pypy([23])\\.([0-9]+)/")
+          set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+          set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE)
+          set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE)
+        elseif (version EQUAL "3")
+          set (${_PGV_PREFIX}VERSION_MAJOR "3" PARENT_SCOPE)
+          set (${_PGV_PREFIX}VERSION "3" PARENT_SCOPE)
+        else()
+          set (${_PGV_PREFIX}VERSION_MAJOR "2" PARENT_SCOPE)
+          set (${_PGV_PREFIX}VERSION "2" PARENT_SCOPE)
+        endif()
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      endif()
+    endif()
+  elseif (_PGV_SABI_LIBRARY)
+    # retrieve version and abi from library name
+    if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+      get_filename_component (library_name "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" NAME)
+      # extract version from library name
+      if (library_name MATCHES "python([23])([dmu]*)")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_2}" PARENT_SCOPE)
+      elseif (library_name MATCHES "pypy([23])-c")
+        set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      elseif (library_name MATCHES "pypy-c")
+        # try to pick-up a more precise version from the path
+        get_filename_component (library_dir "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+        if (library_dir MATCHES "/pypy([23])\\.([0-9]+)/")
+          set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE)
+          set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
+        endif()
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      endif()
+    endif()
   else()
-    unset (expected_version)
+    if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
+      # retrieve version from header file
+      file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" version
+            REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
+      string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+                            version "${version}")
+      string (REGEX MATCHALL "[0-9]+" versions "${version}")
+      list (GET versions 0 version_major)
+      list (GET versions 1 version_minor)
+      list (GET versions 2 version_patch)
+
+      set (${_PGV_PREFIX}VERSION "${version_major}.${version_minor}.${version_patch}" PARENT_SCOPE)
+      set (${_PGV_PREFIX}VERSION_MAJOR ${version_major} PARENT_SCOPE)
+      set (${_PGV_PREFIX}VERSION_MINOR ${version_minor} PARENT_SCOPE)
+      set (${_PGV_PREFIX}VERSION_PATCH ${version_patch} PARENT_SCOPE)
+
+      # compute ABI flags
+      if (version_major VERSION_GREATER "2")
+        file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/pyconfig.h" config REGEX "(Py_DEBUG|WITH_PYMALLOC|Py_UNICODE_SIZE|MS_WIN32)")
+        set (abi)
+        if (config MATCHES "#[ ]*define[ ]+MS_WIN32")
+          # ABI not used on Windows
+          set (abi "")
+        else()
+          if (NOT config)
+            # pyconfig.h can be a wrapper to a platform specific pyconfig.h
+            # In this case, try to identify ABI from include directory
+            if (_${_PYTHON_PREFIX}_INCLUDE_DIR MATCHES "python${version_major}\\.${version_minor}+([dmu]*)")
+              set (abi "${CMAKE_MATCH_1}")
+            else()
+              set (abi "")
+            endif()
+          else()
+            if (config MATCHES "#[ ]*define[ ]+Py_DEBUG[ ]+1")
+              string (APPEND abi "d")
+            endif()
+            if (config MATCHES "#[ ]*define[ ]+WITH_PYMALLOC[ ]+1")
+              string (APPEND abi "m")
+            endif()
+            if (config MATCHES "#[ ]*define[ ]+Py_UNICODE_SIZE[ ]+4")
+              string (APPEND abi "u")
+            endif()
+          endif()
+          set (${_PGV_PREFIX}ABI "${abi}" PARENT_SCOPE)
+        endif()
+      else()
+        # ABI not supported
+        set (${_PGV_PREFIX}ABI "" PARENT_SCOPE)
+      endif()
+    endif()
+  endif()
+endfunction()
+
+function (_PYTHON_GET_LAUNCHER _PYTHON_PGL_NAME)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGL "INTERPRETER;COMPILER" "CONFIG" "")
+
+  unset (${_PYTHON_PGL_NAME} PARENT_SCOPE)
+
+  if ((_PGL_INTERPRETER AND NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+      OR (_PGL_COMPILER AND NOT _${_PYTHON_PREFIX}_COMPILER)
+      OR (_PGL_CONFIG AND NOT _${_PYTHON_PREFIX}_CONFIG))
+    return()
+  endif()
+
+  if (_PGL_CONFIG)
+    # default config script can be launched directly
+    set (${_PYTHON_PGL_NAME} "${_${_PYTHON_PREFIX}_CONFIG}" PARENT_SCOPE)
+
+    if (NOT MINGW)
+      return()
+    endif()
+    # on MINGW environment, python-config script may require bash to be launched
+    execute_process (COMMAND cygpath.exe -u "${_${_PYTHON_PREFIX}_CONFIG}"
+            RESULT_VARIABLE _result
+            OUTPUT_VARIABLE _config
+            ERROR_QUIET
+            OUTPUT_STRIP_TRAILING_WHITESPACE)
+    if (_result)
+      # impossible to convert path, keep default config
+      return()
+    endif()
+    execute_process (COMMAND bash.exe "${_config}" --prefix
+            RESULT_VARIABLE _result
+            OUTPUT_QUIET
+            ERROR_QUIET)
+    if (_result)
+      # fail to execute through bash, keep default config
+      return()
+    endif()
+
+    set(${_PYTHON_PGL_NAME} bash.exe "${_config}" PARENT_SCOPE)
+    return()
+  endif()
+
+  if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+      AND NOT SYSTEM_NAME MATCHES "Windows|Linux")
+    if (_PGL_INTERPRETER)
+      get_filename_component (name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
+      get_filename_component (ext "${_${_PYTHON_PREFIX}_EXECUTABLE}" LAST_EXT)
+      if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES
+          AND ext STREQUAL ".exe")
+        set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE)
+      endif()
+    elseif (_PGL_COMPILER)
+      get_filename_component (name "${_${_PYTHON_PREFIX}_COMPILER}" NAME)
+      get_filename_component (ext "${_${_PYTHON_PREFIX}_COMPILER}" LAST_EXT)
+      if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES
+          AND ext STREQUAL ".exe")
+        set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE)
+      endif()
+    endif()
+  endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_INTERPRETER)
+  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+    return()
+  endif()
+
+  cmake_parse_arguments (PARSE_ARGV 0 _PVI "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
+
+  if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}")
+    # interpreter does not exist anymore
+    set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+    return()
   endif()
 
-  get_filename_component (python_name "${${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
+  _python_get_launcher (launcher INTERPRETER)
 
-  if (expected_version AND NOT python_name STREQUAL "python${expected_version}${CMAKE_EXECUTABLE_SUFFIX}")
-    # executable found must have a specific version
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                             "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))"
+  # validate ABI compatibility
+  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI)
+    execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                             "import sys; sys.stdout.write(sys.abiflags)"
+                     RESULT_VARIABLE result
+                     OUTPUT_VARIABLE abi
+                     ERROR_QUIET
+                     OUTPUT_STRIP_TRAILING_WHITESPACE)
+    if (result)
+      # assume ABI is not supported
+      set (abi "")
+    endif()
+    if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+      # incompatible ABI
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+      return()
+    endif()
+  endif()
+
+  if (_PVI_IN_RANGE OR _PVI_VERSION)
+    # retrieve full version
+    execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                             "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))"
                      RESULT_VARIABLE result
                      OUTPUT_VARIABLE version
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (result OR NOT version EQUAL expected_version)
-      # interpreter not usable or has wrong major version
-      set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
+    if (result)
+      # interpreter is not usable
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
+
+    if (_PVI_VERSION)
+      # check against specified version
+      ## compute number of components for version
+      string (REGEX REPLACE "[^.]" "" dots "${_PVI_VERSION}")
+      ## add one dot because there is one dot less than there are components
+      string (LENGTH "${dots}." count)
+      if (count GREATER 3)
+        set (count 3)
+      endif()
+      set (version_regex "^[0-9]+")
+      if (count EQUAL 3)
+        string (APPEND version_regex "\\.[0-9]+\\.[0-9]+")
+      elseif (count EQUAL 2)
+        string (APPEND version_regex "\\.[0-9]+")
+      endif()
+      # extract needed range
+      string (REGEX MATCH "${version_regex}" version "${version}")
+
+      if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION)
+        # interpreter has wrong version
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+        return()
+      else()
+        # check that version is OK
+        string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+        string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVI_VERSION}")
+        if (NOT major_version VERSION_EQUAL expected_major_version
+            OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+          return()
+        endif()
+      endif()
+    endif()
+
+    if (_PVI_IN_RANGE)
+      # check if version is in the requested range
+      find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
+      if (NOT in_range)
+        # interpreter has invalid version
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+        return()
+      endif()
+    endif()
   else()
+    get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
     if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}")
       # executable found do not have version in name
       # ensure major version is OK
-      execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+      execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
                                "import sys; sys.stdout.write(str(sys.version_info[0]))"
                        RESULT_VARIABLE result
                        OUTPUT_VARIABLE version
@@ -117,16 +919,23 @@ function (_PYTHON_VALIDATE_INTERPRETER)
                        OUTPUT_STRIP_TRAILING_WHITESPACE)
       if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
         # interpreter not usable or has wrong major version
-        set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
+        if (result)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        else()
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        endif()
+        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
       endif()
     endif()
   endif()
 
-  if (CMAKE_SIZEOF_VOID_P AND "Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+  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)
       AND NOT CMAKE_CROSSCOMPILING)
     # In this case, interpreter must have same architecture as environment
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+    execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
                              "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))"
                      RESULT_VARIABLE result
                      OUTPUT_VARIABLE size
@@ -134,36 +943,320 @@ function (_PYTHON_VALIDATE_INTERPRETER)
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P)
       # interpreter not usable or has wrong architecture
-      set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
+      if (result)
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      else()
+        set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+      endif()
+      set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+      return()
+    endif()
+
+    if (WIN32)
+      # In this case, check if the interpreter is compatible with the target processor architecture
+      if (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM")
+        set(target_arm TRUE)
+      else()
+        set(target_arm FALSE)
+      endif()
+      execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+        "import sys, sysconfig; sys.stdout.write(sysconfig.get_platform())"
+        RESULT_VARIABLE result
+        OUTPUT_VARIABLE platform
+        ERROR_QUIET
+        OUTPUT_STRIP_TRAILING_WHITESPACE)
+      string(TOUPPER "${platform}" platform)
+      if (result OR ((target_arm AND NOT platform MATCHES "ARM") OR
+                     (NOT target_arm AND platform MATCHES "ARM")))
+        # interpreter not usable or has wrong architecture
+        if (result)
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        else()
+          set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+        endif()
+        set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+        return()
+      endif()
+    endif()
+  endif()
+endfunction()
+
+function(_python_validate_find_interpreter status interpreter)
+  set(_${_PYTHON_PREFIX}_EXECUTABLE "${interpreter}" CACHE FILEPATH "" FORCE)
+  _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+    set (${status} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_COMPILER)
+  if (NOT _${_PYTHON_PREFIX}_COMPILER)
+    return()
+  endif()
+
+  cmake_parse_arguments (PARSE_ARGV 0 _PVC "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
+
+  if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}")
+    # Compiler does not exist anymore
+    set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+    return()
+  endif()
+
+  _python_get_launcher (launcher COMPILER)
+
+  # retrieve python environment version from compiler
+  set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
+  file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]])); sys.stdout.flush()\n")
+  execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_COMPILER}"
+                           ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
+                           /target:exe /embed "${working_dir}/version.py"
+                   WORKING_DIRECTORY "${working_dir}"
+                   OUTPUT_QUIET
+                   ERROR_QUIET
+                   OUTPUT_STRIP_TRAILING_WHITESPACE)
+  get_filename_component (ir_dir "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY)
+  execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${ir_dir}"
+                                              ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${working_dir}/version.exe"
+                   WORKING_DIRECTORY "${working_dir}"
+                   RESULT_VARIABLE result
+                   OUTPUT_VARIABLE version
+                   ERROR_QUIET)
+  file (REMOVE_RECURSE "${working_dir}")
+  if (result)
+    # compiler is not usable
+    set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+    return()
+  endif()
+
+  if (_PVC_VERSION OR _PVC_IN_RANGE)
+    if (_PVC_VERSION)
+      # check against specified version
+      ## compute number of components for version
+      string (REGEX REPLACE "[^.]" "" dots "${_PVC_VERSION}")
+      ## add one dot because there is one dot less than there are components
+      string (LENGTH "${dots}." count)
+      if (count GREATER 3)
+        set (count 3)
+      endif()
+      set (version_regex "^[0-9]+")
+      if (count EQUAL 3)
+        string (APPEND version_regex "\\.[0-9]+\\.[0-9]+")
+      elseif (count EQUAL 2)
+        string (APPEND version_regex "\\.[0-9]+")
+      endif()
+      # extract needed range
+      string (REGEX MATCH "${version_regex}" version "${version}")
+
+      if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION)
+        # interpreter has wrong version
+        set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+        return()
+      else()
+        # check that version is OK
+        string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+        string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVC_VERSION}")
+        if (NOT major_version VERSION_EQUAL expected_major_version
+            OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION)
+          set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+          return()
+        endif()
+      endif()
+    endif()
+
+    if (_PVC_IN_RANGE)
+      # check if version is in the requested range
+      find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE)
+      if (NOT in_range)
+        # interpreter has invalid version
+        set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
+        return()
+      endif()
+    endif()
+  else()
+    string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}")
+    if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+      # Compiler has wrong major version
+      set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
       return()
     endif()
   endif()
 endfunction()
 
+function(_python_validate_find_compiler status compiler)
+  set(_${_PYTHON_PREFIX}_COMPILER "${compiler}" CACHE FILEPATH "" FORCE)
+  _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS})
+  if (NOT _${_PYTHON_PREFIX}_COMPILER)
+    set (${status} FALSE PARENT_SCOPE)
+  endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_LIBRARY)
+  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+    unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+    return()
+  endif()
+
+  cmake_parse_arguments (PARSE_ARGV 0 _PVL "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
+
+  if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+    # library does not exist anymore
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+    if (WIN32)
+      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+    endif()
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+    return()
+  endif()
+
+  # retrieve version and abi from library name
+  _python_get_version (LIBRARY PREFIX lib_)
+
+  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+    # incompatible ABI
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+  else()
+    if (_PVL_VERSION OR _PVL_IN_RANGE)
+      if (_PVL_VERSION)
+        # library have only major.minor information
+        string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${_PVL_VERSION}")
+        if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version))
+          # library has wrong version
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+        endif()
+      endif()
+
+      if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND _PVL_IN_RANGE)
+        # check if library version is in the requested range
+        find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE)
+        if (NOT in_range)
+          # library has wrong version
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+        endif()
+      endif()
+    else()
+      if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+        # library has wrong major version
+        set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+      endif()
+    endif()
+  endif()
+
+  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+    if (WIN32)
+      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+    endif()
+    unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE CACHE)
+    unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG CACHE)
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+  endif()
+endfunction()
+
+
+function (_PYTHON_VALIDATE_SABI_LIBRARY)
+  if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+    unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG)
+    return()
+  endif()
+
+  cmake_parse_arguments (PARSE_ARGV 0 _PVL "CHECK_EXISTS" "" "")
+
+  if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+    # library does not exist anymore
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+    if (WIN32)
+      set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG-NOTFOUND")
+    endif()
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+    return()
+  endif()
+
+  # retrieve version and abi from library name
+  _python_get_version (SABI_LIBRARY PREFIX lib_)
+
+  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+    # incompatible ABI
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+  else()
+    if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+      # library has wrong major version
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+    endif()
+  endif()
+
+  if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+    if (WIN32)
+      set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND")
+    endif()
+    unset (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE CACHE)
+    unset (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG CACHE)
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+  endif()
+endfunction()
+
 
-function (_PYTHON_VALIDATE_COMPILER expected_version)
-  if (NOT ${_PYTHON_PREFIX}_COMPILER)
+function (_PYTHON_VALIDATE_INCLUDE_DIR)
+  if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
     return()
   endif()
 
-  # retrieve python environment version from compiler
-  set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
-  file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n")
-  execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${working_dir}/version.py"
-                   WORKING_DIRECTORY "${working_dir}"
-                   OUTPUT_QUIET
-                   ERROR_QUIET
-                   OUTPUT_STRIP_TRAILING_WHITESPACE)
-  execute_process (COMMAND "${working_dir}/version"
-                   WORKING_DIRECTORY "${working_dir}"
-                   RESULT_VARIABLE result
-                   OUTPUT_VARIABLE version
-                   ERROR_QUIET)
-  file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
+  cmake_parse_arguments (PARSE_ARGV 0 _PVID "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "")
+
+  if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
+    # include file does not exist anymore
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+    return()
+  endif()
+
+  # retrieve version from header file
+  _python_get_version (INCLUDE PREFIX inc_)
+
+  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+    # incompatible ABI
+    set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+  else()
+    if (_PVID_VERSION OR _PVID_IN_RANGE)
+      if (_PVID_VERSION)
+        if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version))
+          # include dir has wrong version
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+        endif()
+      endif()
 
-  if (result OR NOT version EQUAL expected_version)
-    # Compiler not usable or has wrong major version
-    set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE)
+      if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND PVID_IN_RANGE)
+        # check if include dir is in the request range
+        find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE)
+        if (NOT in_range)
+          # include dir has wrong version
+          set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+          set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+        endif()
+      endif()
+    else()
+      if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+        # include dir has wrong major version
+        set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+        set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+      endif()
+    endif()
   endif()
 endfunction()
 
@@ -186,25 +1279,70 @@ endfunction()
 
 function (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT)
   unset (_PYTHON_DIRS)
-  set (_PYTHON_LIBS ${ARGV})
-  list (REMOVE_AT _PYTHON_LIBS 0)
+  set (_PYTHON_LIBS ${ARGN})
   foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS)
     if (${_PYTHON_LIB})
       get_filename_component (_PYTHON_DIR "${${_PYTHON_LIB}}" DIRECTORY)
       list (APPEND _PYTHON_DIRS "${_PYTHON_DIR}")
     endif()
   endforeach()
-  if (_PYTHON_DIRS)
-    list (REMOVE_DUPLICATES _PYTHON_DIRS)
-  endif()
+  list (REMOVE_DUPLICATES _PYTHON_DIRS)
   set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE)
 endfunction()
 
 
-# If major version is specified, it must be the same as internal major version
-if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR
-    AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
-  _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}\"")
+function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module)
+  if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_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
+      set (${_PYTHON_PREFIX}_Development.SABIModule_FOUND FALSE PARENT_SCOPE)
+      _python_add_reason_failure ("Development" "SABIModule requires version 3.2 or upper.")
+      return()
+    endif()
+
+    string(TOUPPER "${module}" id)
+    set (module_found TRUE)
+
+    if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+        AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      set (module_found FALSE)
+    endif()
+    if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+        AND NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+      set (module_found FALSE)
+    endif()
+    if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+        AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+      set (module_found FALSE)
+    endif()
+
+    set (${_PYTHON_PREFIX}_Development.${module}_FOUND ${module_found} PARENT_SCOPE)
+  endif()
+endfunction()
+
+
+if (${_PYTHON_PREFIX}_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}\"")
+
+    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 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}\"")
+
+    cmake_policy(POP)
+    return()
+  endif()
 endif()
 
 
@@ -214,57 +1352,250 @@ if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS)
   set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE)
 endif()
 if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development")
-  list (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development.Module")
 endif()
-foreach (_${_PYTHON_PREFIX}_COMPONENT IN LISTS ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+  list (APPEND ${_PYTHON_PREFIX}_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)
 endforeach()
-unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)
+  set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE)
+  set (${_PYTHON_PREFIX}_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 (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 (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)
+  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})
+list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
 
 # Set versions to search
 ## default: search any version
 set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS})
+unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
+
+if (${_PYTHON_PREFIX}_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})
+    endif()
+  endforeach()
+else()
+  if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
+    if (${_PYTHON_PREFIX}_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})
+    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})
+        endif()
+      endforeach()
+    endif()
+  endif()
+endif()
+
+# Set ABIs to search
+## default: search any ABI
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_LESS "3")
+  # ABI not supported
+  unset (_${_PYTHON_PREFIX}_FIND_ABI)
+  set (_${_PYTHON_PREFIX}_ABIFLAGS "")
+else()
+  unset (_${_PYTHON_PREFIX}_FIND_ABI)
+  unset (_${_PYTHON_PREFIX}_ABIFLAGS)
+  if (DEFINED ${_PYTHON_PREFIX}_FIND_ABI)
+    # normalization
+    string (TOUPPER "${${_PYTHON_PREFIX}_FIND_ABI}" _${_PYTHON_PREFIX}_FIND_ABI)
+    list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(TRUE|Y(ES)?|1)$" "ON")
+    list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(FALSE|N(O)?|0)$" "OFF")
+    if (NOT _${_PYTHON_PREFIX}_FIND_ABI MATCHES "^(ON|OFF|ANY);(ON|OFF|ANY);(ON|OFF|ANY)$")
+      message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_ABI}: invalid value for '${_PYTHON_PREFIX}_FIND_ABI'. Ignore it")
+      unset (_${_PYTHON_PREFIX}_FIND_ABI)
+    endif()
+    _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS)
+  endif()
+endif()
+unset (${_PYTHON_PREFIX}_SOABI)
+unset (${_PYTHON_PREFIX}_SOSABI)
 
-if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
-  if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT)
-    set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR})
+# Define lookup strategy
+cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY)
+if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW")
+  set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION")
+else()
+  set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
+endif()
+if (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY)
+  if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES "^(VERSION|LOCATION)$")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.")
+    set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION")
   else()
-    unset (_${_PYTHON_PREFIX}_FIND_VERSIONS)
-    # add all compatible versions
-    foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS)
-      if (NOT _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION)
-        list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION})
-      endif()
-    endforeach()
+    set (_${_PYTHON_PREFIX}_FIND_STRATEGY "${${_PYTHON_PREFIX}_FIND_STRATEGY}")
   endif()
 endif()
 
 # Python and Anaconda distributions: define which architectures can be used
+unset (_${_PYTHON_PREFIX}_REGISTRY_VIEW)
 if (CMAKE_SIZEOF_VOID_P)
-  # In this case, search only for 64bit or 32bit
   math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
-  set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH})
+  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)
+    # 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"
+                   OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM"))
+      # search exclusively ARM architecture: 64bit or 32bit
+      if (_${_PYTHON_PREFIX}_ARCH EQUAL 64)
+        set (_${_PYTHON_PREFIX}_ARCH ARM64)
+      else()
+        set (_${_PYTHON_PREFIX}_ARCH ARM)
+      endif()
+    endif()
+  else()
+    if (_${_PYTHON_PREFIX}_ARCH EQUAL "32")
+      if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+        # search first ARM architectures: 32bit and then 64bit
+        list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM ARM64)
+      endif()
+      list (APPEND _${_PYTHON_PREFIX}_ARCH 64)
+    else()
+      if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+        # search first ARM architectures: 64bit and then 32bit
+        list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM)
+      endif()
+      list (APPEND _${_PYTHON_PREFIX}_ARCH 32)
+    endif()
+  endif()
 else()
   # architecture unknown, search for both 64bit and 32bit
-  set (_${_PYTHON_PREFIX}_ARCH 64)
-  set (_${_PYTHON_PREFIX}_ARCH2 32)
+  set (_${_PYTHON_PREFIX}_ARCH 64 32)
+  if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM")
+    list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM)
+  endif()
 endif()
 
 # IronPython support
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES)
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES)
+unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS)
 if (CMAKE_SIZEOF_VOID_P)
-  # In this case, search only for 64bit or 32bit
-  math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8")
-  set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy${_${_PYTHON_PREFIX}_ARCH} ipy)
+  if (CMAKE_SIZEOF_VOID_P EQUAL "4")
+    set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x86")
+  else()
+    set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x64")
+  endif()
+endif()
+if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used
+  list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}" "ipy64" "ipy32" "ipy")
+  list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc")
+endif()
+list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy.exe")
+list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc.exe")
+set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40 bin)
+
+# PyPy support
+if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3")
+  set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy3)
+  set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy3-c)
+  if (WIN32)
+    # special name for runtime part
+    list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy3-c)
+  endif()
+  set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy3/include pypy3/include)
+else()
+  set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy)
+  set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy-c)
+  if (WIN32)
+    # special name for runtime part
+    list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy-c)
+  endif()
+  set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy/include pypy/include)
+endif()
+list (APPEND _${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES libexec/include)
+set (_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES bin)
+set (_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES lib libs bin)
+list (APPEND _${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES include)
+
+# Python Implementations handling
+unset (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+if (DEFINED ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+  foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+    if (NOT _${_PYTHON_PREFIX}_IMPLEMENTATION MATCHES "^(CPython|IronPython|PyPy)$")
+      message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_IMPLEMENTATION}: invalid value for '${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS'. 'CPython', 'IronPython' or 'PyPy' expected. Value will be ignored.")
+    else()
+      list (APPEND _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_IMPLEMENTATION})
+    endif()
+  endforeach()
 else()
-  # architecture unknown, search for natural interpreter
-  set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy)
+  if (WIN32)
+    set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython IronPython)
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython)
+  endif()
 endif()
-set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40)
+
+# compute list of names for header file
+unset (_${_PYTHON_PREFIX}_INCLUDE_NAMES)
+foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+  if (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "CPython")
+    list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "Python.h")
+  elseif (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "PyPy")
+    list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "PyPy.h" "pypy_decl.h")
+  endif()
+endforeach()
+
 
 # Apple frameworks handling
 _python_find_frameworks ()
 
+set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
+
+if (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK)
+  if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK})
+  endif()
+elseif (DEFINED CMAKE_FIND_FRAMEWORK)
+  if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.")
+  elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
+  endif()
+endif()
+
 # Save CMAKE_FIND_APPBUNDLE
 if (DEFINED CMAKE_FIND_APPBUNDLE)
   set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE})
@@ -277,15 +1608,8 @@ set (CMAKE_FIND_APPBUNDLE "NEVER")
 # Save CMAKE_FIND_FRAMEWORK
 if (DEFINED CMAKE_FIND_FRAMEWORK)
   set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
-  if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY")
-    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.")
-    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
-  else()
-    set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK})
-  endif()
 else()
   unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK)
-  set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST")
 endif()
 # To avoid framework lookup
 set (CMAKE_FIND_FRAMEWORK "NEVER")
@@ -293,7 +1617,7 @@ set (CMAKE_FIND_FRAMEWORK "NEVER")
 # Windows Registry handling
 if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY)
   if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$")
-    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected.")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.")
     set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
   else()
     set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY})
@@ -302,321 +1626,943 @@ else()
   set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
 endif()
 
+# virtual environments recognition
+if (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX})
+  if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV)
+    if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
+      message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
+      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST")
+    else()
+      set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV})
+    endif()
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST)
+  endif()
+else()
+  set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD)
+endif()
+
+
+# Python naming handling
+if (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES)
+  if (NOT ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES MATCHES "^(FIRST|LAST|NEVER)$")
+    message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}: invalid value for '${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES'. 'FIRST', 'LAST' or 'NEVER' expected. 'LAST' will be used instead.")
+    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+  else()
+    set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES ${${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES})
+  endif()
+else()
+  set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST)
+endif()
+
+
+# Compute search signature
+# This signature will be used to check validity of cached variables on new search
+set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}")
+if (NOT WIN32)
+  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:")
+endif()
+if (CMAKE_HOST_APPLE)
+  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}")
+endif()
+if (CMAKE_HOST_WIN32)
+  string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_REGISTRY}")
+endif()
+
+function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module)
+  if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
+    string (TOUPPER "${module}" id)
+    set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:")
+    if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
+    endif()
+    if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}:")
+    endif()
+    if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
+    endif()
+    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)
+          _python_validate_library (IN_RANGE CHECK_EXISTS)
+        elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+          _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+        else()
+          _python_validate_library (CHECK_EXISTS)
+        endif()
+      endif()
+      if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+          _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)
+          _python_validate_include_dir (IN_RANGE CHECK_EXISTS)
+        elseif (${_PYTHON_PREFIX}_FIND_VERSION)
+          _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+        else()
+          _python_validate_include_dir (CHECK_EXISTS)
+        endif()
+      endif()
+    else()
+      if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+        unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE)
+        unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
+      endif()
+      if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+        unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE CACHE)
+        unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG CACHE)
+      endif()
+      if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+        unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
+      endif()
+    endif()
+    if (("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+          AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+        OR ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+          AND NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+        OR ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS
+          AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR))
+      unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+      unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)
+    endif()
+  endif()
+endfunction()
+
+function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module)
+  string (TOUPPER "${module}" id)
+  if (${_PYTHON_PREFIX}_Development.${module}_FOUND)
+    set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:")
+    if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:")
+    endif()
+    if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}:")
+    endif()
+    if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS)
+      list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:")
+    endif()
+    string (MD5 signature "${signature}")
+    set (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE "${signature}" CACHE INTERNAL "")
+  else()
+    unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE)
+  endif()
+endfunction()
 
 unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
 unset (_${_PYTHON_PREFIX}_CACHED_VARS)
+unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE CACHE INTERNAL "Interpreter reason failure")
+unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE CACHE INTERNAL "Compiler reason failure")
+foreach (artifact IN LISTS _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+  unset (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE)
+  set (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE CACHE INTERNAL "Development ${artifact} reason failure")
+endforeach()
+unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE CACHE INTERNAL "Development reason failure")
+unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE)
+set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE CACHE INTERNAL "NumPy reason failure")
+
+
+# preamble
+## For IronPython on platforms other than Windows, search for the .Net interpreter
+if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+    AND NOT WIN32)
+  find_program (${_PYTHON_PREFIX}_DOTNET_LAUNCHER
+                NAMES "mono")
+endif()
 
 
 # first step, search for the interpreter
 if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_EXECUTABLE)
+  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE
+                                              _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
   if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE)
   endif()
 
-  set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+  if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_EXECUTABLE}")
+    if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE)
+      # invalidate cache properties
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+    endif()
+    set (_${_PYTHON_PREFIX}_EXECUTABLE "${${_PYTHON_PREFIX}_EXECUTABLE}" CACHE INTERNAL "")
+  elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE)
+    # compute interpreter signature and check validity of definition
+    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)
+        _python_validate_interpreter (IN_RANGE CHECK_EXISTS)
+      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+        _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+      else()
+        _python_validate_interpreter (CHECK_EXISTS)
+      endif()
+    else()
+      unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE)
+    endif()
+    if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+    endif()
+  endif()
 
-  # look-up for various versions and locations
-  foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-    string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
+  if (NOT _${_PYTHON_PREFIX}_EXECUTABLE)
+    set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
 
-    _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+    if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+      # build all executable names
+      _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX INTERPRETER)
+      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} INTERPRETER)
 
-    # Apple frameworks handling
-    if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                    NAMES_PER_DIR
-                    PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                    PATH_SUFFIXES bin
-                    NO_CMAKE_PATH
-                    NO_CMAKE_ENVIRONMENT_PATH
-                    NO_SYSTEM_ENVIRONMENT_PATH
-                    NO_CMAKE_SYSTEM_PATH)
-    endif()
+      # Framework Paths
+      _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+      # Registry Paths
+      _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
 
-    # Windows registry
-    if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                          python
-                          ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
-                    NAMES_PER_DIR
-                    HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                    PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                    PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                    NO_SYSTEM_ENVIRONMENT_PATH
-                    NO_CMAKE_SYSTEM_PATH)
-    endif()
+      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+      if (${_PYTHON_PREFIX}_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})
+      endif()
 
-    # try using HINTS
-    find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                  NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                        python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                        python
-                        ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
-                  NAMES_PER_DIR
-                  HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                  PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                  NO_SYSTEM_ENVIRONMENT_PATH
-                  NO_CMAKE_SYSTEM_PATH)
-    # try using standard paths.
-    if (WIN32)
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                          python
-                          ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
-                    NAMES_PER_DIR)
+      while (TRUE)
+        # Virtual environments handling
+        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+            break()
+          endif()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+        endif()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+        endif()
+
+        # try using HINTS
+        find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      NO_SYSTEM_ENVIRONMENT_PATH
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_interpreter)
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+        # try using standard paths
+        find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_interpreter)
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+        endif()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+        endif()
+
+        break()
+      endwhile()
     else()
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                    NAMES_PER_DIR)
-    endif()
+      # look-up for various versions and locations
+      set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
+      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+        list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
+      endif()
 
-    # Apple frameworks handling
-    if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                    NAMES_PER_DIR
-                    PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                    PATH_SUFFIXES bin
-                    NO_DEFAULT_PATH)
-    endif()
+      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+        _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX INTERPRETER)
+        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INTERPRETER)
 
-    # Windows registry
-    if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
-      find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                          python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                          python
-                          ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
-                    NAMES_PER_DIR
-                    PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-                          [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                    PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                    NO_DEFAULT_PATH)
-    endif()
+        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS})
 
-    _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION})
-    if (${_PYTHON_PREFIX}_EXECUTABLE)
-      break()
-    endif()
-  endforeach()
+        # Virtual environments handling
+        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+          if (_${_PYTHON_PREFIX}_EXECUTABLE)
+            break()
+          endif()
+          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+            continue()
+          endif()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+        endif()
+
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+        endif()
+
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+
+        # try using HINTS
+        find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      NO_SYSTEM_ENVIRONMENT_PATH
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_interpreter)
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+
+        # try using standard paths.
+        find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_interpreter)
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+        endif()
 
-  if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
-    # No specific version found. Retry with generic names
-    # try using HINTS
-    find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                  NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                        python
-                        ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
-                  NAMES_PER_DIR
-                  HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                  PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                  NO_SYSTEM_ENVIRONMENT_PATH
-                  NO_CMAKE_SYSTEM_PATH)
-    # try using standard paths.
-    # NAMES_PER_DIR is not defined on purpose to have a chance to find
-    # expected version.
-    # For example, typical systems have 'python' for version 2.* and 'python3'
-    # for version 3.*. So looking for names per dir will find, potentially,
-    # systematically 'python' (i.e. version 2) even if version 3 is searched.
-    find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                  NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                        python
-                        ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES})
-
-    _python_validate_interpreter ()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                        NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_interpreter)
+        endif()
+
+        if (_${_PYTHON_PREFIX}_EXECUTABLE)
+          break()
+        endif()
+      endforeach()
+
+      if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND
+          NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+        # No specific version found. Retry with generic names and standard paths.
+        _python_get_names (_${_PYTHON_PREFIX}_NAMES POSIX INTERPRETER)
+        unset (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS)
+        find_program (_${_PYTHON_PREFIX}_EXECUTABLE
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                      NAMES_PER_DIR
+                      VALIDATOR _python_validate_find_interpreter)
+      endif()
+    endif()
   endif()
 
+  set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}")
+  _python_get_launcher (_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER INTERPRETER)
+
   # retrieve exact version of executable found
-  if (${_PYTHON_PREFIX}_EXECUTABLE)
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+  if (_${_PYTHON_PREFIX}_EXECUTABLE)
+    execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
                              "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))"
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                      OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
+      set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE)
+    else()
+      # Interpreter is not usable
+      set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE)
+      unset (${_PYTHON_PREFIX}_VERSION)
+      set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"")
+    endif()
+  endif()
+
+  if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE)
+    list (LENGTH _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES _properties_length)
+    if (NOT _properties_length EQUAL "12")
+      # cache variable comes from some older Python module version: not usable
+      unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE)
+    endif()
+    unset (_properties_length)
+
+    if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES)
+      set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_SOSABI)
+
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDLIB)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_STDARCH)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITELIB)
+      list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 11 ${_PYTHON_PREFIX}_SITEARCH)
+    else()
       string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}")
       list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR)
       list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR)
       list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH)
-    else()
-      # Interpreter is not usable
-      set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
-      unset (${_PYTHON_PREFIX}_VERSION)
-    endif()
-  endif()
-
-  if (${_PYTHON_PREFIX}_EXECUTABLE
-      AND ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
-    set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
-    # Use interpreter version for future searches to ensure consistency
-    set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
-  endif()
 
-  if (${_PYTHON_PREFIX}_Interpreter_FOUND)
-    if (NOT CMAKE_SIZEOF_VOID_P)
-      # determine interpreter architecture
-      execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)"
-                       RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                       OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT
-                       ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)
-      if (NOT _${_PYTHON_PREFIX}_RESULT)
-        if (${_PYTHON_PREFIX}_IS64BIT)
-          set (_${_PYTHON_PREFIX}_ARCH 64)
-          set (_${_PYTHON_PREFIX}_ARCH2 64)
-        else()
-          set (_${_PYTHON_PREFIX}_ARCH 32)
-          set (_${_PYTHON_PREFIX}_ARCH2 32)
+      if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
+        set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE)
+
+        # Use interpreter version and ABI for future searches to ensure consistency
+        set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                                 "import sys; sys.stdout.write(sys.abiflags)"
+                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS
+                         ERROR_QUIET
+                         OUTPUT_STRIP_TRAILING_WHITESPACE)
+        if (_${_PYTHON_PREFIX}_RESULT)
+          # assunme ABI is not supported
+          set (_${_PYTHON_PREFIX}_ABIFLAGS "")
         endif()
       endif()
-    endif()
 
-    # retrieve interpreter identity
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -V
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID
-                     ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)
-    if (NOT _${_PYTHON_PREFIX}_RESULT)
-      if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda")
-        set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda")
-      elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought")
-        set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy")
-      else()
-        string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}")
-        if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python")
-          # try to get a more precise ID
-          execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.copyright)"
+      if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+        unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE CACHE)
+
+        # compute and save interpreter signature
+        string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}")
+        set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "")
+
+        if (NOT CMAKE_SIZEOF_VOID_P)
+          # determine interpreter architecture
+          execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                                   "import sys; sys.stdout.write(str(sys.maxsize > 2**32))"
                            RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                           OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT
-                           ERROR_QUIET)
-          if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState")
-            set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython")
+                           OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT
+                           ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT)
+          if (NOT _${_PYTHON_PREFIX}_RESULT)
+            if (${_PYTHON_PREFIX}_IS64BIT)
+              set (_${_PYTHON_PREFIX}_ARCH 64)
+            else()
+              set (_${_PYTHON_PREFIX}_ARCH 32)
+            endif()
+          endif()
+
+          if (WIN32)
+            # check if architecture is Intel or ARM
+            execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                                     "import sys; import sysconfig; sys.stdout.write(sysconfig.get_platform())"
+                             RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                             OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PLATFORM
+                             ERROR_VARIABLE ${_PYTHON_PREFIX}_PLATFORM)
+            if (NOT _${_PYTHON_PREFIX}_RESULT)
+              string(TOUPPER "${_${_PYTHON_PREFIX}_PLATFORM}" _${_PYTHON_PREFIX}_PLATFORM)
+              if (_${_PYTHON_PREFIX}_PLATFORM MATCHES "ARM")
+                if (${_PYTHON_PREFIX}_IS64BIT)
+                  set (_${_PYTHON_PREFIX}_ARCH ARM64)
+                else()
+                  set (_${_PYTHON_PREFIX}_ARCH ARM)
+                endif()
+              endif()
+            endif()
+          endif()
+        endif()
+
+        # retrieve interpreter identity
+        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V
+                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                         OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID
+                         ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID)
+        if (NOT _${_PYTHON_PREFIX}_RESULT)
+          if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda")
+            set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda")
+          elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought")
+            set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy")
+          elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "PyPy ([0-9.]+)")
+            set (${_PYTHON_PREFIX}_INTERPRETER_ID "PyPy")
+            set  (${_PYTHON_PREFIX}_PyPy_VERSION "${CMAKE_MATCH_1}")
+          else()
+            string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}")
+            if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python")
+              # try to get a more precise ID
+              execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                                       "import sys; sys.stdout.write(sys.copyright)"
+                               RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                               OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT
+                               ERROR_QUIET)
+              if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState")
+                set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython")
+              endif()
+            endif()
           endif()
+        else()
+          set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)
+        endif()
+
+        # retrieve various package installation directories
+        execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                                 "import sys\nif sys.version_info >= (3,10):\n   import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))\nelse:\n   from distutils import sysconfig\n   sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
+                         RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                         OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
+                         ERROR_QUIET)
+        if (NOT _${_PYTHON_PREFIX}_RESULT)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
+          list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)
+        else()
+          unset (${_PYTHON_PREFIX}_STDLIB)
+          unset (${_PYTHON_PREFIX}_STDARCH)
+          unset (${_PYTHON_PREFIX}_SITELIB)
+          unset (${_PYTHON_PREFIX}_SITEARCH)
         endif()
+
+        _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
+        _python_get_config_var (${_PYTHON_PREFIX}_SOSABI SOSABI)
+
+        # store properties in the cache to speed-up future searches
+        set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
+          "${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_SOSABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}" CACHE INTERNAL "${_PYTHON_PREFIX} Properties")
+      else()
+        unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE)
+        unset (${_PYTHON_PREFIX}_INTERPRETER_ID)
       endif()
-    else()
-      set (${_PYTHON_PREFIX}_INTERPRETER_ID Python)
     endif()
-  else()
-    unset (${_PYTHON_PREFIX}_INTERPRETER_ID)
   endif()
 
-  # retrieve various package installation directories
-  execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))"
-
-                   RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                   OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS
-                   ERROR_QUIET)
-  if (NOT _${_PYTHON_PREFIX}_RESULT)
-    list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB)
-    list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH)
-    list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB)
-    list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH)
-  else()
-    unset (${_PYTHON_PREFIX}_STDLIB)
-    unset (${_PYTHON_PREFIX}_STDARCH)
-    unset (${_PYTHON_PREFIX}_SITELIB)
-    unset (${_PYTHON_PREFIX}_SITEARCH)
+  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+    set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}" CACHE FILEPATH "${_PYTHON_PREFIX} Interpreter")
   endif()
 
-  mark_as_advanced (${_PYTHON_PREFIX}_EXECUTABLE)
+  _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE
+                            _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES
+                            _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE)
 endif()
 
 
 # second step, search for compiler (IronPython)
 if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
-  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_COMPILER)
+  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER)
   if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler)
     list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER)
   endif()
 
-  # IronPython specific artifacts
-  # If IronPython interpreter is found, use its path
-  unset (_${_PYTHON_PREFIX}_IRON_ROOT)
-  if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
-    get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY)
+  if (NOT "IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+    unset (_${_PYTHON_PREFIX}_COMPILER CACHE)
+    unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
+  elseif (DEFINED ${_PYTHON_PREFIX}_COMPILER
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_COMPILER}")
+    set (_${_PYTHON_PREFIX}_COMPILER "${${_PYTHON_PREFIX}_COMPILER}" CACHE INTERNAL "")
+  elseif (DEFINED _${_PYTHON_PREFIX}_COMPILER)
+    # compute compiler signature and check validity of definition
+    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)
+        _python_validate_compiler (IN_RANGE CHECK_EXISTS)
+      elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION)
+        _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS)
+      else()
+        _python_validate_compiler (CHECK_EXISTS)
+      endif()
+    else()
+      unset (_${_PYTHON_PREFIX}_COMPILER CACHE)
+      unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
+    endif()
   endif()
 
-  # try using root dir and registry
-  foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-    if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
-      find_program (${_PYTHON_PREFIX}_COMPILER
-                    NAMES ipyc
-                    HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
-                    PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                    NO_SYSTEM_ENVIRONMENT_PATH
-                    NO_CMAKE_SYSTEM_PATH)
+  if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS
+      AND NOT _${_PYTHON_PREFIX}_COMPILER)
+    # IronPython specific artifacts
+    # If IronPython interpreter is found, use its path
+    unset (_${_PYTHON_PREFIX}_IRON_ROOT)
+    if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
+      get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY)
     endif()
 
-    find_program (${_PYTHON_PREFIX}_COMPILER
-                  NAMES ipyc
-                  HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
-                  PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                  NO_SYSTEM_ENVIRONMENT_PATH
-                  NO_CMAKE_SYSTEM_PATH)
+    if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+      _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
+                         IMPLEMENTATIONS IronPython
+                         VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+                         COMPILER)
+
+      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+                                 IMPLEMENTATIONS IronPython
+                                 VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+                                 COMPILER)
+
+      _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS
+                              IMPLEMENTATIONS IronPython
+                              VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+      _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS
+                              IMPLEMENTATIONS IronPython
+                              VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+
+      set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT})
+      if (${_PYTHON_PREFIX}_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})
+      endif()
 
-    if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
-      find_program (${_PYTHON_PREFIX}_COMPILER
-                    NAMES ipyc
-                    PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}
-                    NO_DEFAULT_PATH)
-    endif()
+      while (TRUE)
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
 
-    _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION})
-    if (${_PYTHON_PREFIX}_COMPILER)
-      break()
+        # try using HINTS
+        find_program (_${_PYTHON_PREFIX}_COMPILER
+                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      NO_SYSTEM_ENVIRONMENT_PATH
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_compiler)
+        if (_${_PYTHON_PREFIX}_COMPILER)
+          break()
+        endif()
+
+        # try using standard paths
+        find_program (_${_PYTHON_PREFIX}_COMPILER
+                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                      NAMES_PER_DIR
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      VALIDATOR _python_validate_find_compiler)
+        if (_${_PYTHON_PREFIX}_COMPILER)
+          break()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+
+        break()
+      endwhile()
+    else()
+      # try using root dir and registry
+      set (_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS EXACT)
+      if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE)
+        list (APPEND _${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS IN_RANGE)
+      endif()
+
+      foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+        _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
+                           IMPLEMENTATIONS IronPython
+                           VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+                           COMPILER)
+
+        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+                                   IMPLEMENTATIONS IronPython
+                                   VERSION ${_${_PYTHON_PREFIX}_FIND_VERSION}
+                                   COMPILER)
+
+        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS
+                                IMPLEMENTATIONS IronPython
+                                VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS
+                                IMPLEMENTATIONS IronPython
+                                VERSION ${_${_PYTHON_PREFIX}_VERSION})
+
+        set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_COMMON_VALIDATE_OPTIONS})
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+
+        # try using HINTS
+        find_program (_${_PYTHON_PREFIX}_COMPILER
+                      NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      NO_SYSTEM_ENVIRONMENT_PATH
+                      NO_CMAKE_SYSTEM_PATH
+                      VALIDATOR _python_validate_find_compiler)
+        if (_${_PYTHON_PREFIX}_COMPILER)
+          break()
+        endif()
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+        # Windows registry
+        if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_COMPILER
+                        NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        ${_${_PYTHON_PREFIX}_REGISTRY_VIEW}
+                        NO_DEFAULT_PATH
+                        VALIDATOR _python_validate_find_compiler)
+          if (_${_PYTHON_PREFIX}_COMPILER)
+            break()
+          endif()
+        endif()
+      endforeach()
+
+      # no specific version found, re-try in standard paths
+      _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES
+                         IMPLEMENTATIONS IronPython
+                         VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+                         COMPILER)
+      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES
+                                 IMPLEMENTATIONS IronPython
+                                 VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}
+                                 COMPILER)
+      unset (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS)
+      find_program (_${_PYTHON_PREFIX}_COMPILER
+                    NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES}
+                    NAMES_PER_DIR
+                    HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
+                    PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                    VALIDATOR _python_validate_find_compiler)
     endif()
-  endforeach()
+  endif()
 
-  # no specific version found, re-try in standard paths
-  find_program (${_PYTHON_PREFIX}_COMPILER
-                NAMES ipyc
-                HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS}
-                PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
+  set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}")
 
-  if (${_PYTHON_PREFIX}_COMPILER)
+  if (_${_PYTHON_PREFIX}_COMPILER)
     # retrieve python environment version from compiler
+    _python_get_launcher (_${_PYTHON_PREFIX}_COMPILER_LAUNCHER COMPILER)
     set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir")
-    file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n")
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py"
+    file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]])); sys.stdout.flush()\n")
+    execute_process (COMMAND ${_${_PYTHON_PREFIX}_COMPILER_LAUNCHER} "${_${_PYTHON_PREFIX}_COMPILER}"
+                             ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS}
+                             /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py"
                      WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}"
                      OUTPUT_QUIET
                      ERROR_QUIET)
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_VERSION_DIR}/version"
+    get_filename_component (_${_PYTHON_PREFIX}_IR_DIR "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY)
+    execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${_${_PYTHON_PREFIX}_IR_DIR}"
+                             ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.exe"
                      WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}"
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                      OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION
                      ERROR_QUIET)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
+      set (_${_PYTHON_PREFIX}_COMPILER_USABLE TRUE)
       string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}")
       list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR)
       list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR)
@@ -631,47 +2577,124 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
       endif()
     else()
       # compiler not usable
-      set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE)
+      set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE)
+      set_property (CACHE _${_PYTHON_PREFIX}_Compiler_REASON_FAILURE PROPERTY VALUE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"")
     endif()
     file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
   endif()
 
-  if (${_PYTHON_PREFIX}_COMPILER)
+  if (_${_PYTHON_PREFIX}_COMPILER AND _${_PYTHON_PREFIX}_COMPILER_USABLE)
     if (${_PYTHON_PREFIX}_Interpreter_FOUND)
       # Compiler must be compatible with interpreter
-      if (${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR} VERSION_EQUAL ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+      if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}")
         set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)
       endif()
     elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
       set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE)
-    # Use compiler version for future searches to ensure consistency
-    set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
+      # Use compiler version for future searches to ensure consistency
+      set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
     endif()
   endif()
 
   if (${_PYTHON_PREFIX}_Compiler_FOUND)
+    unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE CACHE)
+
+    # compute and save compiler signature
+    string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}")
+    set (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${__${_PYTHON_PREFIX}_COMPILER_SIGNATURE}" CACHE INTERNAL "")
+
     set (${_PYTHON_PREFIX}_COMPILER_ID IronPython)
   else()
+    unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE)
     unset (${_PYTHON_PREFIX}_COMPILER_ID)
   endif()
 
-  mark_as_advanced (${_PYTHON_PREFIX}_COMPILER)
-endif()
+  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+    set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}" CACHE FILEPATH "${_PYTHON_PREFIX} Compiler")
+  endif()
 
+  _python_mark_as_internal (_${_PYTHON_PREFIX}_COMPILER
+                            _${_PYTHON_PREFIX}_COMPILER_SIGNATURE)
+endif()
 
 # third step, search for the development artifacts
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module)
+  if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
+  endif()
+  if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
+  endif()
+endif()
+if (${_PYTHON_PREFIX}_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()
+  if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
+  endif()
+endif()
+if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed)
+  if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES)
+  endif()
+  if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS)
+  endif()
+endif()
+list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS)
 ## Development environment is not compatible with IronPython interpreter
-if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-    AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
-  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_LIBRARY
-                                              ${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                                              ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
-                                              ${_PYTHON_PREFIX}_LIBRARY_DEBUG
-                                              ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
-                                              ${_PYTHON_PREFIX}_INCLUDE_DIR)
-  if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development)
-    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARY
-                                                  ${_PYTHON_PREFIX}_INCLUDE_DIR)
+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)
+    AND ((${_PYTHON_PREFIX}_Interpreter_FOUND
+        AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython")
+      OR NOT ${_PYTHON_PREFIX}_Interpreter_FOUND))
+  if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+    # reduce possible implementations to the interpreter one
+    if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "PyPy")
+      set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "PyPy")
+    else()
+      set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "CPython")
+    endif()
+  else()
+    list (REMOVE_ITEM _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "IronPython")
+  endif()
+  if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                                              _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+                                              _${_PYTHON_PREFIX}_LIBRARY_DEBUG
+                                              _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+  endif()
+  if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                                              _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+                                              _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+                                              _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG)
+  endif()
+  if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_INCLUDE_DIR)
+  endif()
+
+  _python_check_development_signature (Module)
+  _python_check_development_signature (SABIModule)
+  _python_check_development_signature (Embed)
+
+  if (DEFINED ${_PYTHON_PREFIX}_LIBRARY
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_LIBRARY}")
+    set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_LIBRARY}" CACHE INTERNAL "")
+    unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE)
+    unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
+  endif()
+  if (DEFINED ${_PYTHON_PREFIX}_SABI_LIBRARY
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_SABI_LIBRARY}")
+    set (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_SABI_LIBRARY}" CACHE INTERNAL "")
+    unset (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG CACHE)
+    unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE)
+  endif()
+  if (DEFINED ${_PYTHON_PREFIX}_INCLUDE_DIR
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
+    set (_${_PYTHON_PREFIX}_INCLUDE_DIR "${${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE INTERNAL "")
   endif()
 
   # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
@@ -683,345 +2706,804 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
     else()
       list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX})
     endif()
-  else()
   endif()
 
-  # if python interpreter is found, use its location and version to ensure consistency
-  # between interpreter and development environment
-  unset (_${_PYTHON_PREFIX}_PREFIX)
-  if (${_PYTHON_PREFIX}_Interpreter_FOUND)
-    execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                             "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.PREFIX)"
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX
-                     ERROR_QUIET
-                     OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (_${_PYTHON_PREFIX}_RESULT)
-      unset (_${_PYTHON_PREFIX}_PREFIX)
+  if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+      OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+    # if python interpreter is found, use it to look-up for artifacts
+    # to ensure consistency between interpreter and development environments.
+    # If not, try to locate a compatible config tool
+    if ((NOT ${_PYTHON_PREFIX}_Interpreter_FOUND OR CMAKE_CROSSCOMPILING)
+        AND "CPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+      set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+      unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+      if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+        set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+      endif()
+
+      if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+        _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX CONFIG)
+          # Framework Paths
+        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS})
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+          find_program (_${_PYTHON_PREFIX}_CONFIG
+                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                              ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES bin
+                        NO_CMAKE_PATH
+                        NO_CMAKE_ENVIRONMENT_PATH
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH)
+        endif()
+
+        find_program (_${_PYTHON_PREFIX}_CONFIG
+                      NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                      PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                      PATH_SUFFIXES bin)
+
+        # Apple frameworks handling
+        if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          find_program (_${_PYTHON_PREFIX}_CONFIG
+                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                        PATH_SUFFIXES bin
+                        NO_DEFAULT_PATH)
+        endif()
+
+        _python_get_launcher (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER CONFIG "${_${_PYTHON_PREFIX}_CONFIG}")
+
+        if (_${_PYTHON_PREFIX}_CONFIG)
+          execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --prefix
+                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP
+                           ERROR_VARIABLE __${_PYTHON_PREFIX}_HELP
+                           OUTPUT_STRIP_TRAILING_WHITESPACE)
+          if (_${_PYTHON_PREFIX}_RESULT)
+            # assume config tool is not usable
+            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+            unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+          endif()
+        endif()
+
+        if (_${_PYTHON_PREFIX}_CONFIG)
+          execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --abiflags
+                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS
+                           ERROR_QUIET
+                           OUTPUT_STRIP_TRAILING_WHITESPACE)
+          if (_${_PYTHON_PREFIX}_RESULT)
+            # assume ABI is not supported
+            set (__${_PYTHON_PREFIX}_ABIFLAGS "")
+          endif()
+          if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+            # Wrong ABI
+            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+            unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+          endif()
+        endif()
+
+        if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+          # check that config tool match library architecture
+          execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --configdir
+                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                           OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+                           ERROR_QUIET
+                           OUTPUT_STRIP_TRAILING_WHITESPACE)
+          if (_${_PYTHON_PREFIX}_RESULT)
+            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+            unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+          else()
+            string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+            if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+              unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+            endif()
+          endif()
+        endif()
+      else()
+        foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+          # try to use pythonX.Y-config tool
+          _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG)
+
+          # Framework Paths
+          _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+
+          # Apple frameworks handling
+          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+            find_program (_${_PYTHON_PREFIX}_CONFIG
+                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                          PATH_SUFFIXES bin
+                          NO_CMAKE_PATH
+                          NO_CMAKE_ENVIRONMENT_PATH
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+          endif()
+
+          find_program (_${_PYTHON_PREFIX}_CONFIG
+                        NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                        PATH_SUFFIXES bin)
+
+          # Apple frameworks handling
+          if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+            find_program (_${_PYTHON_PREFIX}_CONFIG
+                          NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
+                          NAMES_PER_DIR
+                          PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                          PATH_SUFFIXES bin
+                          NO_DEFAULT_PATH)
+          endif()
+
+          unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
+
+          _python_get_launcher (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER CONFIG "${_${_PYTHON_PREFIX}_CONFIG}")
+
+          if (_${_PYTHON_PREFIX}_CONFIG)
+            execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --prefix
+                             RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                             OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP
+                             ERROR_QUIET
+                             OUTPUT_STRIP_TRAILING_WHITESPACE)
+            if (_${_PYTHON_PREFIX}_RESULT)
+              # assume config tool is not usable
+              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+              unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+            endif()
+          endif()
+
+          if (NOT _${_PYTHON_PREFIX}_CONFIG)
+            continue()
+          endif()
+
+          execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --abiflags
+                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                           OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS
+                           ERROR_QUIET
+                           OUTPUT_STRIP_TRAILING_WHITESPACE)
+          if (_${_PYTHON_PREFIX}_RESULT)
+            # assume ABI is not supported
+            set (__${_PYTHON_PREFIX}_ABIFLAGS "")
+          endif()
+          if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)
+            # Wrong ABI
+            unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+            unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+            continue()
+          endif()
+
+          if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+            # check that config tool match library architecture
+            execute_process (COMMAND ${_${_PYTHON_PREFIX}_CONFIG_LAUNCHER} --configdir
+                             RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                             OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
+                             ERROR_QUIET
+                             OUTPUT_STRIP_TRAILING_WHITESPACE)
+            if (_${_PYTHON_PREFIX}_RESULT)
+              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+              unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+              continue()
+            endif()
+            string (FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
+            if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
+              unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+              unset (_${_PYTHON_PREFIX}_CONFIG_LAUNCHER)
+              continue()
+            endif()
+          endif()
+
+          if (_${_PYTHON_PREFIX}_CONFIG)
+            break()
+          endif()
+        endforeach()
+      endif()
     endif()
   endif()
-  set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
 
-  foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-    string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
+  if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)
+        # retrieve root install directory
+        _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX)
 
-    # try to use pythonX.Y-config tool
-    set (_${_PYTHON_PREFIX}_CONFIG_NAMES)
-    if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
-      set (_${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config")
-    endif()
-    list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config")
-    find_program (_${_PYTHON_PREFIX}_CONFIG
-                  NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
-                  NAMES_PER_DIR
-                  HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                  PATH_SUFFIXES bin)
-    unset (_${_PYTHON_PREFIX}_CONFIG_NAMES)
+        # enforce current ABI
+        _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS)
 
-    if (NOT _${_PYTHON_PREFIX}_CONFIG)
-      continue()
-    endif()
-    if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
-      # check that config tool match library architecture
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
-                       RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                       OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
-                       ERROR_QUIET
-                       OUTPUT_STRIP_TRAILING_WHITESPACE)
-      if (_${_PYTHON_PREFIX}_RESULT)
-        unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
-        continue()
+        set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+
+        # retrieve library
+        ## compute some paths and artifact names
+        if (_${_PYTHON_PREFIX}_CONFIG)
+          string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_CONFIG}")
+        else()
+          set (_${_PYTHON_PREFIX}_VERSION "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}")
+        endif()
+        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY)
+        _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)
+
+        _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR)
+        list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
+
+        list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+        find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                      NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                      NAMES_PER_DIR
+                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                      PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                      NO_SYSTEM_ENVIRONMENT_PATH
+                      NO_CMAKE_SYSTEM_PATH)
+      endif()
+
+      # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts
+      if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+        set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+        unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+        endif()
+
+        if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+          # library names
+          _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 POSIX LIBRARY)
+          _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 DEBUG)
+          # Paths suffixes
+          _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} LIBRARY)
+
+          # Framework Paths
+          _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_FIND_VERSIONS})
+          # Registry Paths
+          _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} )
+
+          if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                          NO_CMAKE_PATH
+                          NO_CMAKE_ENVIRONMENT_PATH
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+          endif()
+
+          if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+          endif()
+
+          # search in HINTS locations
+          find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                        NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                        NAMES_PER_DIR
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH)
+
+          if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+            set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+          else()
+            unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+          endif()
+
+          if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+            set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+          else()
+            unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+          endif()
+
+          # search in all default paths
+          find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                        NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                        NAMES_PER_DIR
+                        PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                              ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+        else()
+          foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+            _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY)
+            _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG)
+
+            _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+            _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+
+            _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+
+            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+              find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                  ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                            NO_CMAKE_PATH
+                            NO_CMAKE_ENVIRONMENT_PATH
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+            endif()
+
+            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+              find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                  ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+            endif()
+
+            # search in HINTS locations
+            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                          NAMES_PER_DIR
+                          HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                          NO_SYSTEM_ENVIRONMENT_PATH
+                          NO_CMAKE_SYSTEM_PATH)
+
+            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+              set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+            else()
+              unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+            endif()
+
+            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+              set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+            else()
+              unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+            endif()
+
+            # search in all default paths
+            find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                          NAMES_PER_DIR
+                          PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                                ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+
+            if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+              break()
+            endif()
+          endforeach()
+        endif()
       endif()
-      string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT)
-      if (_${_PYTHON_PREFIX}_RESULT EQUAL -1)
-        unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
-        continue()
+    endif()
+
+    # finalize library version information
+    _python_get_version (LIBRARY PREFIX _${_PYTHON_PREFIX}_)
+    if (_${_PYTHON_PREFIX}_VERSION EQUAL "${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}")
+      # not able to extract full version from library name
+      if (${_PYTHON_PREFIX}_Interpreter_FOUND)
+        # update from interpreter
+        set (_${_PYTHON_PREFIX}_VERSION ${${_PYTHON_PREFIX}_VERSION})
+        set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${${_PYTHON_PREFIX}_VERSION_MAJOR})
+        set (_${_PYTHON_PREFIX}_VERSION_MINOR ${${_PYTHON_PREFIX}_VERSION_MINOR})
+        set (_${_PYTHON_PREFIX}_VERSION_PATCH ${${_PYTHON_PREFIX}_VERSION_PATCH})
       endif()
     endif()
 
-    # retrieve root install directory
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --prefix
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX
-                     ERROR_QUIET
-                     OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (_${_PYTHON_PREFIX}_RESULT)
-      # python-config is not usable
-      unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
-      continue()
+    set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+
+    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND")
+    else()
+      unset (_${_PYTHON_PREFIX}_Development_LIBRARY_REASON_FAILURE CACHE)
     endif()
-    set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
 
-    # retrieve library
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
-                     ERROR_QUIET
-                     OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (NOT _${_PYTHON_PREFIX}_RESULT)
-      # retrieve library directory
-      string (REGEX MATCHALL "-L[^ ]+" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_FLAGS}")
-      string (REPLACE "-L" "" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_LIB_DIRS}")
-      list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_DIRS)
-      # retrieve library name
-      string (REGEX MATCHALL "-lpython[^ ]+" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_FLAGS}")
-      string (REPLACE "-l" "" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_LIB_NAMES}")
-      list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_NAMES)
-
-      find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+    set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+    if (WIN32 AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      # search for debug library
+      # use release library location as a hint
+      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+      find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG
+                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+                    NAMES_PER_DIR
+                    HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+                    NO_DEFAULT_PATH)
+      # second try including CMAKE variables to catch-up non conventional layouts
+      find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG
+                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
                     NAMES_PER_DIR
-                    HINTS ${_${_PYTHON_PREFIX}_HINTS} ${_${_PYTHON_PREFIX}_LIB_DIRS}
-                    PATH_SUFFIXES lib
                     NO_SYSTEM_ENVIRONMENT_PATH
                     NO_CMAKE_SYSTEM_PATH)
-      # retrieve runtime library
-      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
-        get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
-        get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
-        _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
-                                      NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
-                                      NAMES_PER_DIR
-                                      HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
-                                      PATH_SUFFIXES bin
-                                      NO_SYSTEM_ENVIRONMENT_PATH
-                                      NO_CMAKE_SYSTEM_PATH)
-      endif()
-    endif()
-
-    # retrieve include directory
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --includes
-                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
-                     ERROR_QUIET
-                     OUTPUT_STRIP_TRAILING_WHITESPACE)
-    if (NOT _${_PYTHON_PREFIX}_RESULT)
-      # retrieve include directory
-      string (REGEX MATCHALL "-I[^ ]+" _${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_FLAGS}")
-      string (REPLACE "-I" "" _${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIRS}")
-      list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_DIRS)
-
-      find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
-                 NAMES Python.h
-                 HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS}
-                 NO_SYSTEM_ENVIRONMENT_PATH
-                 NO_CMAKE_SYSTEM_PATH)
     endif()
 
-    if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_INCLUDE_DIR)
-      break()
+    # retrieve runtime libraries
+    if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                                    NAMES_PER_DIR
+                                    HINTS "${_${_PYTHON_PREFIX}_PATH}"
+                                          "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+                                    PATH_SUFFIXES bin)
     endif()
-  endforeach()
+    if (_${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+                                    NAMES_PER_DIR
+                                    HINTS "${_${_PYTHON_PREFIX}_PATH}"
+                                          "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+                                    PATH_SUFFIXES bin)
+    endif()
+  endif()
 
-  # Rely on HINTS and standard paths if config tool failed to locate artifacts
-  if (NOT (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) OR NOT ${_PYTHON_PREFIX}_INCLUDE_DIR)
-    foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-      string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION})
-
-      _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
-
-      set (_${_PYTHON_PREFIX}_REGISTRY_PATHS
-        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]
-        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath]
-        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]
-        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath])
-
-      if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
-        find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                      NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
-                            python${_${_PYTHON_PREFIX}_VERSION}mu
-                            python${_${_PYTHON_PREFIX}_VERSION}m
-                            python${_${_PYTHON_PREFIX}_VERSION}u
-                            python${_${_PYTHON_PREFIX}_VERSION}
-                      NAMES_PER_DIR
-                      PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                      PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config
-                      NO_CMAKE_PATH
-                      NO_CMAKE_ENVIRONMENT_PATH
-                      NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-      endif()
+  if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+      ## compute artifact names
+      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} WIN32 POSIX LIBRARY)
+      _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} WIN32 DEBUG)
 
-      if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
-        find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                      NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
-                            python${_${_PYTHON_PREFIX}_VERSION}mu
-                            python${_${_PYTHON_PREFIX}_VERSION}m
-                            python${_${_PYTHON_PREFIX}_VERSION}u
-                            python${_${_PYTHON_PREFIX}_VERSION}
-                      NAMES_PER_DIR
-                      HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                      PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                      PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
-                                    lib/python${_${_PYTHON_PREFIX}_VERSION}/config
-                      NO_SYSTEM_ENVIRONMENT_PATH
-                      NO_CMAKE_SYSTEM_PATH)
-      endif()
+      if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+          AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+        # SABI_LIBRARY_RELEASE search is based on LIBRARY_RELEASE
+        set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
 
-      # search in HINTS locations
-      find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
-                          python${_${_PYTHON_PREFIX}_VERSION}mu
-                          python${_${_PYTHON_PREFIX}_VERSION}m
-                          python${_${_PYTHON_PREFIX}_VERSION}u
-                          python${_${_PYTHON_PREFIX}_VERSION}
-                    NAMES_PER_DIR
-                    HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                    PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config
-                    NO_SYSTEM_ENVIRONMENT_PATH
-                    NO_CMAKE_SYSTEM_PATH)
+        get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
 
-      if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
-        set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+        find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+          HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+          NO_DEFAULT_PATH)
       else()
-        unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
-      endif()
+        if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)
+          # retrieve root install directory
+          _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX)
 
-      if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
-        set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
-      else()
-        unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
-      endif()
+          # enforce current ABI
+          _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS)
 
-      # search in all default paths
-      find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE
-                    NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
-                          python${_${_PYTHON_PREFIX}_VERSION}mu
-                          python${_${_PYTHON_PREFIX}_VERSION}m
-                          python${_${_PYTHON_PREFIX}_VERSION}u
-                          python${_${_PYTHON_PREFIX}_VERSION}
-                    NAMES_PER_DIR
-                    PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                          ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                    PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}
-                                  lib/python${_${_PYTHON_PREFIX}_VERSION}/config)
-      # retrieve runtime library
-      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
-        get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
-        get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
-        _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
-                                      NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}
-                                            python${_${_PYTHON_PREFIX}_VERSION}mu
-                                            python${_${_PYTHON_PREFIX}_VERSION}m
-                                            python${_${_PYTHON_PREFIX}_VERSION}u
-                                            python${_${_PYTHON_PREFIX}_VERSION}
-                                      NAMES_PER_DIR
-                                      HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
-                                      PATH_SUFFIXES bin)
-      endif()
+          set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
 
-      if (WIN32)
-        # search for debug library
-        if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
-          # use library location as a hint
-          get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
-          find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
-                        NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
+          # retrieve SABI library
+          ## compute some paths
+          if (_${_PYTHON_PREFIX}_CONFIG)
+            string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_CONFIG}")
+          else()
+            set (_${_PYTHON_PREFIX}_VERSION "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}")
+          endif()
+          _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY)
+
+          _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR)
+          list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
+
+          list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+          find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                        NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
                         NAMES_PER_DIR
-                        HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
-                        NO_DEFAULT_PATH)
-        else()
-          # search first in known locations
-          if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
-            find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
-                          NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
+                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                        PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                        NO_SYSTEM_ENVIRONMENT_PATH
+                        NO_CMAKE_SYSTEM_PATH)
+        endif()
+
+        # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts
+        if (NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+          set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+
+          unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+          if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+            set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+          endif()
+
+          if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
+            # Paths suffixes
+            _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} LIBRARY)
+
+            # Framework Paths
+            _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_FIND_VERSIONS})
+            # Registry Paths
+            _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} )
+
+            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+              find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                  ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                            NO_CMAKE_PATH
+                            NO_CMAKE_ENVIRONMENT_PATH
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+            endif()
+
+            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+              find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                  ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+            endif()
+
+            # search in HINTS locations
+            find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
                           NAMES_PER_DIR
                           HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                          PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                          PATH_SUFFIXES lib libs
+                          PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                           NO_SYSTEM_ENVIRONMENT_PATH
                           NO_CMAKE_SYSTEM_PATH)
+
+            if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+              set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+            else()
+              unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+            endif()
+
+            if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+              set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+            else()
+              unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+            endif()
+
+            # search in all default paths
+            find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                          NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                          NAMES_PER_DIR
+                          PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                                ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                          PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+          else()
+            foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
+              _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+              _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION})
+
+              _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+
+              if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
+                find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                              NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                              NAMES_PER_DIR
+                              HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                              PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                    ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                              PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                              NO_CMAKE_PATH
+                              NO_CMAKE_ENVIRONMENT_PATH
+                              NO_SYSTEM_ENVIRONMENT_PATH
+                              NO_CMAKE_SYSTEM_PATH)
+              endif()
+
+              if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
+                find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                              NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                              NAMES_PER_DIR
+                              HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                              PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                                    ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                              PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                              NO_SYSTEM_ENVIRONMENT_PATH
+                              NO_CMAKE_SYSTEM_PATH)
+              endif()
+
+              # search in HINTS locations
+              find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            HINTS ${_${_PYTHON_PREFIX}_HINTS}
+                            PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
+                            NO_SYSTEM_ENVIRONMENT_PATH
+                            NO_CMAKE_SYSTEM_PATH)
+
+              if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+                set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+              else()
+                unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+              endif()
+
+              if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+                set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+              else()
+                unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+              endif()
+
+              # search in all default paths
+              find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                            NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                            NAMES_PER_DIR
+                            PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                                  ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                            PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES})
+
+              if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+                break()
+              endif()
+            endforeach()
           endif()
-          # search in all default paths
-          find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG
-                        NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
-                        NAMES_PER_DIR
-                        HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                        PATHS ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                        PATH_SUFFIXES lib libs)
         endif()
-        if (${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-          get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY)
-          get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
-          _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
-                                        NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d
-                                        NAMES_PER_DIR
-                                        HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
-                                        PATH_SUFFIXES bin)
+      endif()
+    endif()
+
+    # finalize library version information
+    _python_get_version (SABI_LIBRARY PREFIX _${_PYTHON_PREFIX}_)
+    # ABI library does not have the full version information
+    if (${_PYTHON_PREFIX}_Interpreter_FOUND OR _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+      # update from interpreter or library
+      set (_${_PYTHON_PREFIX}_VERSION ${${_PYTHON_PREFIX}_VERSION})
+      set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${${_PYTHON_PREFIX}_VERSION_MAJOR})
+      set (_${_PYTHON_PREFIX}_VERSION_MINOR ${${_PYTHON_PREFIX}_VERSION_MINOR})
+      set (_${_PYTHON_PREFIX}_VERSION_PATCH ${${_PYTHON_PREFIX}_VERSION_PATCH})
+    endif()
+
+    set (${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+
+    if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}")
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE PROPERTY VALUE "Cannot find the library \"${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE-NOTFOUND")
+    else()
+      unset (_${_PYTHON_PREFIX}_Development_SABI_LIBRARY_REASON_FAILURE CACHE)
+    endif()
+
+    if (WIN32 AND _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+      # search for debug library
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+      find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+                    NAMES_PER_DIR
+                    HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS}
+                    NO_DEFAULT_PATH)
+      # second try including CMAKE variables to catch-up non conventional layouts
+      find_library (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+                    NAMES_PER_DIR
+                    NO_SYSTEM_ENVIRONMENT_PATH
+                    NO_CMAKE_SYSTEM_PATH)
+    endif()
+
+    # retrieve runtime libraries
+    if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES}
+                                    NAMES_PER_DIR
+                                    HINTS "${_${_PYTHON_PREFIX}_PATH}"
+                                          "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+                                    PATH_SUFFIXES bin)
+    endif()
+
+    if (_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG}" DIRECTORY)
+      get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY)
+      _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG
+                                    NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG}
+                                    NAMES_PER_DIR
+                                    HINTS "${_${_PYTHON_PREFIX}_PATH}"
+                                          "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS}
+                                    PATH_SUFFIXES bin)
+    endif()
+  endif()
+
+  if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+      set (_${_PYTHON_PREFIX}_LIBRARY_REQUIRED FALSE)
+      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
+            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
+            AND "SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${_${_PYTHON_PREFIX}_ID}_ARTIFACTS)
+          set (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED TRUE)
         endif()
+      endforeach()
+      if ((_${_PYTHON_PREFIX}_LIBRARY_REQUIRED
+          AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+        AND (_${_PYTHON_PREFIX}_SABI_LIBRARY_REQUIRED
+          AND NOT _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE))
+        # Don't search for include dir if no library was founded
+        break()
+      endif()
+
+      if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG)
+        _python_get_config_var (_${_PYTHON_PREFIX}_INCLUDE_DIRS INCLUDES)
+
+        find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+                   NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+                   HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS}
+                   NO_SYSTEM_ENVIRONMENT_PATH
+                   NO_CMAKE_SYSTEM_PATH)
       endif()
 
-      # Don't search for include dir until library location is known
-      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+      # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts
+      if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)
+        unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS)
+        if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+          set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX)
+        endif()
         unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS)
 
-        if (${_PYTHON_PREFIX}_EXECUTABLE)
-          # pick up include directory from configuration
-          execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-                                   "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('include'))"
-                           RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                           OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PATH
-                           ERROR_QUIET
-                           OUTPUT_STRIP_TRAILING_WHITESPACE)
-           if (NOT _${_PYTHON_PREFIX}_RESULT)
-             file (TO_CMAKE_PATH "${_${_PYTHON_PREFIX}_PATH}" _${_PYTHON_PREFIX}_PATH)
-             list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PATH}")
-           endif()
-        endif()
-
-        foreach (_${_PYTHON_PREFIX}_LIB IN ITEMS ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-          if (${_${_PYTHON_PREFIX}_LIB})
-            # Use the library's install prefix as a hint
-            if (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
-              list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
-            elseif (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
-              list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
-            elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
-              list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
-            else()
-              # assume library is in a directory under root
-              get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${${_${_PYTHON_PREFIX}_LIB}}" DIRECTORY)
-              get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
-              list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
-            endif()
+        if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+            AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+          # Use the library's install prefix as a hint
+          if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIBRARY_RELEASE} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          else()
+            # assume library is in a directory under root
+            get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY)
+            get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
           endif()
-        endforeach()
-        list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_HINTS)
+        elseif ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+            AND _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE)
+          # Use the library's install prefix as a hint
+          if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          elseif (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}")
+          else()
+            # assume library is in a directory under root
+            get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" DIRECTORY)
+            get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY)
+            list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+          endif()
+        endif()
+
+        _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION})
+        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INCLUDE)
 
         if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
-          find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
-                     NAMES Python.h
-                     HINTS ${_${_PYTHON_PREFIX}_HINTS}
-                     PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
-                     PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}m
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}u
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}
-                                   include
+          find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+                     NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
+                     HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
+                     PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                           ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                     PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                      NO_CMAKE_PATH
                      NO_CMAKE_ENVIRONMENT_PATH
                      NO_SYSTEM_ENVIRONMENT_PATH
@@ -1029,159 +3511,361 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
         endif()
 
         if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST")
-          find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
-                     NAMES Python.h
+          find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+                     NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
                      HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
-                     PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                     PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}m
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}u
-                                   include/python${_${_PYTHON_PREFIX}_VERSION}
-                                   include
+                     PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                           ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}
+                     PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                      NO_SYSTEM_ENVIRONMENT_PATH
                      NO_CMAKE_SYSTEM_PATH)
         endif()
 
-        find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
-                   NAMES Python.h
+        if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST")
+          set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS})
+        else()
+          unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS)
+        endif()
+
+        if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST")
+          set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS})
+        else()
+          unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS)
+        endif()
+
+        find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+                   NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}
                    HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS}
-                   PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
+                   PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS}
+                         ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS}
                          ${__${_PYTHON_PREFIX}_REGISTRY_PATHS}
-                   PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu
-                                 include/python${_${_PYTHON_PREFIX}_VERSION}m
-                                 include/python${_${_PYTHON_PREFIX}_VERSION}u
-                                 include/python${_${_PYTHON_PREFIX}_VERSION}
-                                 include
+                   PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}
                    NO_SYSTEM_ENVIRONMENT_PATH
                    NO_CMAKE_SYSTEM_PATH)
       endif()
 
-      if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) AND ${_PYTHON_PREFIX}_INCLUDE_DIR)
-        break()
-      endif()
-    endforeach()
+      # search header file in standard locations
+      find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR
+                 NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES})
 
-    # search header file in standard locations
-    find_path (${_PYTHON_PREFIX}_INCLUDE_DIR
-               NAMES Python.h)
-  endif()
+      break()
+    endwhile()
 
-  if (${_PYTHON_PREFIX}_INCLUDE_DIR)
-    # retrieve version from header file
-    file (STRINGS "${${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" _${_PYTHON_PREFIX}_VERSION
-          REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
-    string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
-                          _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_VERSION}")
-    string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}")
-    list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR)
-    list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR)
-    list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH)
+    set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
 
-    if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND)
-      # set public version information
-      set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})
-      set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})
-      set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})
-      set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})
+    if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}")
+      set_property (CACHE _${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"")
+      set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND")
+    else()
+      unset (_${_PYTHON_PREFIX}_Development_INCLUDE_DIR_REASON_FAILURE CACHE)
+    endif()
+
+    if (_${_PYTHON_PREFIX}_INCLUDE_DIR)
+      # retrieve version from header file
+      _python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_)
+      if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS
+          AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE)
+        if ("${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}"
+            VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION)
+          # update versioning
+          set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})
+          set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})
+        elseif (_${_PYTHON_PREFIX}_VERSION VERSION_EQUAL _${_PYTHON_PREFIX}_INC_VERSION_MAJOR)
+          # library specify only major version, use include file for full version information
+          set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})
+          set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR})
+          set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})
+        endif()
+      else()
+        set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION})
+        set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR})
+        set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR})
+        set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH})
+      endif()
     endif()
   endif()
 
-  # define public variables
-  include (SelectLibraryConfigurations)
-  select_library_configurations (${_PYTHON_PREFIX})
-  if (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
-    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
-  elseif (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
-    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
-  else()
-    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "$${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND")
+  if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND)
+    # set public version information
+    set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION})
+    set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR})
+    set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR})
+    set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH})
   endif()
 
-  _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS
-                            ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-  if (UNIX)
-    if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
-        OR ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
-      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})
+  # define public variables
+  if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    set (${_PYTHON_PREFIX}_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+    _python_select_library_configurations (${_PYTHON_PREFIX})
+
+    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+    set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+
+    if (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
+      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
+    elseif (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+    else()
+      set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND")
     endif()
-  else()
+
+    _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS
+                              _${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                              _${_PYTHON_PREFIX}_LIBRARY_DEBUG)
+    if (UNIX)
+      if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+        set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})
+      endif()
+    else()
       _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS
-                                ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+                                _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+                                _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
+    endif()
   endif()
 
-  set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
+  if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+    set (${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG}")
+    _python_select_library_configurations (${_PYTHON_PREFIX}_SABI)
+
+    set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE}")
+    set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG}")
+
+    if (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE)
+      set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE}")
+    elseif (_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG)
+      set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG}")
+    else()
+      set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY-NOTFOUND")
+    endif()
 
-  mark_as_advanced (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
-                    ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
-                    ${_PYTHON_PREFIX}_INCLUDE_DIR)
+    _python_set_library_dirs (${_PYTHON_PREFIX}_SABI_LIBRARY_DIRS
+                              _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                              _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG)
+    if (UNIX)
+      if (_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+        set (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS})
+      endif()
+    else()
+      _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DIRS
+                                _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+                                _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG)
+    endif()
+  endif()
 
-  if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-      AND ${_PYTHON_PREFIX}_INCLUDE_DIR)
+  if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR)
     if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND)
       # development environment must be compatible with interpreter/compiler
-      if (${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR} VERSION_EQUAL ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR})
-        set (${_PYTHON_PREFIX}_Development_FOUND TRUE)
+      if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}"
+          AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}")
+        _python_set_development_module_found (Module)
+        _python_set_development_module_found (SABIModule)
+        _python_set_development_module_found (Embed)
       endif()
-    elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
-      set (${_PYTHON_PREFIX}_Development_FOUND TRUE)
+    elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR
+        AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}")
+      _python_set_development_module_found (Module)
+      _python_set_development_module_found (SABIModule)
+      _python_set_development_module_found (Embed)
     endif()
+    if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND
+        (NOT _${_PYTHON_PREFIX}_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS
+          OR NOT _${_PYTHON_PREFIX}_INC_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS))
+      set (${_PYTHON_PREFIX}_Development.Module_FOUND FALSE)
+      set (${_PYTHON_PREFIX}_Development.SABIModule_FOUND FALSE)
+      set (${_PYTHON_PREFIX}_Development.Embed_FOUND FALSE)
+    endif()
+  endif()
+
+  if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+      AND ${_PYTHON_PREFIX}_Development.Module_FOUND
+      AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+    set (${_PYTHON_PREFIX}_Development_FOUND TRUE)
+  endif()
+
+  if ((${_PYTHON_PREFIX}_Development.Module_FOUND
+        OR ${_PYTHON_PREFIX}_Development.SABIModule_FOUND
+        OR ${_PYTHON_PREFIX}_Development.Embed_FOUND)
+      AND EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/PyPy.h")
+    # retrieve PyPy version
+    file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" ${_PYTHON_PREFIX}_PyPy_VERSION
+          REGEX "^#define[ \t]+PYPY_VERSION[ \t]+\"[^\"]+\"")
+    string (REGEX REPLACE "^#define[ \t]+PYPY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
+            ${_PYTHON_PREFIX}_PyPy_VERSION "${${_PYTHON_PREFIX}_PyPy_VERSION}")
+  endif()
+
+  unset(${_PYTHON_PREFIX}_LINK_OPTIONS)
+  if (${_PYTHON_PREFIX}_Development.Embed_FOUND AND APPLE
+      AND ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$")
+    # rpath must be specified if python is part of a framework
+    unset(_${_PYTHON_PREFIX}_is_prefix)
+    foreach (_${_PYTHON_PREFIX}_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS)
+      foreach (_${_PYTHON_PREFIX}_framework IN LISTS _${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_implementation}_FRAMEWORKS)
+        cmake_path (IS_PREFIX _${_PYTHON_PREFIX}_framework "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" _${_PYTHON_PREFIX}_is_prefix)
+        if (_${_PYTHON_PREFIX}_is_prefix)
+          cmake_path (GET _${_PYTHON_PREFIX}_framework PARENT_PATH _${_PYTHON_PREFIX}_framework)
+          set (${_PYTHON_PREFIX}_LINK_OPTIONS "LINKER:-rpath,${_${_PYTHON_PREFIX}_framework}")
+          break()
+        endif()
+      endforeach()
+      if (_${_PYTHON_PREFIX}_is_prefix)
+        break()
+      endif()
+    endforeach()
+    unset(_${_PYTHON_PREFIX}_implementation)
+    unset(_${_PYTHON_PREFIX}_framework)
+    unset(_${_PYTHON_PREFIX}_is_prefix)
+  endif()
+
+  if (NOT DEFINED ${_PYTHON_PREFIX}_SOABI)
+    _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI)
   endif()
 
+  if (NOT DEFINED ${_PYTHON_PREFIX}_SOSABI)
+    _python_get_config_var (${_PYTHON_PREFIX}_SOSABI SOSABI)
+  endif()
+
+  _python_compute_development_signature (Module)
+  _python_compute_development_signature (SABIModule)
+  _python_compute_development_signature (Embed)
+
   # Restore the original find library ordering
   if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES)
     set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES})
   endif()
+
+  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+    if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+      set (${_PYTHON_PREFIX}_LIBRARY "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} Library")
+    endif()
+    if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+      set (${_PYTHON_PREFIX}_SABI_LIBRARY "${_${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} ABI Library")
+    endif()
+    if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+      set (${_PYTHON_PREFIX}_INCLUDE_DIR "${_${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} Include Directory")
+    endif()
+  endif()
+
+  _python_mark_as_internal (_${_PYTHON_PREFIX}_LIBRARY_RELEASE
+                            _${_PYTHON_PREFIX}_LIBRARY_DEBUG
+                            _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE
+                            _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG
+                            _${_PYTHON_PREFIX}_SABI_LIBRARY_RELEASE
+                            _${_PYTHON_PREFIX}_SABI_LIBRARY_DEBUG
+                            _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_RELEASE
+                            _${_PYTHON_PREFIX}_RUNTIME_SABI_LIBRARY_DEBUG
+                            _${_PYTHON_PREFIX}_INCLUDE_DIR
+                            _${_PYTHON_PREFIX}_CONFIG
+                            _${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE
+                            _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE)
 endif()
 
+if (${_PYTHON_PREFIX}_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)
-  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
-  if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy)
-    list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
-  endif()
-  execute_process(
-      COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-              "from __future__ import print_function\ntry: import numpy; print(numpy.get_include(), end='')\nexcept:pass\n"
-      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-      OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH
-      ERROR_QUIET
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-  if (NOT _${_PYTHON_PREFIX}_RESULT)
-    find_path(${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
-              NAMES "numpy/arrayobject.h" "numpy/numpyconfig.h"
-              HINTS "${_${_PYTHON_PREFIX}_NumPy_PATH}"
-              NO_DEFAULT_PATH)
-  endif()
-  if(${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
-    set(${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
-    set(${_PYTHON_PREFIX}_NumPy_FOUND TRUE)
-  endif()
-  if(${_PYTHON_PREFIX}_NumPy_FOUND)
-    execute_process(
-            COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
-            "from __future__ import print_function\ntry: import numpy; print(numpy.__version__, end='')\nexcept:pass\n"
-            RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-            OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION)
+  list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+
+  if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+      AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+    set (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE INTERNAL "")
+  elseif (DEFINED _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+    # compute numpy signature. Depends on interpreter and development signatures
+    string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+    if (NOT __${_PYTHON_PREFIX}_NUMPY_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_NUMPY_SIGNATURE
+        OR NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+      unset (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR CACHE)
+      unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)
+    endif()
+  endif()
+
+  if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+    execute_process(COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                            "import sys\ntry: import numpy; sys.stdout.write(numpy.get_include())\nexcept:pass\n"
+                    RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                    OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH
+                    ERROR_QUIET
+                    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+    if (NOT _${_PYTHON_PREFIX}_RESULT)
+      find_path (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+                 NAMES "numpy/arrayobject.h" "numpy/numpyconfig.h"
+                 HINTS "${_${_PYTHON_PREFIX}_NumPy_PATH}"
+                 NO_DEFAULT_PATH)
+    endif()
+  endif()
+
+  set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+
+  if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
+    set_property (CACHE _${_PYTHON_PREFIX}_NumPy_REASON_FAILURE PROPERTY VALUE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"")
+    set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND")
+  endif()
+
+  if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR)
+    execute_process (COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c
+                             "import sys\ntry: import numpy; sys.stdout.write(numpy.__version__)\nexcept:pass\n"
+                     RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
-       set(${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}")
+      set (${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}")
+    else()
+      unset (${_PYTHON_PREFIX}_NumPy_VERSION)
     endif()
+
+    # final step: set NumPy founded only if Development.Module component is founded as well
+    set(${_PYTHON_PREFIX}_NumPy_FOUND ${${_PYTHON_PREFIX}_Development.Module_FOUND})
+  else()
+    set (${_PYTHON_PREFIX}_NumPy_FOUND FALSE)
+  endif()
+
+  if (${_PYTHON_PREFIX}_NumPy_FOUND)
+    unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE CACHE)
+
+    # compute and save numpy signature
+    string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}")
+    set (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${__${_PYTHON_PREFIX}_NUMPY_SIGNATURE}" CACHE INTERNAL "")
+  else()
+    unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE)
   endif()
-  # final step: set NumPy founded only if Development component is founded as well
-  if (NOT ${_PYTHON_PREFIX}_Development_FOUND)
-    set(${_PYTHON_PREFIX}_NumPy_FOUND FALSE)
+
+  if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE)
+    set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} NumPy Include Directory")
   endif()
+
+  _python_mark_as_internal (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR
+                            _${_PYTHON_PREFIX}_NUMPY_SIGNATURE)
 endif()
 
 # final validation
 if (${_PYTHON_PREFIX}_VERSION_MAJOR AND
     NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR)
   _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"")
+
+  cmake_policy(POP)
+  return()
 endif()
 
-include (FindPackageHandleStandardArgs)
+unset (_${_PYTHON_PREFIX}_REASON_FAILURE)
+foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy)
+  if (_${_PYTHON_PREFIX}_COMPONENT STREQUAL "Development")
+    foreach (artifact IN LISTS _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS)
+      if (_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE)
+        _python_add_reason_failure ("Development" "${_${_PYTHON_PREFIX}_Development_${artifact}_REASON_FAILURE}")
+      endif()
+    endforeach()
+  endif()
+  if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE)
+    string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n        ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}")
+    unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE CACHE)
+  endif()
+endforeach()
+
 find_package_handle_standard_args (${_PYTHON_PREFIX}
                                    REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS}
                                    VERSION_VAR ${_PYTHON_PREFIX}_VERSION
-                                   HANDLE_COMPONENTS)
+                                   HANDLE_VERSION_RANGE
+                                   HANDLE_COMPONENTS
+                                   REASON_FAILURE_MESSAGE "${_${_PYTHON_PREFIX}_REASON_FAILURE}")
 
 # Create imported targets and helper functions
 if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
@@ -1201,73 +3885,123 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
                   PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}")
   endif()
 
-  if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
-      AND ${_PYTHON_PREFIX}_Development_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::Python)
+  if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+        AND ${_PYTHON_PREFIX}_Development.Module_FOUND)
+      OR ("Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+        AND ${_PYTHON_PREFIX}_Development.SABIModule_FOUND)
+      OR ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
+        AND ${_PYTHON_PREFIX}_Development.Embed_FOUND))
 
-    if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
-        OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
-        OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)
-      set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
-    else()
-      set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
-    endif()
-
-    add_library (${_PYTHON_PREFIX}::Python ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)
-
-    set_property (TARGET ${_PYTHON_PREFIX}::Python
-                  PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIR}")
-
-    if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE)
-        OR (${_PYTHON_PREFIX}_LIBRARY_DEBUG AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG))
-      # System manage shared libraries in two parts: import and runtime
-      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-        set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
-                                          IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}"
-                                          IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}")
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
-                                          IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}"
-                                          IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}")
+    macro (__PYTHON_IMPORT_LIBRARY __name)
+      if (${ARGC} GREATER 1)
+        set (_PREFIX "${ARGV1}_")
       else()
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
-                                          IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARY}"
-                                          IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY}")
+        set (_PREFIX "")
       endif()
-    else()
-      if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-        set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
-                                          IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}")
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
-                                          IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}")
+      if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$"
+          OR ${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE)
+        set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED)
+      else()
+        set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC)
+      endif()
+
+      if (NOT TARGET ${__name})
+        add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED)
+      endif()
+
+      set_property (TARGET ${__name}
+                    PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
+
+      if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE)
+        # System manage shared libraries in two parts: import and runtime
+        if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG)
+          set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+                                            IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}"
+                                            IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_${_PREFIX}RUNTIME_LIBRARY_RELEASE}")
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+                                            IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG}"
+                                            IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_DEBUG}")
+        else()
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+                                            IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARIES}"
+                                            IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_${_PREFIX}LIBRARY_RELEASE}")
+        endif()
       else()
-        set_target_properties (${_PYTHON_PREFIX}::Python
-                               PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
-                                          IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY}")
+        if (${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG)
+          set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG)
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+                                            IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}")
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+                                            IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_DEBUG}")
+        else()
+          set_target_properties (${__name}
+                                 PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+                                            IMPORTED_LOCATION "${${_PYTHON_PREFIX}_${_PREFIX}LIBRARY_RELEASE}")
+        endif()
       endif()
+
+      if (_${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC")
+        # extend link information with dependent libraries
+        _python_get_config_var (_${_PYTHON_PREFIX}_LINK_LIBRARIES LIBS)
+        if (_${_PYTHON_PREFIX}_LINK_LIBRARIES)
+          set_property (TARGET ${__name}
+                        PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})
+        endif()
+      endif()
+
+      if (${_PYTHON_PREFIX}_LINK_OPTIONS
+          AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "SHARED")
+        set_property (TARGET ${__name} PROPERTY INTERFACE_LINK_OPTIONS "${${_PYTHON_PREFIX}_LINK_OPTIONS}")
+      endif()
+    endmacro()
+
+    macro (__PYTHON_IMPORT_MODULE __name)
+      if (NOT TARGET ${__name})
+        add_library (${__name} INTERFACE IMPORTED)
+      endif()
+      set_property (TARGET ${__name}
+                    PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}")
+
+      # When available, enforce shared library generation with undefined symbols
+      if (APPLE)
+        set_property (TARGET ${__name}
+                      PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup")
+      endif()
+      if (CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+        set_property (TARGET ${__name}
+                      PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs")
+      endif()
+      if (CMAKE_SYSTEM_NAME STREQUAL "AIX")
+        set_property (TARGET ${__name}
+                      PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok")
+      endif()
+    endmacro()
+
+    if (${_PYTHON_PREFIX}_Development.Embed_FOUND)
+      __python_import_library (${_PYTHON_PREFIX}::Python)
     endif()
 
-    if (_${_PYTHON_PREFIX}_CONFIG AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC")
-      # extend link information with dependent libraries
-      execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
-                       RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                       OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
-                       ERROR_QUIET
-                       OUTPUT_STRIP_TRAILING_WHITESPACE)
-      if (NOT _${_PYTHON_PREFIX}_RESULT)
-        string (REGEX MATCHALL "-[Ll][^ ]+" _${_PYTHON_PREFIX}_LINK_LIBRARIES "${_${_PYTHON_PREFIX}_FLAGS}")
-        # remove elements relative to python library itself
-        list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-lpython")
-        foreach (_${_PYTHON_PREFIX}_DIR IN LISTS ${_PYTHON_PREFIX}_LIBRARY_DIRS)
-          list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-L${${_PYTHON_PREFIX}_DIR}")
-        endforeach()
-        set_property (TARGET ${_PYTHON_PREFIX}::Python
-                      PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES})
+    if (${_PYTHON_PREFIX}_Development.Module_FOUND)
+      if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS)
+        # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python
+        # but ALIAS cannot be used because the imported library is not GLOBAL.
+        __python_import_library (${_PYTHON_PREFIX}::Module)
+      else()
+        __python_import_module (${_PYTHON_PREFIX}::Module)
+      endif()
+    endif()
+
+    if (${_PYTHON_PREFIX}_Development.SABIModule_FOUND)
+      if ("SABI_LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_SABIMODULE_ARTIFACTS)
+        __python_import_library (${_PYTHON_PREFIX}::SABIModule SABI)
+      else()
+        __python_import_module (${_PYTHON_PREFIX}::SABIModule)
       endif()
     endif()
 
@@ -1276,35 +4010,115 @@ if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT")
     # It is used to build modules for python.
     #
     function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name)
-      cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY
-                             "STATIC;SHARED;MODULE" "" "")
+      cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY "STATIC;SHARED;MODULE;WITH_SOABI" "USE_SABI" "")
 
-      unset (type)
-      if (NOT (PYTHON_ADD_LIBRARY_STATIC
-            OR PYTHON_ADD_LIBRARY_SHARED
-            OR PYTHON_ADD_LIBRARY_MODULE))
+      if (PYTHON_ADD_LIBRARY_STATIC)
+        set (type STATIC)
+      elseif (PYTHON_ADD_LIBRARY_SHARED)
+        set (type SHARED)
+      else()
         set (type MODULE)
       endif()
-      add_library (${name} ${type} ${ARGN})
-      target_link_libraries (${name} PRIVATE ${prefix}::Python)
 
-      # customize library name to follow module name rules
+      if (PYTHON_ADD_LIBRARY_USE_SABI)
+        if (NOT type STREQUAL MODULE)
+          message (SEND_ERROR "${prefix}_ADD_LIBRARY: 'USE_SABI' option is only valid for 'MODULE' type.")
+          return()
+        endif()
+        if (NOT PYTHON_ADD_LIBRARY_USE_SABI MATCHES "^(3)(\\.([0-9]+))?$")
+          message (SEND_ERROR "${prefix}_ADD_LIBRARY: ${PYTHON_ADD_LIBRARY_USE_SABI}: wrong version specified for 'USE_SABI'.")
+          return()
+        endif()
+        # compute value for Py_LIMITED_API macro
+        set (major_version "${CMAKE_MATCH_1}")
+        unset (minor_version)
+        if (CMAKE_MATCH_3)
+          set (minor_version "${CMAKE_MATCH_3}")
+        endif()
+        if (major_version EQUAL "3" AND NOT minor_version)
+          set (Py_LIMITED_API "3")
+        elseif ("${major_version}.${minor_version}" VERSION_LESS "3.2")
+          message (SEND_ERROR "${prefix}_ADD_LIBRARY: ${PYTHON_ADD_LIBRARY_USE_SABI}: invalid version. Version must be '3.2' or upper.")
+          return()
+        else()
+          set (Py_LIMITED_API "0x0${major_version}")
+          if (NOT minor_version)
+            string (APPEND Py_LIMITED_API "00")
+          else()
+            if (minor_version LESS 16)
+              string (APPEND Py_LIMITED_API "0")
+            endif()
+            math (EXPR minor_version "${minor_version}" OUTPUT_FORMAT HEXADECIMAL)
+            string (REGEX REPLACE "^0x(.+)$" "\\1" minor_version "${minor_version}")
+            string (APPEND Py_LIMITED_API "${minor_version}")
+          endif()
+          string (APPEND Py_LIMITED_API "0000")
+        endif()
+      endif()
+
+      if (type STREQUAL "MODULE")
+        if (PYTHON_ADD_LIBRARY_USE_SABI AND NOT TARGET ${prefix}::SABIModule)
+          message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::SABIModule' is not defined.\n   Did you miss to request COMPONENT 'Development.SABIModule'?")
+          return()
+        endif()
+        if (NOT PYTHON_ADD_LIBRARY_USE_SABI AND NOT TARGET ${prefix}::Module)
+          message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Module' is not defined.\n   Did you miss to request COMPONENT 'Development.Module'?")
+          return()
+        endif()
+      endif()
+      if (NOT type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Python)
+        message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Python' is not defined.\n   Did you miss to request COMPONENT 'Development.Embed'?")
+        return()
+      endif()
+
+      add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS})
+
       get_property (type TARGET ${name} PROPERTY TYPE)
+
       if (type STREQUAL "MODULE_LIBRARY")
+        if (PYTHON_ADD_LIBRARY_USE_SABI)
+          target_compile_definitions (${name} PRIVATE Py_LIMITED_API=${Py_LIMITED_API})
+          target_link_libraries (${name} PRIVATE ${prefix}::SABIModule)
+        else()
+          target_link_libraries (${name} PRIVATE ${prefix}::Module)
+        endif()
+        # customize library name to follow module name rules
         set_property (TARGET ${name} PROPERTY PREFIX "")
         if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
           set_property (TARGET ${name} PROPERTY SUFFIX ".pyd")
         endif()
+
+        if (PYTHON_ADD_LIBRARY_WITH_SOABI)
+          if (NOT PYTHON_ADD_LIBRARY_USE_SABI AND ${prefix}_SOABI)
+            get_property (suffix TARGET ${name} PROPERTY SUFFIX)
+            if (NOT suffix)
+              set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+            endif()
+            set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOABI}${suffix}")
+          endif()
+          if (PYTHON_ADD_LIBRARY_USE_SABI AND ${prefix}_SOSABI)
+            get_property (suffix TARGET ${name} PROPERTY SUFFIX)
+            if (NOT suffix)
+              set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}")
+            endif()
+            set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOSABI}${suffix}")
+          endif()
+        endif()
+      else()
+        if (PYTHON_ADD_LIBRARY_WITH_SOABI OR PYTHON_ADD_LIBRARY_USE_SABI)
+          message (AUTHOR_WARNING "Find${prefix}: Options 'WITH_SOABI' and 'USE_SABI' are only supported for `MODULE` library type.")
+        endif()
+        target_link_libraries (${name} PRIVATE ${prefix}::Python)
       endif()
     endfunction()
   endif()
 
   if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND
-      AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Python)
+      AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module)
     add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED)
     set_property (TARGET ${_PYTHON_PREFIX}::NumPy
-                  PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}")
-    target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Python)
+                  PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS}")
+    target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module)
   endif()
 endif()
 
@@ -1325,4 +4139,4 @@ else()
   unset (CMAKE_FIND_FRAMEWORK)
 endif()
 
-unset (_${_PYTHON_PREFIX}_CONFIG CACHE)
+cmake_policy(POP)
index c2f338469712f84bc8c9defb0d47dccb630bb3cb..901565bdfac375f83506b14d9a8ce582db19ba1b 100644 (file)
@@ -5,21 +5,52 @@
 FindPython3
 -----------
 
+.. versionadded:: 3.12
+
 Find Python 3 interpreter, compiler and development environment (include
 directories and libraries).
 
-Three components are supported:
+.. versionadded:: 3.19
+  When a version is requested, it can be specified as a simple value or as a
+  range. For a detailed description of version range usage and capabilities,
+  refer to the :command:`find_package` command.
+
+The following components are supported:
 
 * ``Interpreter``: search for Python 3 interpreter
 * ``Compiler``: search for Python 3 compiler. Only offered by IronPython.
 * ``Development``: search for development artifacts (include directories and
-  libraries)
+  libraries).
+
+  .. versionadded:: 3.18
+    This component includes two sub-components which can be specified
+    independently:
+
+    * ``Development.Module``: search for artifacts for Python 3 module
+      developments.
+    * ``Development.Embed``: search for artifacts for Python 3 embedding
+      developments.
+
+  .. versionadded:: 3.26
+
+    * ``Development.SABIModule``: search for artifacts for Python 3 module
+      developments using the
+      `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_.
+      This component is available only for version ``3.2`` and upper.
+
 * ``NumPy``: search for NumPy include directories.
 
-If no ``COMPONENTS`` is specified, ``Interpreter`` is assumed.
+.. versionadded:: 3.14
+  Added the ``NumPy`` component.
+
+If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed.
+
+If component ``Development`` is specified, it implies sub-components
+``Development.Module`` and ``Development.Embed``.
 
 To ensure consistent versions between components ``Interpreter``, ``Compiler``,
-``Development`` and ``NumPy``, specify all components at the same time::
+``Development`` (or one of its sub-components) and ``NumPy``, specify all
+components at the same time::
 
   find_package (Python3 COMPONENTS Interpreter Development)
 
@@ -31,24 +62,45 @@ for you.
 
 .. note::
 
-  If components ``Interpreter`` and ``Development`` are both specified, this
-  module search only for interpreter with same platform architecture as the one
-  defined by ``CMake`` configuration. This contraint does not apply if only
-  ``Interpreter`` component is specified.
+  If components ``Interpreter`` and ``Development`` (or one of its
+  sub-components) are both specified, this module search only for interpreter
+  with same platform architecture as the one defined by CMake
+  configuration. This constraint does not apply if only ``Interpreter``
+  component is specified.
 
 Imported Targets
 ^^^^^^^^^^^^^^^^
 
-This module defines the following :ref:`Imported Targets <Imported Targets>`
-(when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``):
+This module defines the following :ref:`Imported Targets <Imported Targets>`:
+
+.. versionchanged:: 3.14
+  :ref:`Imported Targets <Imported Targets>` are only created when
+  :prop_gbl:`CMAKE_ROLE` is ``PROJECT``.
 
 ``Python3::Interpreter``
   Python 3 interpreter. Target defined if component ``Interpreter`` is found.
 ``Python3::Compiler``
   Python 3 compiler. Target defined if component ``Compiler`` is found.
+
+``Python3::Module``
+  .. versionadded:: 3.15
+
+  Python 3 library for Python module. Target defined if component
+  ``Development.Module`` is found.
+
+``Python3::SABIModule``
+  .. versionadded:: 3.26
+
+  Python 3 library for Python module using the Stable Application Binary
+  Interface. Target defined if component ``Development.SABIModule`` is found.
+
 ``Python3::Python``
-  Python 3 library. Target defined if component ``Development`` is found.
+  Python 3 library for Python embedding. Target defined if component
+  ``Development.Embed`` is found.
+
 ``Python3::NumPy``
+  .. versionadded:: 3.14
+
   NumPy library for Python 3. Target defined if component ``NumPy`` is found.
 
 Result Variables
@@ -70,26 +122,43 @@ This module will set the following variables in your project
     * Anaconda
     * Canopy
     * IronPython
+    * PyPy
 ``Python3_STDLIB``
   Standard platform independent installation directory.
 
-  Information returned by
-  ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``.
+  Information returned by ``sysconfig.get_path('stdlib')``.
 ``Python3_STDARCH``
   Standard platform dependent installation directory.
 
-  Information returned by
-  ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``.
+  Information returned by ``sysconfig.get_path('platstdlib')``.
 ``Python3_SITELIB``
   Third-party platform independent installation directory.
 
-  Information returned by
-  ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``.
+  Information returned by ``sysconfig.get_path('purelib')``.
 ``Python3_SITEARCH``
   Third-party platform dependent installation directory.
 
-  Information returned by
-  ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``.
+  Information returned by ``sysconfig.get_path('platlib')``.
+
+``Python3_SOABI``
+  .. versionadded:: 3.17
+
+  Extension suffix for modules.
+
+  Information computed from ``sysconfig.get_config_var('EXT_SUFFIX')`` or
+  ``sysconfig.get_config_var('SOABI')`` or
+  ``python3-config --extension-suffix``.
+
+``Python3_SOSABI``
+  .. versionadded:: 3.26
+
+  Extension suffix for modules using the Stable Application Binary Interface.
+
+  Information computed from ``importlib.machinery.EXTENSION_SUFFIXES`` if the
+  COMPONENT ``Interpreter`` was specified. Otherwise, the extension is ``abi3``
+  except for ``Windows``, ``MSYS`` and ``CYGWIN`` for which this is an empty
+  string.
+
 ``Python3_Compiler_FOUND``
   System has the Python 3 compiler.
 ``Python3_COMPILER``
@@ -97,16 +166,60 @@ This module will set the following variables in your project
 ``Python3_COMPILER_ID``
   A short string unique to the compiler. Possible values include:
     * IronPython
+
+``Python3_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
+  The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
 ``Python3_Development_FOUND``
+
   System has the Python 3 development artifacts.
+
+``Python3_Development.Module_FOUND``
+  .. versionadded:: 3.18
+
+  System has the Python 3 development artifacts for Python module.
+
+``Python3_Development.SABIModule_FOUND``
+  .. versionadded:: 3.26
+
+  System has the Python 3 development artifacts for Python module using the
+  Stable Application Binary Interface.
+
+``Python3_Development.Embed_FOUND``
+  .. versionadded:: 3.18
+
+  System has the Python 3 development artifacts for Python embedding.
+
 ``Python3_INCLUDE_DIRS``
+
   The Python 3 include directories.
+
+``Python3_LINK_OPTIONS``
+  .. versionadded:: 3.19
+
+  The Python 3 link options. Some configurations require specific link options
+  for a correct build and execution.
+
 ``Python3_LIBRARIES``
   The Python 3 libraries.
 ``Python3_LIBRARY_DIRS``
   The Python 3 library directories.
 ``Python3_RUNTIME_LIBRARY_DIRS``
   The Python 3 runtime library directories.
+``Python3_SABI_LIBRARIES``
+  .. versionadded:: 3.26
+
+  The Python 3 libraries for the Stable Application Binary Interface.
+``Python3_SABI_LIBRARY_DIRS``
+  .. versionadded:: 3.26
+
+  The Python 3 ``SABI`` library directories.
+``Python3_RUNTIME_SABI_LIBRARY_DIRS``
+  .. versionadded:: 3.26
+
+  The Python 3 runtime ``SABI`` library directories.
 ``Python3_VERSION``
   Python 3 version.
 ``Python3_VERSION_MAJOR``
@@ -115,11 +228,25 @@ This module will set the following variables in your project
   Python 3 minor version.
 ``Python3_VERSION_PATCH``
   Python 3 patch version.
+
+``Python3_PyPy_VERSION``
+  .. versionadded:: 3.18
+
+  Python 3 PyPy version.
+
 ``Python3_NumPy_FOUND``
+  .. versionadded:: 3.14
+
   System has the NumPy.
+
 ``Python3_NumPy_INCLUDE_DIRS``
-  The NumPy include directries.
+  .. versionadded:: 3.14
+
+  The NumPy include directories.
+
 ``Python3_NumPy_VERSION``
+  .. versionadded:: 3.14
+
   The NumPy version.
 
 Hints
@@ -134,43 +261,280 @@ Hints
   * If set to TRUE, search **only** for static libraries.
   * If set to FALSE, search **only** for shared libraries.
 
+  .. note::
+
+    This hint will be ignored on ``Windows`` because static libraries are not
+    available on this platform.
+
+``Python3_FIND_ABI``
+  .. versionadded:: 3.16
+
+  This variable defines which ABIs, as defined in :pep:`3149`, should be
+  searched.
+
+  .. note::
+
+    If ``Python3_FIND_ABI`` is not defined, any ABI will be searched.
+
+  The ``Python3_FIND_ABI`` variable is a 3-tuple specifying, in that order,
+  ``pydebug`` (``d``), ``pymalloc`` (``m``) and ``unicode`` (``u``) flags.
+  Each element can be set to one of the following:
+
+  * ``ON``: Corresponding flag is selected.
+  * ``OFF``: Corresponding flag is not selected.
+  * ``ANY``: The two possibilities (``ON`` and ``OFF``) will be searched.
+
+  From this 3-tuple, various ABIs will be searched starting from the most
+  specialized to the most general. Moreover, ``debug`` versions will be
+  searched **after** ``non-debug`` ones.
+
+  For example, if we have::
+
+    set (Python3_FIND_ABI "ON" "ANY" "ANY")
+
+  The following flags combinations will be appended, in that order, to the
+  artifact names: ``dmu``, ``dm``, ``du``, and ``d``.
+
+  And to search any possible ABIs::
+
+    set (Python3_FIND_ABI "ANY" "ANY" "ANY")
+
+  The following combinations, in that order, will be used: ``mu``, ``m``,
+  ``u``, ``<empty>``, ``dmu``, ``dm``, ``du`` and ``d``.
+
+  .. note::
+
+    This hint is useful only on ``POSIX`` systems. So, on ``Windows`` systems,
+    when ``Python3_FIND_ABI`` is defined, ``Python`` distributions from
+    `python.org <https://www.python.org/>`_ will be found only if value for
+    each flag is ``OFF`` or ``ANY``.
+
+``Python3_FIND_STRATEGY``
+  .. versionadded:: 3.15
+
+  This variable defines how lookup will be done.
+  The ``Python3_FIND_STRATEGY`` variable can be set to one of the following:
+
+  * ``VERSION``: Try to find the most recent version in all specified
+    locations.
+    This is the default if policy :policy:`CMP0094` is undefined or set to
+    ``OLD``.
+  * ``LOCATION``: Stops lookup as soon as a version satisfying version
+    constraints is founded.
+    This is the default if policy :policy:`CMP0094` is set to ``NEW``.
+
+  See also ``Python3_FIND_UNVERSIONED_NAMES``.
+
 ``Python3_FIND_REGISTRY``
+  .. versionadded:: 3.13
+
   On Windows the ``Python3_FIND_REGISTRY`` variable determine the order
   of preference between registry and environment variables.
-  the ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
-  following:
+  The ``Python3_FIND_REGISTRY`` variable can be set to one of the following:
 
   * ``FIRST``: Try to use registry before environment variables.
     This is the default.
   * ``LAST``: Try to use registry after environment variables.
   * ``NEVER``: Never try to use registry.
 
-``CMAKE_FIND_FRAMEWORK``
-  On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+``Python3_FIND_FRAMEWORK``
+  .. versionadded:: 3.15
+
+  On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of
   preference between Apple-style and unix-style package components.
+  This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK`
+  variable.
 
   .. note::
 
     Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
 
+  If ``Python3_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK`
+  variable will be used, if any.
+
+``Python3_FIND_VIRTUALENV``
+  .. versionadded:: 3.15
+
+  This variable defines the handling of virtual environments managed by
+  ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment
+  is active (i.e. the ``activate`` script has been evaluated). In this case, it
+  takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK``
+  variables.  The ``Python3_FIND_VIRTUALENV`` variable can be set to one of the
+  following:
+
+  * ``FIRST``: The virtual environment is used before any other standard
+    paths to look-up for the interpreter. This is the default.
+  * ``ONLY``: Only the virtual environment is used to look-up for the
+    interpreter.
+  * ``STANDARD``: The virtual environment is not used to look-up for the
+    interpreter but environment variable ``PATH`` is always considered.
+    In this case, variable ``Python3_FIND_REGISTRY`` (Windows) or
+    ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or
+    ``NEVER`` to select preferably the interpreter from the virtual
+    environment.
+
+  .. versionadded:: 3.17
+    Added support for ``conda`` environments.
+
+  .. note::
+
+    If the component ``Development`` is requested, it is **strongly**
+    recommended to also include the component ``Interpreter`` to get expected
+    result.
+
+``Python3_FIND_IMPLEMENTATIONS``
+  .. versionadded:: 3.18
+
+  This variable defines, in an ordered list, the different implementations
+  which will be searched. The ``Python3_FIND_IMPLEMENTATIONS`` variable can
+  hold the following values:
+
+  * ``CPython``: this is the standard implementation. Various products, like
+    ``Anaconda`` or ``ActivePython``, rely on this implementation.
+  * ``IronPython``: This implementation use the ``CSharp`` language for
+    ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``).
+    See `IronPython <https://ironpython.net>`_.
+  * ``PyPy``: This implementation use ``RPython`` language and
+    ``RPython translation toolchain`` to produce the python interpreter.
+    See `PyPy <https://www.pypy.org>`_.
+
+  The default value is:
+
+  * Windows platform: ``CPython``, ``IronPython``
+  * Other platforms: ``CPython``
+
+  .. note::
+
+    This hint has the lowest priority of all hints, so even if, for example,
+    you specify ``IronPython`` first and ``CPython`` in second, a python
+    product based on ``CPython`` can be selected because, for example with
+    ``Python3_FIND_STRATEGY=LOCATION``, each location will be search first for
+    ``IronPython`` and second for ``CPython``.
+
+  .. note::
+
+    When ``IronPython`` is specified, on platforms other than ``Windows``, the
+    ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available
+    through the ``PATH`` variable.
+
+``Python3_FIND_UNVERSIONED_NAMES``
+  .. versionadded:: 3.20
+
+  This variable defines how the generic names will be searched. Currently, it
+  only applies to the generic names of the interpreter, namely, ``python3`` and
+  ``python``.
+  The ``Python3_FIND_UNVERSIONED_NAMES`` variable can be set to one of the
+  following values:
+
+  * ``FIRST``: The generic names are searched before the more specialized ones
+    (such as ``python3.5`` for example).
+  * ``LAST``: The generic names are searched after the more specialized ones.
+    This is the default.
+  * ``NEVER``: The generic name are not searched at all.
+
+  See also ``Python3_FIND_STRATEGY``.
+
+Artifacts Specification
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. versionadded:: 3.16
+
+To solve special cases, it is possible to specify directly the artifacts by
+setting the following variables:
+
+``Python3_EXECUTABLE``
+  The path to the interpreter.
+
+``Python3_COMPILER``
+  The path to the compiler.
+
+``Python3_DOTNET_LAUNCHER``
+  .. versionadded:: 3.18
+
+  The ``.Net`` interpreter. Only used by ``IronPython`` implementation.
+
+``Python3_LIBRARY``
+  The path to the library. It will be used to compute the
+  variables ``Python3_LIBRARIES``, ``Python3_LIBRARY_DIRS`` and
+  ``Python3_RUNTIME_LIBRARY_DIRS``.
+
+``Python3_SABI_LIBRARY``
+  .. versionadded:: 3.26
+
+  The path to the library for Stable Application Binary Interface. It will be
+  used to compute the variables ``Python3_SABI_LIBRARIES``,
+  ``Python3_SABI_LIBRARY_DIRS`` and ``Python3_RUNTIME_SABI_LIBRARY_DIRS``.
+
+``Python3_INCLUDE_DIR``
+  The path to the directory of the ``Python`` headers. It will be used to
+  compute the variable ``Python3_INCLUDE_DIRS``.
+
+``Python3_NumPy_INCLUDE_DIR``
+  The path to the directory of the ``NumPy`` headers. It will be used to
+  compute the variable ``Python3_NumPy_INCLUDE_DIRS``.
+
+.. note::
+
+  All paths must be absolute. Any artifact specified with a relative path
+  will be ignored.
+
 .. note::
 
-  If a Python virtual environment is configured, set variable
-  ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with
-  value ``LAST`` or ``NEVER`` to select it preferably.
+  When an artifact is specified, all ``HINTS`` will be ignored and no search
+  will be performed for this artifact.
+
+  If more than one artifact is specified, it is the user's responsibility to
+  ensure the consistency of the various artifacts.
+
+By default, this module supports multiple calls in different directories of a
+project with different version/component requirements while providing correct
+and consistent results for each call. To support this behavior, CMake cache
+is not used in the traditional way which can be problematic for interactive
+specification. So, to enable also interactive specification, module behavior
+can be controlled with the following variable:
+
+``Python3_ARTIFACTS_INTERACTIVE``
+  .. versionadded:: 3.18
+
+  Selects the behavior of the module. This is a boolean variable:
+
+  * If set to ``TRUE``: Create CMake cache entries for the above artifact
+    specification variables so that users can edit them interactively.
+    This disables support for multiple version/component requirements.
+  * If set to ``FALSE`` or undefined: Enable multiple version/component
+    requirements.
 
 Commands
 ^^^^^^^^
 
 This module defines the command ``Python3_add_library`` (when
 :prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as
-:command:`add_library`, but takes care of Python module naming rules
-(only applied if library is of type ``MODULE``), and adds a dependency to target
-``Python3::Python``::
-
-  Python3_add_library (my_module MODULE src1.cpp)
-
-If library type is not specified, ``MODULE`` is assumed.
+:command:`add_library` and adds a dependency to target ``Python3::Python`` or,
+when library type is ``MODULE``, to target ``Python3::Module`` or
+``Python3::SABIModule`` (when ``USE_SABI`` option is specified) and takes care
+of Python module naming rules::
+
+  Python3_add_library (<name> [STATIC | SHARED | MODULE [USE_SABI <version>] [WITH_SOABI]]
+                       <source1> [<source2> ...])
+
+If the library type is not specified, ``MODULE`` is assumed.
+
+.. versionadded:: 3.17
+  For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the
+  module suffix will include the ``Python3_SOABI`` value, if any.
+
+.. versionadded:: 3.26
+  For ``MODULE`` type, if the option ``USE_SABI`` is specified, the
+  preprocessor definition ``Py_LIMITED_API`` will be specified, as ``PRIVATE``,
+  for the target ``<name>`` with the value computed from ``<version>`` argument.
+  The expected format for ``<version>`` is ``major[.minor]``, where each
+  component is a numeric value. If ``minor`` component is specified, the
+  version should be, at least, ``3.2`` which is the version where the
+  `Stable Application Binary Interface <https://docs.python.org/3/c-api/stable.html>`_
+  was introduced. Specifying only major version ``3`` is equivalent to ``3.2``.
+
+  When option ``WITH_SOABI`` is also specified,  the module suffix will include
+  the ``Python3_SOSABI`` value, if any.
 #]=======================================================================]