summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2019-04-01 11:19:54 +0200
committerMarc Chevrier <marc.chevrier@gmail.com>2019-04-03 09:16:17 +0200
commit8a2f62cc18ece0ebfed0ff6abf53d419d43d2fa1 (patch)
tree465c79b4ce0f366fe40a00e1be9e965f3c04af4d
parent5ad73b608d4fc7cc6b30017159b800802a503b0c (diff)
downloadcmake-8a2f62cc18ece0ebfed0ff6abf53d419d43d2fa1.tar.gz
FindPython*: Add capability to control virtual env handling.
Fixes: #19097
-rw-r--r--Help/release/dev/FindPython-virtual-env.rst5
-rw-r--r--Modules/FindPython.cmake22
-rw-r--r--Modules/FindPython/Support.cmake65
-rw-r--r--Modules/FindPython2.cmake20
-rw-r--r--Modules/FindPython3.cmake24
-rw-r--r--Tests/FindPython/CMakeLists.txt11
-rw-r--r--Tests/FindPython/VirtualEnv/CMakeLists.txt42
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake6
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake16
-rw-r--r--Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake7
10 files changed, 198 insertions, 20 deletions
diff --git a/Help/release/dev/FindPython-virtual-env.rst b/Help/release/dev/FindPython-virtual-env.rst
new file mode 100644
index 0000000000..5489dc28b1
--- /dev/null
+++ b/Help/release/dev/FindPython-virtual-env.rst
@@ -0,0 +1,5 @@
+FindPython-virtual-env
+----------------------
+
+* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython`
+ gain capability to control how virtual environments are handled.
diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake
index 1c134e278b..c5074e8b3d 100644
--- a/Modules/FindPython.cmake
+++ b/Modules/FindPython.cmake
@@ -145,18 +145,30 @@ Hints
* ``NEVER``: Never try to use registry.
``CMAKE_FIND_FRAMEWORK``
- On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+ On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
preference between Apple-style and unix-style package components.
.. note::
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+``Python_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ only when a virtual environment is active (i.e. the ``activate`` script has
+ been evaluated). In this case, it takes precedence over
+ ``Python_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+ The ``Python_FIND_VIRTUALENV`` variable can be set to empty or one of the
+ following:
- 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.
+ * ``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. In this case, variable ``Python_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.
Commands
^^^^^^^^
diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake
index 1236bf8f86..0868989df4 100644
--- a/Modules/FindPython/Support.cmake
+++ b/Modules/FindPython/Support.cmake
@@ -298,6 +298,22 @@ else()
set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST")
endif()
+# virtual environments handling
+if (DEFINED ENV{VIRTUAL_ENV})
+ 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 'IGNORE' expected.")
+ 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()
+
unset (_${_PYTHON_PREFIX}_REQUIRED_VARS)
unset (_${_PYTHON_PREFIX}_CACHED_VARS)
@@ -318,6 +334,30 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
_python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION})
+ # Virtual environments handling
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
+ find_program (${_PYTHON_PREFIX}_EXECUTABLE
+ NAMES python${_${_PYTHON_PREFIX}_VERSION}
+ python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}
+ python
+ NAMES_PER_DIR
+ HINTS ${_${_PYTHON_PREFIX}_HINTS}
+ PATHS ENV VIRTUAL_ENV
+ PATH_SUFFIXES bin Scripts
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ NO_SYSTEM_ENVIRONMENT_PATH
+ NO_CMAKE_SYSTEM_PATH)
+
+ _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION})
+ if (${_PYTHON_PREFIX}_EXECUTABLE)
+ break()
+ endif()
+ if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
+ continue()
+ endif()
+ endif()
+
# Apple frameworks handling
if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST")
find_program (${_PYTHON_PREFIX}_EXECUTABLE
@@ -423,7 +463,8 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS)
endif()
endforeach()
- if (NOT ${_PYTHON_PREFIX}_EXECUTABLE)
+ if (NOT ${_PYTHON_PREFIX}_EXECUTABLE AND
+ NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY")
# No specific version found. Retry with generic names
# try using HINTS
find_program (${_PYTHON_PREFIX}_EXECUTABLE
@@ -685,18 +726,32 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS
# if python interpreter is found, use its location and version to ensure consistency
# between interpreter and development environment
unset (_${_PYTHON_PREFIX}_PREFIX)
+ unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
+ unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
if (${_PYTHON_PREFIX}_Interpreter_FOUND)
execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
- "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.PREFIX)"
+ "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.EXEC_PREFIX)"
RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
- OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_EXEC_PREFIX
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (_${_PYTHON_PREFIX}_RESULT)
- unset (_${_PYTHON_PREFIX}_PREFIX)
+ unset (_${_PYTHON_PREFIX}_EXEC_PREFIX)
+ endif()
+
+ if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "STANDARD")
+ execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c
+ "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.BASE_EXEC_PREFIX)"
+ RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT
+ OUTPUT_VARIABLE _${_PYTHON_PREFIX}_BASE_EXEC_PREFIX
+ ERROR_QUIET
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ if (_${_PYTHON_PREFIX}_RESULT)
+ unset (_${_PYTHON_PREFIX}_BASE_EXEC_PREFIX)
+ endif()
endif()
endif()
- set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR)
+ set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_EXEC_PREFIX}" "${_${_PYTHON_PREFIX}_BASE_EXEC_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})
diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake
index b9c0b6b739..a2be84fee5 100644
--- a/Modules/FindPython2.cmake
+++ b/Modules/FindPython2.cmake
@@ -153,11 +153,23 @@ Hints
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+``Python2_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ only when a virtual environment is active (i.e. the ``activate`` script has
+ been evaluated). In this case, it takes precedence over
+ ``Python2_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables.
+ The ``Python2_FIND_VIRTUALENV`` variable can be set to empty or one of the
+ following:
- 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.
+ * ``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. In this case, variable ``Python2_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.
Commands
^^^^^^^^
diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake
index c2f3384697..3409554580 100644
--- a/Modules/FindPython3.cmake
+++ b/Modules/FindPython3.cmake
@@ -137,7 +137,7 @@ Hints
``Python3_FIND_REGISTRY``
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
+ The ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the
following:
* ``FIRST``: Try to use registry before environment variables.
@@ -146,18 +146,30 @@ Hints
* ``NEVER``: Never try to use registry.
``CMAKE_FIND_FRAMEWORK``
- On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
+ On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of
preference between Apple-style and unix-style package components.
.. note::
Value ``ONLY`` is not supported so ``FIRST`` will be used instead.
-.. note::
+``Python3_FIND_VIRTUALENV``
+ This variable defines the handling of virtual environments. It is meaningfull
+ 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 empty or one of the
+ following:
- 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.
+ * ``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. 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.
Commands
^^^^^^^^
diff --git a/Tests/FindPython/CMakeLists.txt b/Tests/FindPython/CMakeLists.txt
index 38211a4bb5..d6f50e7b10 100644
--- a/Tests/FindPython/CMakeLists.txt
+++ b/Tests/FindPython/CMakeLists.txt
@@ -68,6 +68,17 @@ if(CMake_TEST_FindPython)
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
+
+ add_test(NAME FindPython.VirtualEnv COMMAND
+ ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
+ --build-and-test
+ "${CMake_SOURCE_DIR}/Tests/FindPython/VirtualEnv"
+ "${CMake_BINARY_DIR}/Tests/FindPython/VirtualEnv"
+ ${build_generator_args}
+ --build-project TestVirtualEnv
+ --build-options ${build_options}
+ --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
+ )
endif()
if(CMake_TEST_FindPython_NumPy)
diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt
new file mode 100644
index 0000000000..64ba201861
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(TestVirtualEnv LANGUAGES NONE)
+
+include(CTest)
+
+find_package(Python3 REQUIRED COMPONENTS Interpreter)
+if (NOT Python3_FOUND)
+ message (FATAL_ERROR "Fail to found Python 3")
+endif()
+
+set (Python3_VIRTUAL_ENV "${CMAKE_CURRENT_BINARY_DIR}/py3venv")
+
+execute_process (COMMAND "${Python3_EXECUTABLE}" -m venv "${Python3_VIRTUAL_ENV}"
+ RESULT_VARIABLE result
+ OUTPUT_VARIABLE outputs
+ ERROR_VARIABLE outputs)
+if (result)
+ message (FATAL_ERROR "Fail to create virtual environment: ${outputs}")
+endif()
+
+add_test(NAME FindPython3.VirtualEnvDefault
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvDefault.cmake")
+
+add_test(NAME FindPython3.VirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+add_test(NAME FindPython3.UnsetVirtualEnvOnly
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ --unset=VIRTUAL_ENV
+ "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvOnly.cmake")
+
+add_test(NAME FindPython3.VirtualEnvStandard
+ COMMAND "${CMAKE_COMMAND}" -E env --unset=PYTHONHOME
+ "VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ "${CMAKE_COMMAND}" "-DPYTHON3_VIRTUAL_ENV=${Python3_VIRTUAL_ENV}"
+ -P "${CMAKE_CURRENT_LIST_DIR}/VirtualEnvStandard.cmake")
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
new file mode 100644
index 0000000000..020ecacd9d
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvDefault.cmake
@@ -0,0 +1,6 @@
+
+find_package (Python3 REQUIRED)
+
+if (NOT Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Fail to use virtual environment")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
new file mode 100644
index 0000000000..29a49249cb
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvOnly.cmake
@@ -0,0 +1,16 @@
+
+#
+# Virtual environment is defined for python3
+# Trying to find a python2 using only virtual environment
+# It is expecting to fail if a virtual environment is active and to success otherwise.
+#
+set (Python2_FIND_VIRTUALENV ONLY)
+find_package (Python2 QUIET)
+
+if (PYTHON3_VIRTUAL_ENV AND Python2_FOUND)
+ message (FATAL_ERROR "Python2 unexpectedly found.")
+endif()
+
+if (NOT PYTHON3_VIRTUAL_ENV AND NOT Python2_FOUND)
+ message (FATAL_ERROR "Fail to find Python2.")
+endif()
diff --git a/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
new file mode 100644
index 0000000000..89f27d8da2
--- /dev/null
+++ b/Tests/FindPython/VirtualEnv/VirtualEnvStandard.cmake
@@ -0,0 +1,7 @@
+
+set (Python3_FIND_VIRTUALENV STANDARD)
+find_package (Python3 REQUIRED)
+
+if (Python3_EXECUTABLE MATCHES "^${PYTHON3_VIRTUAL_ENV}/.+")
+ message (FATAL_ERROR "Python3 virtual env unexpectedly found.")
+endif()