Use CMake 3.12+ facilities for detecting Python.
authorM. Eric Irrgang <mei2n@virginia.edu>
Thu, 23 Apr 2020 14:43:55 +0000 (14:43 +0000)
committerM. Eric Irrgang <mei2n@virginia.edu>
Thu, 23 Apr 2020 14:43:55 +0000 (14:43 +0000)
Consolidate Python detection in the main CMakeLists.txt before the
first usage in a subdirectory. Use FindPython3.cmake instead of
FindPythonInterp.cmake. Populate the legacy PYTHON_EXECUTABLE variable
for compatibility.

Fixes #2998

CMakeLists.txt
cmake/FindPythonModule.cmake
cmake/gmxPythonDiscovery.cmake [new file with mode: 0644]
cmake/gmxVersionInfo.cmake
docs/CMakeLists.txt
docs/doxygen/CMakeLists.txt
docs/gmxapi/userguide/install.rst
docs/release-notes/2021/major/portability.rst
python_packaging/CMakeLists.txt
tests/CMakeLists.txt

index 64fb2f5079d857c17c04475136c4d6e366a88b20..1443c44094e932a180cefca7dab74579c88f9a47 100644 (file)
@@ -68,6 +68,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
 
 find_package(LibStdCpp)
 
 
 find_package(LibStdCpp)
 
+# Python is first referenced in gmxVersionInfo, so we perform the search early
+# to find a suitable installation for all components.
+include(gmxPythonDiscovery)
 # Set up common version variables, as well as general information about
 # the build tree (whether the build is from a source package or from a git
 # repository).  Also declares a few functions that will be used for generating
 # Set up common version variables, as well as general information about
 # the build tree (whether the build is from a source package or from a git
 # repository).  Also declares a few functions that will be used for generating
@@ -840,25 +843,6 @@ option(GMX_PYTHON_PACKAGE "Configure gmxapi Python package" OFF)
 mark_as_advanced(GMX_PYTHON_PACKAGE)
 
 if (NOT GMX_BUILD_MDRUN_ONLY)
 mark_as_advanced(GMX_PYTHON_PACKAGE)
 
 if (NOT GMX_BUILD_MDRUN_ONLY)
-    # Note: Though only documented as an output variable, PYTHON_EXECUTABLE is
-    # also effective as a CMake input variable to effectively hint the location
-    # of the Python interpreter. This may be helpful in environments with both
-    # Python 2 and Python 3 on the default PATH.
-    # Ref: https://cmake.org/cmake/help/latest/module/FindPythonInterp.html
-    if(FIND_PACKAGE_MESSAGE_DETAILS_PythonInterp)
-        # Keep quiet on subsequent runs of cmake
-        set(PythonInterp_FIND_QUIETLY ON)
-    endif()
-    # Older CMake versions might not search for Python newer than 3.7.
-    set(Python_ADDITIONAL_VERSIONS 3.8)
-    if(GMX_PYTHON_PACKAGE)
-        find_package(PythonInterp 3.6 REQUIRED)
-        # Note: PythonLibs will be found later by pybind11.
-        # TODO: (Issue #2998) When CMake >= 3.12 is required, update detection.
-        # I.e.  find_package(Python3 3.6 COMPONENTS Interpreter Development REQUIRED)
-    else()
-        find_package(PythonInterp 3.6)
-    endif()
     find_package(ImageMagick QUIET COMPONENTS convert)
     include(gmxTestImageMagick)
     GMX_TEST_IMAGEMAGICK(IMAGE_CONVERT_POSSIBLE)
     find_package(ImageMagick QUIET COMPONENTS convert)
     include(gmxTestImageMagick)
     GMX_TEST_IMAGEMAGICK(IMAGE_CONVERT_POSSIBLE)
index 8fbac87163b9c33160156f949f02b2964f3fa183..a5328dd8b8e379b80bfa4887f4bf7aa79dfb6734 100644 (file)
@@ -34,7 +34,6 @@
 
 # Adapted from code posted on cmake-users by Mark Moll (the execute_process()
 # call remains, but other things have been rewritten for nicer behavior).
 
 # Adapted from code posted on cmake-users by Mark Moll (the execute_process()
 # call remains, but other things have been rewritten for nicer behavior).
-find_package(PythonInterp 3.6)
 
 function (find_python_module module)
     string(TOUPPER ${module} _module_upper)
 
 function (find_python_module module)
     string(TOUPPER ${module} _module_upper)
diff --git a/cmake/gmxPythonDiscovery.cmake b/cmake/gmxPythonDiscovery.cmake
new file mode 100644 (file)
index 0000000..21a1743
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2020, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+# Perform Python installation discovery early and in one place, for consistency.
+#
+# Note: If necessary, the Python location can be hinted with Python3_ROOT_DIR
+# For additional parameters affecting Python installation discovery, see
+# https://cmake.org/cmake/help/latest/module/FindPython3.html#hints
+if(FIND_PACKAGE_MESSAGE_DETAILS_Python3)
+    # Keep quiet on subsequent runs of cmake
+    set(Python3_FIND_QUIETLY ON)
+    set(PythonInterp_FIND_QUIETLY ON)
+endif()
+# Older CMake versions might not search for Python newer than 3.7.
+set(Python_ADDITIONAL_VERSIONS 3.8)
+# We advocate using Python venvs to manage package availability, so by default
+# we want to preferentially discover user-space software.
+set(Python3_FIND_REGISTRY LAST)
+# Make package discovery consistent with Unix behavior and our documented
+# suggestions for installing dependencies.
+set(CMAKE_FIND_FRAMEWORK LAST)
+if(GMX_PYTHON_PACKAGE)
+    find_package(Python3 3.6 COMPONENTS Interpreter Development)
+    if (NOT Python3_FOUND OR NOT Python3_Development_FOUND)
+        message(FATAL_ERROR "Could not locate Python development requirements. \
+                Provide appropriate CMake hints or set GMX_PYTHON_PACKAGE=OFF")
+    endif ()
+else()
+    find_package(Python3 3.6 COMPONENTS Interpreter)
+endif()
+# Other components, such as pybind and googletest, may expect the
+# PYTHON_EXECUTABLE variable from pre-3.12 FindPythonInterp.cmake.
+if (Python3_Interpreter_FOUND)
+    set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE FILEPATH "Location hint for Python interpreter.")
+endif ()
+# We've already generated all of the output we need, even though other subcomponents
+# may call find_package(PythonInterp) later on.
+set(Python3_FIND_QUIETLY ON)
+set(PythonInterp_FIND_QUIETLY ON)
index 7a2b56344e731ffcff230cd8b0738c6040034ead..136b8893c8fbfb82df19c3762ac59fdb9a62a5e5 100644 (file)
@@ -337,9 +337,6 @@ set(SET_OF_DIRECTORIES_TO_CHECKSUM  "${PROJECT_SOURCE_DIR}/src")
 list(APPEND SET_OF_DIRECTORIES_TO_CHECKSUM "${PROJECT_SOURCE_DIR}/python_packaging")
 # Due to the limitations for passing a list as arguments, we make the directories a string here
 string(REPLACE ";" ":" DIRECTORIES_TO_CHECKSUM_STRING "${SET_OF_DIRECTORIES_TO_CHECKSUM}")
 list(APPEND SET_OF_DIRECTORIES_TO_CHECKSUM "${PROJECT_SOURCE_DIR}/python_packaging")
 # Due to the limitations for passing a list as arguments, we make the directories a string here
 string(REPLACE ";" ":" DIRECTORIES_TO_CHECKSUM_STRING "${SET_OF_DIRECTORIES_TO_CHECKSUM}")
-# Try to find python for the checksumming script
-set(PythonInterp_FIND_QUIETLY ON)
-find_package(PythonInterp 3.6)
 
 # Rules to create the VersionInfo.cmake file.
 # For git info, the sequence is:
 
 # Rules to create the VersionInfo.cmake file.
 # For git info, the sequence is:
@@ -437,7 +434,7 @@ set(CHECKSUM_FILE "${PROJECT_SOURCE_DIR}/src/reference_checksum")
 # not been tampered with.
 # Note: The RUN_ALWAYS here is to regenerate the hash file only, it does not
 # mean that the target is run in all builds
 # not been tampered with.
 # Note: The RUN_ALWAYS here is to regenerate the hash file only, it does not
 # mean that the target is run in all builds
-if (PYTHONINTERP_FOUND)
+if (PYTHON_EXECUTABLE)
     gmx_add_custom_output_target(reference_checksum RUN_ALWAYS
         OUTPUT ${CHECKSUM_FILE}
         COMMAND ${PYTHON_EXECUTABLE}
     gmx_add_custom_output_target(reference_checksum RUN_ALWAYS
         OUTPUT ${CHECKSUM_FILE}
         COMMAND ${PYTHON_EXECUTABLE}
index ee70c62f979ecd52e97aace051fcbcfb288a86ad..3d8ce9b2e0dea083010a4501d2473abaced3c19d 100644 (file)
@@ -704,7 +704,7 @@ set(HTML_BUILD_NOT_POSSIBLE_REASON)
 set(HTML_BUILD_WARNINGS)
 
 # Next, turn it off if any of the preconditions are unsatisified
 set(HTML_BUILD_WARNINGS)
 
 # Next, turn it off if any of the preconditions are unsatisified
-if (NOT PythonInterp_FOUND)
+if (NOT Python3_Interpreter_FOUND)
     set(HTML_BUILD_IS_POSSIBLE OFF)
     set(HTML_BUILD_NOT_POSSIBLE_REASON "Python is required")
 elseif (NOT SPHINX_FOUND)
     set(HTML_BUILD_IS_POSSIBLE OFF)
     set(HTML_BUILD_NOT_POSSIBLE_REASON "Python is required")
 elseif (NOT SPHINX_FOUND)
index 91ba04eaf9d170a6da1680e7480b0a4efbf61c80..0625ecb04d2a107e55ac6c564055929a6328a6c3 100644 (file)
@@ -58,7 +58,7 @@ gmx_dependent_option(
 mark_as_advanced(GMX_COMPACT_DOXYGEN)
 
 set(USE_PYTHON_SCRIPTS OFF)
 mark_as_advanced(GMX_COMPACT_DOXYGEN)
 
 set(USE_PYTHON_SCRIPTS OFF)
-if (PYTHONINTERP_FOUND)
+if (PYTHON_EXECUTABLE)
     set(USE_PYTHON_SCRIPTS ON)
 endif()
 
     set(USE_PYTHON_SCRIPTS ON)
 endif()
 
index adfe44938cfeadb8c179131b0a740815c2964ab1..a696c11e5ccbc101fa9ccc3e17d8425afde0da35 100644 (file)
@@ -483,9 +483,14 @@ extract Python docstrings.
 
 Sometimes the build environment can choose a different Python interpreter than
 the one you intended.
 
 Sometimes the build environment can choose a different Python interpreter than
 the one you intended.
-You can set the ``PYTHON_EXECUTABLE`` CMake variable to explicitly choose the
-Python interpreter for your chosen installation.
-For example: ``-DPYTHON_EXECUTABLE=\`which python\```
+You can set the ``Python3_ROOT`` or ``CMAKE_PREFIX_PATH`` CMake variable to
+explicitly choose the Python installation or *venv* directory.
+
+If you use pyenv or pyenv-virtualenv to dynamically manage your Python version,
+you can help identify a particular version with ``pyenv version-name`` and the
+directory with ``pyenv prefix {version}``. For example::
+
+    -DPython3_ROOT=$(pyenv prefix $(pyenv version-name))
 
 Docker web server
 -----------------
 
 Docker web server
 -----------------
index fdcf01640e44b6574f24c702778cbbedf4f4124a..36940a8833e90bb9e3d9ab571b8cc2b2f25046fa 100644 (file)
@@ -1,12 +1,20 @@
 Portability
 ^^^^^^^^^^^
 
 Portability
 ^^^^^^^^^^^
 
-Supported Python versions
-"""""""""""""""""""""""""
+Python environment
+""""""""""""""""""
 
 Where Python is required,
 `CPython <https://www.python.org>`__ versions 3.6 to 3.8 are supported.
 
 
 Where Python is required,
 `CPython <https://www.python.org>`__ versions 3.6 to 3.8 are supported.
 
+CMake now detects Python using
+`FindPython3 <https://cmake.org/cmake/help/v3.13/module/FindPython3.html>`__.
+If you previously used ``PYTHON_EXECUTABLE`` to hint the location of the Python
+interpreter, you should instead specify the Python "root" or "prefix" path
+(the directory containing ``./bin/python3``) with CMake variable
+``Python3_ROOT`` or ``CMAKE_PREFIX_PATH``. As other infrastructure evolves,
+``PYTHON_EXECUTABLE`` may cease to have the desired effect without warning.
+
 .. Note to developers!
    Please use """"""" to underline the individual entries for fixed issues in the subfolders,
    otherwise the formatting on the webpage is messed up.
 .. Note to developers!
    Please use """"""" to underline the individual entries for fixed issues in the subfolders,
    otherwise the formatting on the webpage is messed up.
index 8bf657337407ce1a640f447a74cbf3e6cef7160e..6d0e7212e9119385ce0dd00863f48cb43fdf10d1 100644 (file)
@@ -1,7 +1,7 @@
 #
 # This file is part of the GROMACS molecular simulation package.
 #
 #
 # This file is part of the GROMACS molecular simulation package.
 #
-# Copyright (c) 2019, by the GROMACS development team, led by
+# Copyright (c) 2019,2020, by the GROMACS development team, led by
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
 # and including many others, as listed in the AUTHORS file in the
 # top-level source directory and at http://www.gromacs.org.
 # (system or user) GROMACS installation and (user) Python environment. For a
 # system-wide Python environment, the package needs to be built and installed
 # (to the ``site-packages`` directory) for each supported Python interpreter.
 # (system or user) GROMACS installation and (user) Python environment. For a
 # system-wide Python environment, the package needs to be built and installed
 # (to the ``site-packages`` directory) for each supported Python interpreter.
-# ``setup.py`` can just be invoked with different Python interpreters. We can
-# add CMake infrastructure to allow multiple/repeated PYTHON_EXECUTABLE
-# specification at the GROMACS project level if such a use case is important to
-# HPC site administrators or Linux distribution packagers.
+# ``setup.py`` can just be invoked with different Python interpreters.
 #
 # To drive the packaging of a Python package distribution archive
 # by a higher-level CMake configuration, a CMakeLists.txt file at this level would
 #
 # To drive the packaging of a Python package distribution archive
 # by a higher-level CMake configuration, a CMakeLists.txt file at this level would
index 051d6d9686582db13cace85523c1f28aab9eb801..e8b65a3ed88028f8fef71d73d0b7883a45b816bd 100644 (file)
@@ -290,10 +290,10 @@ if(GMX_PHYSICAL_VALIDATION)
         # End copied from regression tests.
         #
 
         # End copied from regression tests.
         #
 
-        if (NOT PYTHONINTERP_FOUND)
+        if (NOT Python3_Interpreter_FOUND)
             message(FATAL_ERROR
                     "Python not found. Physical validation requires python. \
             message(FATAL_ERROR
                     "Python not found. Physical validation requires python. \
-                     Install python, set PYTHON_EXECUTABLE to a valid python location, \
+                     Install python, set Python3_ROOT_DIR or PYTHON_EXECUTABLE to a valid location, \
                      or set GMX_PHYSICAL_VALIDATION=OFF to disable the physical validation tests.")
         endif()
         #
                      or set GMX_PHYSICAL_VALIDATION=OFF to disable the physical validation tests.")
         endif()
         #