1# Find specified Python version
2# Arguments:
3#   preferred_version (value): Version to check for first
4#   min_version (value): Minimum supported version
5#   library_env (value): Name of Python library ENV variable to check
6#   include_dir_env (value): Name of Python include directory ENV variable to check
7#   found (variable): Set if interpreter found
8#   executable (variable): Output of executable found
9#   version_string (variable): Output of found version
10#   version_major (variable): Output of found major version
11#   version_minor (variable): Output of found minor version
12#   libs_found (variable): Set if libs found
13#   libs_version_string (variable): Output of found libs version
14#   libraries (variable): Output of found Python libraries
15#   library (variable): Output of found Python library
16#   debug_libraries (variable): Output of found Python debug libraries
17#   debug_library (variable): Output of found Python debug library
18#   include_path (variable): Output of found Python include path
19#   include_dir (variable): Output of found Python include dir
20#   include_dir2 (variable): Output of found Python include dir2
21#   packages_path (variable): Output of found Python packages path
22#   numpy_include_dirs (variable): Output of found Python Numpy include dirs
23#   numpy_version (variable): Output of found Python Numpy version
24function(find_python preferred_version min_version library_env include_dir_env
25         found executable version_string version_major version_minor
26         libs_found libs_version_string libraries library debug_libraries
27         debug_library include_path include_dir include_dir2 packages_path
28         numpy_include_dirs numpy_version)
29
30  ocv_check_environment_variables(${executable})
31  if(${executable})
32    set(PYTHON_EXECUTABLE "${${executable}}")
33  endif()
34
35  if(WIN32 AND NOT ${executable})
36    # search for executable with the same bitness as resulting binaries
37    # standard FindPythonInterp always prefers executable from system path
38    # this is really important because we are using the interpreter for numpy search and for choosing the install location
39    foreach(_CURRENT_VERSION ${Python_ADDITIONAL_VERSIONS} "${preferred_version}" "${min_version}")
40      find_host_program(PYTHON_EXECUTABLE
41        NAMES python${_CURRENT_VERSION} python
42        PATHS
43          [HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${_CURRENT_VERSION}\\\\InstallPath]
44          [HKEY_CURRENT_USER\\\\SOFTWARE\\\\Python\\\\PythonCore\\\\${_CURRENT_VERSION}\\\\InstallPath]
45        NO_SYSTEM_ENVIRONMENT_PATH
46      )
47    endforeach()
48  endif()
49
50  find_host_package(PythonInterp "${preferred_version}")
51  if(NOT PYTHONINTERP_FOUND)
52    find_host_package(PythonInterp "${min_version}")
53  endif()
54
55  if(PYTHONINTERP_FOUND)
56    # Copy outputs
57    set(_found ${PYTHONINTERP_FOUND})
58    set(_executable ${PYTHON_EXECUTABLE})
59    set(_version_string ${PYTHON_VERSION_STRING})
60    set(_version_major ${PYTHON_VERSION_MAJOR})
61    set(_version_minor ${PYTHON_VERSION_MINOR})
62    set(_version_patch ${PYTHON_VERSION_PATCH})
63
64    # Clear find_host_package side effects
65    unset(PYTHONINTERP_FOUND)
66    unset(PYTHON_EXECUTABLE CACHE)
67    unset(PYTHON_VERSION_STRING)
68    unset(PYTHON_VERSION_MAJOR)
69    unset(PYTHON_VERSION_MINOR)
70    unset(PYTHON_VERSION_PATCH)
71  endif()
72
73  if(_found)
74    set(_version_major_minor "${_version_major}.${_version_minor}")
75
76    if(NOT ANDROID AND NOT IOS)
77      ocv_check_environment_variables(${library_env} ${include_dir_env})
78      if(NOT ${${library_env}} EQUAL "")
79          set(PYTHON_LIBRARY "${${library_env}}")
80      endif()
81      if(NOT ${${include_dir_env}} EQUAL "")
82          set(PYTHON_INCLUDE_DIR "${${include_dir_env}}")
83      endif()
84
85      # not using _version_string here, because it might not conform to the CMake version format
86      if(CMAKE_CROSSCOMPILING)
87        # builder version can differ from target, matching base version (e.g. 2.7)
88        find_host_package(PythonLibs "${_version_major_minor}")
89      else()
90        find_host_package(PythonLibs "${_version_major_minor}.${_version_patch}" EXACT)
91      endif()
92
93      if(PYTHONLIBS_FOUND)
94        # Copy outputs
95        set(_libs_found ${PYTHONLIBS_FOUND})
96        set(_libraries ${PYTHON_LIBRARIES})
97        set(_include_path ${PYTHON_INCLUDE_PATH})
98        set(_include_dirs ${PYTHON_INCLUDE_DIRS})
99        set(_debug_libraries ${PYTHON_DEBUG_LIBRARIES})
100        set(_libs_version_string ${PYTHONLIBS_VERSION_STRING})
101        set(_debug_library ${PYTHON_DEBUG_LIBRARY})
102        set(_library ${PYTHON_LIBRARY})
103        set(_library_debug ${PYTHON_LIBRARY_DEBUG})
104        set(_library_release ${PYTHON_LIBRARY_RELEASE})
105        set(_include_dir ${PYTHON_INCLUDE_DIR})
106        set(_include_dir2 ${PYTHON_INCLUDE_DIR2})
107
108        # Clear find_host_package side effects
109        unset(PYTHONLIBS_FOUND)
110        unset(PYTHON_LIBRARIES)
111        unset(PYTHON_INCLUDE_PATH)
112        unset(PYTHON_INCLUDE_DIRS)
113        unset(PYTHON_DEBUG_LIBRARIES)
114        unset(PYTHONLIBS_VERSION_STRING)
115        unset(PYTHON_DEBUG_LIBRARY CACHE)
116        unset(PYTHON_LIBRARY)
117        unset(PYTHON_LIBRARY_DEBUG)
118        unset(PYTHON_LIBRARY_RELEASE)
119        unset(PYTHON_LIBRARY CACHE)
120        unset(PYTHON_LIBRARY_DEBUG CACHE)
121        unset(PYTHON_LIBRARY_RELEASE CACHE)
122        unset(PYTHON_INCLUDE_DIR CACHE)
123        unset(PYTHON_INCLUDE_DIR2 CACHE)
124      endif()
125    endif()
126
127    if(NOT ANDROID AND NOT IOS)
128      if(CMAKE_HOST_UNIX)
129        execute_process(COMMAND ${_executable} -c "from distutils.sysconfig import *; print(get_python_lib())"
130                        RESULT_VARIABLE _cvpy_process
131                        OUTPUT_VARIABLE _std_packages_path
132                        OUTPUT_STRIP_TRAILING_WHITESPACE)
133        if("${_std_packages_path}" MATCHES "site-packages")
134          set(_packages_path "python${_version_major_minor}/site-packages")
135        else() #debian based assumed, install to the dist-packages.
136          set(_packages_path "python${_version_major_minor}/dist-packages")
137        endif()
138        if(EXISTS "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/${${packages_path}}")
139          set(_packages_path "lib${LIB_SUFFIX}/${_packages_path}")
140        else()
141          set(_packages_path "lib/${_packages_path}")
142        endif()
143      elseif(CMAKE_HOST_WIN32)
144        get_filename_component(_path "${_executable}" PATH)
145        file(TO_CMAKE_PATH "${_path}" _path)
146        if(NOT EXISTS "${_path}/Lib/site-packages")
147          unset(_path)
148          get_filename_component(_path "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_version_major_minor}\\InstallPath]" ABSOLUTE)
149          if(NOT _path)
150             get_filename_component(_path "[HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_version_major_minor}\\InstallPath]" ABSOLUTE)
151          endif()
152          file(TO_CMAKE_PATH "${_path}" _path)
153        endif()
154        set(_packages_path "${_path}/Lib/site-packages")
155        unset(_path)
156      endif()
157
158      set(_numpy_include_dirs ${${numpy_include_dirs}})
159
160      if(NOT _numpy_include_dirs)
161        if(CMAKE_CROSSCOMPILING)
162          message(STATUS "Cannot probe for Python/Numpy support (because we are cross-compiling OpenCV)")
163          message(STATUS "If you want to enable Python/Numpy support, set the following variables:")
164          message(STATUS "  PYTHON2_INCLUDE_PATH")
165          message(STATUS "  PYTHON2_LIBRARIES")
166          message(STATUS "  PYTHON2_NUMPY_INCLUDE_DIRS")
167          message(STATUS "  PYTHON3_INCLUDE_PATH")
168          message(STATUS "  PYTHON3_LIBRARIES")
169          message(STATUS "  PYTHON3_NUMPY_INCLUDE_DIRS")
170        else()
171          # Attempt to discover the NumPy include directory. If this succeeds, then build python API with NumPy
172          execute_process(COMMAND "${_executable}" -c "import os; os.environ['DISTUTILS_USE_SDK']='1'; import numpy.distutils; print(os.pathsep.join(numpy.distutils.misc_util.get_numpy_include_dirs()))"
173                          RESULT_VARIABLE _numpy_process
174                          OUTPUT_VARIABLE _numpy_include_dirs
175                          OUTPUT_STRIP_TRAILING_WHITESPACE)
176
177          if(NOT _numpy_process EQUAL 0)
178              unset(_numpy_include_dirs)
179          endif()
180        endif()
181      endif()
182
183      if(_numpy_include_dirs)
184        file(TO_CMAKE_PATH "${_numpy_include_dirs}" _numpy_include_dirs)
185        if(CMAKE_CROSSCOMPILING)
186          if(NOT _numpy_version)
187            set(_numpy_version "undefined - cannot be probed because of the cross-compilation")
188          endif()
189        else()
190          execute_process(COMMAND "${_executable}" -c "import numpy; print(numpy.version.version)"
191                          RESULT_VARIABLE _numpy_process
192                          OUTPUT_VARIABLE _numpy_version
193                          OUTPUT_STRIP_TRAILING_WHITESPACE)
194        endif()
195      endif()
196    endif(NOT ANDROID AND NOT IOS)
197  endif()
198
199  # Export return values
200  set(${found} "${_found}" PARENT_SCOPE)
201  set(${executable} "${_executable}" CACHE FILEPATH "Path to Python interpretor")
202  set(${version_string} "${_version_string}" PARENT_SCOPE)
203  set(${version_major} "${_version_major}" PARENT_SCOPE)
204  set(${version_minor} "${_version_minor}" PARENT_SCOPE)
205  set(${libs_found} "${_libs_found}" PARENT_SCOPE)
206  set(${libs_version_string} "${_libs_version_string}" PARENT_SCOPE)
207  set(${libraries} "${_libraries}" PARENT_SCOPE)
208  set(${library} "${_library}" CACHE FILEPATH "Path to Python library")
209  set(${debug_libraries} "${_debug_libraries}" PARENT_SCOPE)
210  set(${debug_library} "${_debug_library}" CACHE FILEPATH "Path to Python debug")
211  set(${include_path} "${_include_path}" PARENT_SCOPE)
212  set(${include_dir} "${_include_dir}" CACHE PATH "Python include dir")
213  set(${include_dir2} "${_include_dir2}" CACHE PATH "Python include dir 2")
214  set(${packages_path} "${_packages_path}" CACHE PATH "Where to install the python packages.")
215  set(${numpy_include_dirs} ${_numpy_include_dirs} CACHE PATH "Path to numpy headers")
216  set(${numpy_version} "${_numpy_version}" PARENT_SCOPE)
217endfunction(find_python)
218
219find_python(2.7 "${MIN_VER_PYTHON2}" PYTHON2_LIBRARY PYTHON2_INCLUDE_DIR
220    PYTHON2INTERP_FOUND PYTHON2_EXECUTABLE PYTHON2_VERSION_STRING
221    PYTHON2_VERSION_MAJOR PYTHON2_VERSION_MINOR PYTHON2LIBS_FOUND
222    PYTHON2LIBS_VERSION_STRING PYTHON2_LIBRARIES PYTHON2_LIBRARY
223    PYTHON2_DEBUG_LIBRARIES PYTHON2_LIBRARY_DEBUG PYTHON2_INCLUDE_PATH
224    PYTHON2_INCLUDE_DIR PYTHON2_INCLUDE_DIR2 PYTHON2_PACKAGES_PATH
225    PYTHON2_NUMPY_INCLUDE_DIRS PYTHON2_NUMPY_VERSION)
226
227find_python(3.4 "${MIN_VER_PYTHON3}" PYTHON3_LIBRARY PYTHON3_INCLUDE_DIR
228    PYTHON3INTERP_FOUND PYTHON3_EXECUTABLE PYTHON3_VERSION_STRING
229    PYTHON3_VERSION_MAJOR PYTHON3_VERSION_MINOR PYTHON3LIBS_FOUND
230    PYTHON3LIBS_VERSION_STRING PYTHON3_LIBRARIES PYTHON3_LIBRARY
231    PYTHON3_DEBUG_LIBRARIES PYTHON3_LIBRARY_DEBUG PYTHON3_INCLUDE_PATH
232    PYTHON3_INCLUDE_DIR PYTHON3_INCLUDE_DIR2 PYTHON3_PACKAGES_PATH
233    PYTHON3_NUMPY_INCLUDE_DIRS PYTHON3_NUMPY_VERSION)
234
235# Use Python 2 as default Python interpreter
236if(PYTHON2INTERP_FOUND)
237    set(PYTHON_DEFAULT_AVAILABLE "TRUE")
238    set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}")
239endif()
240