1# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2# file Copyright.txt or https://cmake.org/licensing for details.
3
4#.rst:
5# FindPythonInterp
6# ----------------
7#
8# Find python interpreter
9#
10# This module finds if Python interpreter is installed and determines
11# where the executables are.  This code sets the following variables:
12#
13# ::
14#
15#   PYTHONINTERP_FOUND         - Was the Python executable found
16#   PYTHON_EXECUTABLE          - path to the Python interpreter
17#
18#
19#
20# ::
21#
22#   PYTHON_VERSION_STRING      - Python version found e.g. 2.5.2
23#   PYTHON_VERSION_MAJOR       - Python major version found e.g. 2
24#   PYTHON_VERSION_MINOR       - Python minor version found e.g. 5
25#   PYTHON_VERSION_PATCH       - Python patch version found e.g. 2
26#
27#
28#
29# The Python_ADDITIONAL_VERSIONS variable can be used to specify a list
30# of version numbers that should be taken into account when searching
31# for Python.  You need to set this variable before calling
32# find_package(PythonInterp).
33#
34# If calling both ``find_package(PythonInterp)`` and
35# ``find_package(PythonLibs)``, call ``find_package(PythonInterp)`` first to
36# get the currently active Python version by default with a consistent version
37# of PYTHON_LIBRARIES.
38
39function(determine_python_version exe result)
40    execute_process(COMMAND "${exe}" -c
41                            "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))"
42                    OUTPUT_VARIABLE _VERSION
43                    RESULT_VARIABLE _PYTHON_VERSION_RESULT
44                    ERROR_QUIET)
45    if(_PYTHON_VERSION_RESULT)
46        # sys.version predates sys.version_info, so use that
47        execute_process(COMMAND "${exe}" -c "import sys; sys.stdout.write(sys.version)"
48                        OUTPUT_VARIABLE _VERSION
49                        RESULT_VARIABLE _PYTHON_VERSION_RESULT
50                        ERROR_QUIET)
51        if(_PYTHON_VERSION_RESULT)
52            # sys.version was first documented for Python 1.5, so assume
53            # this is older.
54            set(ver "1.4")
55        else()
56            string(REGEX REPLACE " .*" "" ver "${_VERSION}")
57        endif()
58    else()
59        string(REPLACE ";" "." ver "${_VERSION}")
60    endif()
61    set(${result} ${ver} PARENT_SCOPE)
62endfunction()
63
64# Find out if the 'python' executable on path has the correct version,
65# and choose it if it does. This gives this executable the highest
66# priority, which is expected behaviour.
67find_program(PYTHON_EXECUTABLE python)
68if(NOT (${PYTHON_EXECUTABLE} STREQUAL PYTHON_EXECUTABLE-NOTFOUND))
69  determine_python_version(${PYTHON_EXECUTABLE} ver)
70  if(${ver} VERSION_LESS PythonInterp_FIND_VERSION)
71    # We didn't find the correct version on path, so forget about it
72    # and continue looking.
73    unset(PYTHON_EXECUTABLE)
74    unset(PYTHON_EXECUTABLE CACHE)
75  endif()
76endif()
77
78unset(_Python_NAMES)
79
80set(_PYTHON1_VERSIONS 1.6 1.5)
81set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
82set(_PYTHON3_VERSIONS 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
83
84if(PythonInterp_FIND_VERSION)
85    if(PythonInterp_FIND_VERSION_COUNT GREATER 1)
86        set(_PYTHON_FIND_MAJ_MIN "${PythonInterp_FIND_VERSION_MAJOR}.${PythonInterp_FIND_VERSION_MINOR}")
87        list(APPEND _Python_NAMES
88             python${_PYTHON_FIND_MAJ_MIN}
89             python${PythonInterp_FIND_VERSION_MAJOR})
90        unset(_PYTHON_FIND_OTHER_VERSIONS)
91        if(NOT PythonInterp_FIND_VERSION_EXACT)
92            foreach(_PYTHON_V ${_PYTHON${PythonInterp_FIND_VERSION_MAJOR}_VERSIONS})
93                if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN)
94                    list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V})
95                endif()
96             endforeach()
97        endif()
98        unset(_PYTHON_FIND_MAJ_MIN)
99    else()
100        list(APPEND _Python_NAMES python${PythonInterp_FIND_VERSION_MAJOR})
101        set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonInterp_FIND_VERSION_MAJOR}_VERSIONS})
102    endif()
103else()
104    set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS})
105endif()
106find_program(PYTHON_EXECUTABLE NAMES ${_Python_NAMES})
107
108# Set up the versions we know about, in the order we will search. Always add
109# the user supplied additional versions to the front.
110set(_Python_VERSIONS ${Python_ADDITIONAL_VERSIONS})
111# If FindPythonInterp has already found the major and minor version,
112# insert that version next to get consistent versions of the interpreter and
113# library.
114if(DEFINED PYTHONLIBS_VERSION_STRING)
115  string(REPLACE "." ";" _PYTHONLIBS_VERSION "${PYTHONLIBS_VERSION_STRING}")
116  list(GET _PYTHONLIBS_VERSION 0 _PYTHONLIBS_VERSION_MAJOR)
117  list(GET _PYTHONLIBS_VERSION 1 _PYTHONLIBS_VERSION_MINOR)
118  list(APPEND _Python_VERSIONS ${_PYTHONLIBS_VERSION_MAJOR}.${_PYTHONLIBS_VERSION_MINOR})
119endif()
120
121# Search for the current active python version first on Linux, and last on Windows
122if(NOT WIN32)
123  list(APPEND _Python_VERSIONS ";")
124endif()
125
126list(APPEND _Python_VERSIONS ${_PYTHON_FIND_OTHER_VERSIONS})
127
128if(WIN32)
129  list(APPEND _Python_VERSIONS ";")
130endif()
131
132unset(_PYTHON_FIND_OTHER_VERSIONS)
133unset(_PYTHON1_VERSIONS)
134unset(_PYTHON2_VERSIONS)
135unset(_PYTHON3_VERSIONS)
136
137# Search for newest python version if python executable isn't found
138if(NOT PYTHON_EXECUTABLE)
139    foreach(_CURRENT_VERSION IN LISTS _Python_VERSIONS)
140      set(_Python_NAMES python${_CURRENT_VERSION})
141      if(WIN32)
142        list(APPEND _Python_NAMES python)
143      endif()
144
145      if(WIN32)
146          find_program(PYTHON_EXECUTABLE
147            NAMES ${_Python_NAMES}
148            HINTS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
149            )
150      endif()
151
152      find_program(PYTHON_EXECUTABLE
153        NAMES ${_Python_NAMES}
154        PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]
155        )
156    endforeach()
157endif()
158
159# determine python version string
160if(PYTHON_EXECUTABLE)
161    determine_python_version(${PYTHON_EXECUTABLE} res)
162    set(PYTHON_VERSION_STRING ${res})
163
164    if(PYTHON_VERSION_STRING MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
165      set(PYTHON_VERSION_PATCH "${CMAKE_MATCH_3}")
166    else()
167      set(PYTHON_VERSION_PATCH "0")
168    endif()
169    set(PYTHON_VERSION_MAJOR "${CMAKE_MATCH_1}")
170    set(PYTHON_VERSION_MINOR "${CMAKE_MATCH_2}")
171endif()
172
173include(FindPackageHandleStandardArgs)
174FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonInterp REQUIRED_VARS PYTHON_EXECUTABLE VERSION_VAR PYTHON_VERSION_STRING)
175
176mark_as_advanced(PYTHON_EXECUTABLE)
177