Преглед на файлове

Merge topic 'FindPython-FIND_ABI'

9201908ca5 FindPython: add Python_FIND_ABI hint.

Acked-by: Kitware Robot <[email protected]>
Merge-request: !3463
Brad King преди 6 години
родител
ревизия
b4a882cf10

+ 5 - 0
Help/release/dev/FindPython-FIND_ABI.rst

@@ -0,0 +1,5 @@
+FindPython-FIND_ABI
+-------------------
+
+* Modules :module:`FindPython3` and :module:`FindPython` gain the capability
+  to control which ``ABIs`` will be searched.

+ 45 - 0
Modules/FindPython.cmake

@@ -137,6 +137,51 @@ Hints
   * If set to TRUE, search **only** for static libraries.
   * If set to FALSE, search **only** for shared libraries.
 
+``Python_FIND_ABI``
+  This variable defines which ABIs, as defined in
+  `PEP 3149 <https://www.python.org/dev/peps/pep-3149/>`_, should be searched.
+
+  .. note::
+
+    This hint will be honored only when searched for ``Python`` version 3.
+
+  .. note::
+
+    If ``Python_FIND_ABI`` is not defined, any ABI will be searched.
+
+  The ``Python_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 posibilties (``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 (Python_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 (Python_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 ``Python_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``.
+
 ``Python_FIND_STRATEGY``
   This variable defines how lookup will be done.
   The ``Python_FIND_STRATEGY`` variable can be set to empty or one of the

+ 270 - 99
Modules/FindPython/Support.cmake

@@ -96,51 +96,149 @@ function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS _PYTHON_VERSION)
        PARENT_SCOPE)
 endfunction()
 
-function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES _PYTHON_VERSION _PYTHON_TYPE)
-  set (path_suffixes)
 
-  if (_PYTHON_TYPE STREQUAL "LIBRARY")
+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 "LIBRARY;INCLUDE" "VERSION" "")
+
+  if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS)
+    set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}")
+  else()
+    set (abi "mu" "m" "u" "")
+  endif()
+
+  set (path_suffixes)
+  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)
-      list (APPEND path_suffixes lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}mu-${CMAKE_LIBRARY_ARCHITECTURE}
-                                 lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}m-${CMAKE_LIBRARY_ARCHITECTURE}
-                                 lib/python${_PYTHON_VERSION}/config-${CMAKE_MATCH_1}u-${CMAKE_LIBRARY_ARCHITECTURE}
-                                 lib/python${_PYTHON_VERSION}/config-${CMAKE_MATCH_1}-${CMAKE_LIBRARY_ARCHITECTURE})
+      set (suffixes "${abi}")
+      if (suffixes)
+        list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+        list (TRANSFORM suffixes APPEND "-${CMAKE_LIBRARY_ARCHITECTURE}")
+      else()
+        set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}-${CMAKE_LIBRARY_ARCHITECTURE}")
+      endif()
+      list (APPEND path_suffixes ${suffixes})
+    endif()
+    set (suffixes "${abi}")
+    if (suffixes)
+      list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+    else()
+      set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}")
+    endif()
+    list (APPEND path_suffixes ${suffixes})
+  elseif (_PGPS_INCLUDE)
+    set (suffixes "${abi}")
+    if (suffixes)
+      list (TRANSFORM suffixes PREPEND "include/python${_PGPS_VERSION}")
+    else()
+      set (suffixes "include/python${_PGPS_VERSION}")
     endif()
-    list (APPEND path_suffixes lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}mu
-                               lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}m
-                               lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}u
-                               lib/python${_PYTHON_VERSION}/config-${_PYTHON_VERSION}
-                               lib/python${_PYTHON_VERSION}/config)
-
-  elseif (_PYTHON_TYPE STREQUAL "INCLUDE")
-    list (APPEND path_suffixes include/python${_PYTHON_VERSION}mu
-                               include/python${_PYTHON_VERSION}m
-                               include/python${_PYTHON_VERSION}u
-                               include/python${_PYTHON_VERSION}
-                               include)
+    list (APPEND path_suffixes ${suffixes} include)
   endif()
 
   set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE)
 endfunction()
 
-function (_PYTHON_GET_LIB_NAMES _PYTHON_PGLN_NAMES _PYTHON_VERSION)
-  string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PYTHON_VERSION})
+function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES)
+  cmake_parse_arguments (PARSE_ARGV 1 _PGN "POSIX;EXECUTABLE;CONFIG;LIBRARY;WIN32;DEBUG" "VERSION" "")
 
-  if (ARGC EQUAL 3 AND ARGV2 STREQUAL "DEBUG")
-    set (${_PYTHON_PGLN_NAMES} python${_PYTHON_VERSION_NO_DOTS}_d PARENT_SCOPE)
-  else()
-    set (${_PYTHON_PGLN_NAMES} python${_PYTHON_VERSION_NO_DOTS}
-                               python${_PYTHON_VERSION}mu
-                               python${_PYTHON_VERSION}m
-                               python${_PYTHON_VERSION}u
-                               python${_PYTHON_VERSION}
-         PARENT_SCOPE)
+  set (names)
+
+  if (_PGN_WIN32)
+    string (REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${_PGN_VERSION})
+
+    set (name python${_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_EXECUTABLE 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${_PGN_VERSION}")
+        list (TRANSFORM abinames APPEND "-config")
+        list (APPEND names ${abinames})
+      endif()
+      set (abinames "${abi}")
+      list (TRANSFORM abinames PREPEND "python${_PGN_VERSION}")
+      if (_PGN_CONFIG)
+        list (TRANSFORM abinames APPEND "-config")
+      endif()
+      list (APPEND names ${abinames})
+    else()
+      if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
+        set (abinames "${CMAKE_LIBRARY_ARCHITECTURE}-python${_PGN_VERSION}")
+      endif()
+      list (APPEND abinames "python${_PGN_VERSION}")
+      if (_PGN_CONFIG)
+        list (TRANSFORM abinames APPEND "-config")
+      endif()
+      list (APPEND names ${abinames})
+    endif()
+  endif()
+
+  set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE)
 endfunction()
 
 
@@ -149,16 +247,35 @@ function (_PYTHON_VALIDATE_INTERPRETER)
     return()
   endif()
 
-  cmake_parse_arguments (_PVI "EXACT" "" "" ${ARGN})
+  cmake_parse_arguments (PARSE_ARGV 0 _PVI "EXACT" "" "")
   if (_PVI_UNPARSED_ARGUMENTS)
     set (expected_version ${_PVI_UNPARSED_ARGUMENTS})
   else()
     unset (expected_version)
   endif()
 
+  # validate ABI compatibility
+  if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI)
+    execute_process (COMMAND "${${_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}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
+      return()
+    endif()
+  endif()
+
   get_filename_component (python_name "${${_PYTHON_PREFIX}_EXECUTABLE}" NAME)
 
-  if (expected_version AND NOT python_name STREQUAL "python${expected_version}${CMAKE_EXECUTABLE_SUFFIX}")
+  if (expected_version AND NOT python_name STREQUAL "python${expected_version}${abi}${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]]))"
@@ -168,7 +285,7 @@ function (_PYTHON_VALIDATE_INTERPRETER)
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (result OR (_PVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
       # interpreter not usable or has wrong major version
-      set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE)
+      set_property (CACHE ${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
   else()
@@ -183,7 +300,7 @@ 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)
+        set_property (CACHE ${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
         return()
       endif()
     endif()
@@ -200,7 +317,7 @@ 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)
+      set_property (CACHE ${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       return()
     endif()
   endif()
@@ -244,7 +361,7 @@ function (_PYTHON_VALIDATE_COMPILER expected_version)
 
   if (result OR (_PVC_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
     # Compiler not usable or has wrong version
-    set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE)
+    set_property (CACHE ${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
   endif()
 endfunction()
 
@@ -321,6 +438,28 @@ if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1)
   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()
+
 # Define lookup strategy
 if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW")
   set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION")
@@ -446,7 +585,8 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
 
     foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
       # build all executable names
-      list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_VERSION})
+      _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX EXECUTABLE)
+      list (APPEND _${_PYTHON_PREFIX}_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES})
 
       # Framework Paths
       _python_get_frameworks (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_VERSION})
@@ -516,12 +656,24 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
         endif()
       endif()
 
-      # try using HINTS and standard paths
+      # try using HINTS
       find_program (${_PYTHON_PREFIX}_EXECUTABLE
                     NAMES ${_${_PYTHON_PREFIX}_NAMES}
                           ${_${_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)
+      _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
+      if (${_PYTHON_PREFIX}_EXECUTABLE)
+        break()
+      endif()
+      # try using standard paths
+      find_program (${_PYTHON_PREFIX}_EXECUTABLE
+                    NAMES ${_${_PYTHON_PREFIX}_NAMES}
+                          ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}
+                    NAMES_PER_DIR
                     PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES})
       _python_validate_interpreter (${${_PYTHON_PREFIX}_FIND_VERSION})
       if (${_PYTHON_PREFIX}_EXECUTABLE)
@@ -561,9 +713,9 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
   else()
     # look-up for various versions and locations
     foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-      set (_${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_VERSION}
-                                    python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
-                                    python)
+      _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX EXECUTABLE)
+      list (APPEND _${_PYTHON_PREFIX}_NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+                                            python)
 
       _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
       _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION})
@@ -643,12 +795,12 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
       # systematically 'python' (i.e. version 2) even if version 3 is searched.
       if (WIN32)
         find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                      NAMES python${_${_PYTHON_PREFIX}_VERSION}
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES}
                             python
                             ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES})
       else()
         find_program (${_PYTHON_PREFIX}_EXECUTABLE
-                      NAMES python${_${_PYTHON_PREFIX}_VERSION})
+                      NAMES ${_${_PYTHON_PREFIX}_NAMES})
       endif()
       _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION} EXACT)
       if (${_PYTHON_PREFIX}_EXECUTABLE)
@@ -715,7 +867,7 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
       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)
+      set_property (CACHE ${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND")
       unset (${_PYTHON_PREFIX}_VERSION)
     endif()
   endif()
@@ -723,8 +875,17 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
   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
+    # 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}_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()
 
   if (${_PYTHON_PREFIX}_Interpreter_FOUND)
@@ -932,7 +1093,7 @@ 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_property (CACHE ${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND")
     endif()
     file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}")
   endif()
@@ -1015,16 +1176,15 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
       endif()
     endif()
   endif()
-  set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_EXEC_PREFIX}" "${_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+  set (_${_PYTHON_PREFIX}_BASE_HINTS "${_${_PYTHON_PREFIX}_EXEC_PREFIX}" "${_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+  set (_${_PYTHON_PREFIX}_HINTS ${_${_PYTHON_PREFIX}_BASE_HINTS})
 
   if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
     set (_${_PYTHON_PREFIX}_CONFIG_NAMES)
 
     foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-      if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
-        list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config")
-      endif()
-      list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config")
+      _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG)
+      list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES})
     endforeach()
 
     find_program (_${_PYTHON_PREFIX}_CONFIG
@@ -1033,6 +1193,22 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
                   HINTS ${_${_PYTHON_PREFIX}_HINTS}
                   PATH_SUFFIXES bin)
 
+    if (_${_PYTHON_PREFIX}_CONFIG)
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --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)
+      endif()
+    endif()
+
     if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE)
       # check that config tool match library architecture
       execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
@@ -1052,11 +1228,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
   else()
     foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
       # 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")
+      _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG)
       find_program (_${_PYTHON_PREFIX}_CONFIG
                     NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES}
                     NAMES_PER_DIR
@@ -1067,6 +1239,22 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
       if (NOT _${_PYTHON_PREFIX}_CONFIG)
         continue()
       endif()
+
+      execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --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)
+        continue()
+      endif()
+
       if (DEFINED CMAKE_LIBRARY_ARCHITECTURE)
         # check that config tool match library architecture
         execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
@@ -1105,49 +1293,32 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
   endif()
 
   if (_${_PYTHON_PREFIX}_CONFIG)
-    set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
-
-    unset (_${_PYTHON_PREFIX}_LIB_DIRS)
-    unset (_${_PYTHON_PREFIX}_PATH_SUFFIXES)
-    unset (_${_PYTHON_PREFIX}_LIB_NAMES)
-
-    # retrieve library
-    execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags
+    # enforce current ABI
+    execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
-                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS
+                     OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS
                      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}")
-      if (_${_PYTHON_PREFIX}_CONFIG MATCHES "python([0-9.]+)-config")
-        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${CMAKE_MATCH_1} LIBRARY)
-      endif()
-
-      # 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)
+    if (_${_PYTHON_PREFIX}_RESULT)
+      # assume ABI is not supported
+      set (_${_PYTHON_PREFIX}_ABIFLAGS "")
     endif()
 
+    set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}")
+
+    # retrieve library
+    ## compute some paths and artifact names
+    string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_CONFIG_VERSION "${_${_PYTHON_PREFIX}_CONFIG}")
+    _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_CONFIG_VERSION} LIBRARY)
+    _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_CONFIG_VERSION} POSIX LIBRARY)
+
     execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir
                      RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
                      OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR
                      ERROR_QUIET
                      OUTPUT_STRIP_TRAILING_WHITESPACE)
     if (NOT _${_PYTHON_PREFIX}_RESULT)
-      list (APPEND _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
-    endif()
-    list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_DIRS)
-    list (APPEND _${_PYTHON_PREFIX}_HINTS ${_${_PYTHON_PREFIX}_LIB_DIRS})
-
-    if (NOT _${_PYTHON_PREFIX}_LIB_NAMES)
-      # config tool do not specify "-l" option (it is the case starting with 3.8)
-      # extract version from the config tool name and list all possible lib names
-      if (_${_PYTHON_PREFIX}_CONFIG MATCHES "python([0-9.]+)-config")
-        _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${CMAKE_MATCH_1})
-      endif()
+      list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}")
     endif()
 
     list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
@@ -1195,7 +1366,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
 
   # Rely on HINTS and standard paths if config tool failed to locate artifacts
   if (NOT ${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT ${_PYTHON_PREFIX}_INCLUDE_DIR)
-    set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+    set (_${_PYTHON_PREFIX}_HINTS ${_${_PYTHON_PREFIX}_BASE_HINTS})
 
     if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION")
       unset (_${_PYTHON_PREFIX}_LIB_NAMES)
@@ -1206,9 +1377,9 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
 
       foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
         # library names
-        _python_get_lib_names (_${_PYTHON_PREFIX}_VERSION_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION})
+        _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY)
         list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_VERSION_NAMES})
-        _python_get_lib_names (_${_PYTHON_PREFIX}_VERSION_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION} DEBUG)
+        _python_get_names (_${_PYTHON_PREFIX}_VERSION_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG)
         list (APPEND _${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION_NAMES})
 
         # Framework Paths
@@ -1220,7 +1391,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
         list (APPEND _${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION_PATHS})
 
         # Paths suffixes
-        _python_get_path_suffixes (_${_PYTHON_PREFIX}_VERSION_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+        _python_get_path_suffixes (_${_PYTHON_PREFIX}_VERSION_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
         list (APPEND _${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_VERSION_PATHS})
       endforeach()
 
@@ -1290,7 +1461,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
         # search for debug library
         if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
           # use library location as a hint
-          _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION} DEBUG)
+          _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}
@@ -1327,13 +1498,13 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
       endif()
     else()
       foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS)
-        _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_LIB_VERSION})
-        _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_LIB_VERSION} DEBUG)
+        _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 ${_${_PYTHON_PREFIX}_LIB_VERSION})
         _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_LIB_VERSION})
 
-        _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY)
+        _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
@@ -1429,7 +1600,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
 
     # retrieve runtime libraries
     if (${_PYTHON_PREFIX}_LIBRARY_RELEASE)
-      _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES ${_${_PYTHON_PREFIX}_VERSION})
+      _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
@@ -1439,7 +1610,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
                                     PATH_SUFFIXES bin)
     endif()
     if (${_PYTHON_PREFIX}_LIBRARY_DEBUG)
-      _python_get_lib_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG ${_${_PYTHON_PREFIX}_VERSION} 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
@@ -1488,7 +1659,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
 
       _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
       _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_VERSION})
-      _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES ${_${_PYTHON_PREFIX}_VERSION} INCLUDE)
+      _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

+ 41 - 0
Modules/FindPython3.cmake

@@ -138,6 +138,47 @@ Hints
   * If set to TRUE, search **only** for static libraries.
   * If set to FALSE, search **only** for shared libraries.
 
+``Python3_FIND_ABI``
+  This variable defines which ABIs, as defined in
+  `PEP 3149 <https://www.python.org/dev/peps/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 posibilties (``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``
   This variable defines how lookup will be done.
   The ``Python3_FIND_STRATEGY`` variable can be set to empty or one of the

+ 9 - 1
Tests/FindPython/FindPythonScript.cmake

@@ -1 +1,9 @@
-find_package(${PYTHON_PACKAGE_NAME} REQUIRED QUIET)
+
+if (PYTHON_MUST_NOT_BE_FOUND)
+  find_package(${PYTHON_PACKAGE_NAME} QUIET)
+  if (${PYTHON_PACKAGE_NAME}_FOUND)
+    message(FATAL_ERROR "${PYTHON_PACKAGE_NAME}: unexpectedly founded.")
+  endif()
+else()
+  find_package(${PYTHON_PACKAGE_NAME} REQUIRED QUIET)
+endif()

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

@@ -34,4 +34,5 @@ add_test (NAME python2_spam2
 
 add_test(NAME findpython2_script
          COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python2
+         -DPython2_FIND_STRATEGY=${Python2_FIND_STRATEGY}
          -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")

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

@@ -34,4 +34,57 @@ add_test (NAME python3_spam3
 
 add_test(NAME findpython3_script
          COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+         -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+         -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+
+
+## Try a new search specifying only expected ABI
+# retrieve ABI of python interpreter
+execute_process (COMMAND "${Python3_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()
+
+# define FIND_ABI variable
+if (abi MATCHES "d")
+  set (Python3_VALID_ABI "ON")
+else()
+  set (Python3_VALID_ABI "OFF")
+endif()
+if (abi MATCHES "m")
+  list (APPEND Python3_VALID_ABI "ON")
+else()
+  list (APPEND Python3_VALID_ABI "OFF")
+endif()
+if (abi MATCHES "u")
+  list (APPEND Python3_VALID_ABI "ON")
+else()
+  list (APPEND Python3_VALID_ABI "OFF")
+endif()
+# build an invalid pattern for ABI
+set (Python3_INVALID_ABI)
+foreach (abi IN LISTS Python3_VALID_ABI)
+  if (abi)
+    list (APPEND Python3_INVALID_ABI "OFF")
+  else()
+    list (APPEND Python3_INVALID_ABI "ON")
+  endif()
+endforeach()
+
+add_test(NAME python3_find_valid_abi
+         COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+         -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+         "-DPython3_FIND_ABI=${Python3_VALID_ABI}"
+         -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")
+add_test(NAME python3_find_invalid_abi
+         COMMAND "${CMAKE_COMMAND}" -DPYTHON_PACKAGE_NAME=Python3
+         -DPYTHON_MUST_NOT_BE_FOUND=ON
+         -DPython3_FIND_STRATEGY=${Python3_FIND_STRATEGY}
+         "-DPython3_FIND_ABI=${Python3_INVALID_ABI}"
          -P "${CMAKE_CURRENT_LIST_DIR}/../FindPythonScript.cmake")