1# - Find python libraries
2# This module finds if Python is installed and determines where the
3# include files and libraries are. It also determines what the name of
4# the library is. This code sets the following variables:
5#
6#  PYTHONLIBS_FOUND           - have the Python libs been found
7#  PYTHON_LIBRARIES           - path to the python library
8#  PYTHON_INCLUDE_PATH        - path to where Python.h is found (deprecated)
9#  PYTHON_INCLUDE_DIRS        - path to where Python.h is found
10#  PYTHON_DEBUG_LIBRARIES     - path to the debug library (deprecated)
11#  PYTHONLIBS_VERSION_STRING  - version of the Python libs found (since CMake 2.8.8)
12#
13# The Python_ADDITIONAL_VERSIONS variable can be used to specify a list of
14# version numbers that should be taken into account when searching for Python.
15# You need to set this variable before calling find_package(PythonLibs).
16#
17# You can point to a preferred python install to use by setting the following
18# to the point at the root directory of the python install:
19#
20#  PYTHON_ROOT_DIR            - The root directory of the python install
21#
22# If you'd like to specify the installation of Python to use, you should modify
23# the following cache variables:
24#  PYTHON_LIBRARY             - path to the python library
25#  PYTHON_INCLUDE_DIR         - path to where Python.h is found
26
27#=============================================================================
28# Copyright 2001-2009 Kitware, Inc.
29#
30# Distributed under the OSI-approved BSD License (the "License");
31# see accompanying file Copyright.txt for details.
32#
33# This software is distributed WITHOUT ANY WARRANTY; without even the
34# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
35# See the License for more information.
36#=============================================================================
37# (To distribute this file outside of CMake, substitute the full
38#  License text for the above reference.)
39
40include(CMakeFindFrameworks)
41
42# Search for the python framework on Apple.
43cmake_find_frameworks(Python)
44
45set(_PYTHON1_VERSIONS 1.6 1.5)
46set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0)
47set(_PYTHON3_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0)
48
49if(PythonLibs_FIND_VERSION)
50    if(PythonLibs_FIND_VERSION MATCHES "^[0-9]+\\.[0-9]+(\\.[0-9]+.*)?$")
51        string(REGEX REPLACE "^([0-9]+\\.[0-9]+).*" "\\1" _PYTHON_FIND_MAJ_MIN "${PythonLibs_FIND_VERSION}")
52        string(REGEX REPLACE "^([0-9]+).*" "\\1" _PYTHON_FIND_MAJ "${_PYTHON_FIND_MAJ_MIN}")
53        unset(_PYTHON_FIND_OTHER_VERSIONS)
54        if(PythonLibs_FIND_VERSION_EXACT)
55            if(_PYTHON_FIND_MAJ_MIN STREQUAL PythonLibs_FIND_VERSION)
56                set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}")
57            else()
58                set(_PYTHON_FIND_OTHER_VERSIONS "${PythonLibs_FIND_VERSION}" "${_PYTHON_FIND_MAJ_MIN}")
59            endif()
60        else()
61            foreach(_PYTHON_V ${_PYTHON${_PYTHON_FIND_MAJ}_VERSIONS})
62                if(NOT _PYTHON_V VERSION_LESS _PYTHON_FIND_MAJ_MIN)
63                    list(APPEND _PYTHON_FIND_OTHER_VERSIONS ${_PYTHON_V})
64                endif()
65             endforeach()
66        endif()
67        unset(_PYTHON_FIND_MAJ_MIN)
68        unset(_PYTHON_FIND_MAJ)
69    else()
70        set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON${PythonLibs_FIND_VERSION}_VERSIONS})
71    endif()
72else()
73    set(_PYTHON_FIND_OTHER_VERSIONS ${_PYTHON3_VERSIONS} ${_PYTHON2_VERSIONS} ${_PYTHON1_VERSIONS})
74endif()
75
76# Set up the versions we know about, in the order we will search. Always add
77# the user supplied additional versions to the front.
78set(_Python_VERSIONS
79  ${Python_ADDITIONAL_VERSIONS}
80  ${_PYTHON_FIND_OTHER_VERSIONS}
81  )
82
83unset(_PYTHON_FIND_OTHER_VERSIONS)
84unset(_PYTHON1_VERSIONS)
85unset(_PYTHON2_VERSIONS)
86unset(_PYTHON3_VERSIONS)
87
88foreach(_CURRENT_VERSION ${_Python_VERSIONS})
89  string(REPLACE "." "" _CURRENT_VERSION_NO_DOTS ${_CURRENT_VERSION})
90
91  if(WIN32)
92    if(MINGW)
93      find_library(PYTHON_DEBUG_LIBRARY
94        NAMES python${_CURRENT_VERSION}_d
95        PATHS
96          "${PYTHON_ROOT_DIR}"
97          "c:/python${_CURRENT_VERSION}"
98          "c:/python${_CURRENT_VERSION_NO_DOTS}"
99        NO_SYSTEM_ENVIRONMENT_PATH
100      )
101    elseif(VCPKG_TOOLCHAIN)
102      find_library(PYTHON_DEBUG_LIBRARY
103        NAMES python${_CURRENT_VERSION_NO_DOTS}_d
104        PATHS
105          "${PYTHON_ROOT_DIR}"
106        NO_SYSTEM_ENVIRONMENT_PATH
107      )
108    else()
109      find_library(PYTHON_DEBUG_LIBRARY
110        NAMES python${_CURRENT_VERSION_NO_DOTS}_d python
111        PATHS
112          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug
113          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug
114          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
115          [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
116        )
117    endif()
118  endif()
119
120  if(MINGW)
121    find_library(PYTHON_LIBRARY
122      NAMES python${_CURRENT_VERSION}
123      PATHS
124        "${PYTHON_ROOT_DIR}"
125        "C:/python"
126      PATH_SUFFIXES
127        ${_CURRENT_VERSION}
128        ${_CURRENT_VERSION_NO_DOTS}
129      NO_SYSTEM_ENVIRONMENT_PATH
130    )
131  elseif(VCPKG_TOOLCHAIN)
132    find_library(PYTHON_LIBRARY
133      NAMES python${_CURRENT_VERSION_NO_DOTS}
134      PATHS
135        "${PYTHON_ROOT_DIR}"
136      PATH_SUFFIXES
137        ${_CURRENT_VERSION}
138        ${_CURRENT_VERSION_NO_DOTS}
139      NO_SYSTEM_ENVIRONMENT_PATH
140    )
141  else()
142    find_library(PYTHON_LIBRARY
143      NAMES
144        python${_CURRENT_VERSION_NO_DOTS}
145        python${_CURRENT_VERSION}mu
146        python${_CURRENT_VERSION}m
147        python${_CURRENT_VERSION}u
148        python${_CURRENT_VERSION}
149      PATHS
150        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
151        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs
152      # Avoid finding the .dll in the PATH.  We want the .lib.
153      NO_SYSTEM_ENVIRONMENT_PATH
154    )
155  endif()
156
157  # Look for the static library in the Python config directory
158  find_library(PYTHON_LIBRARY
159    NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION}
160    # Avoid finding the .dll in the PATH.  We want the .lib.
161    NO_SYSTEM_ENVIRONMENT_PATH
162    # This is where the static library is usually located
163    PATH_SUFFIXES python${_CURRENT_VERSION}/config
164  )
165
166  # For backward compatibility, honour value of PYTHON_INCLUDE_PATH, if
167  # PYTHON_INCLUDE_DIR is not set.
168  if(DEFINED PYTHON_INCLUDE_PATH AND NOT DEFINED PYTHON_INCLUDE_DIR)
169    set(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_PATH}" CACHE PATH
170      "Path to where Python.h is found" FORCE)
171  endif()
172
173  set(PYTHON_FRAMEWORK_INCLUDES)
174
175  if(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR)
176    foreach(dir ${Python_FRAMEWORKS})
177      set(PYTHON_FRAMEWORK_INCLUDES ${PYTHON_FRAMEWORK_INCLUDES}
178        ${dir}/Versions/${_CURRENT_VERSION}/include/python${_CURRENT_VERSION})
179    endforeach()
180  endif()
181
182  if(MINGW)
183    find_path(PYTHON_INCLUDE_DIR
184      NAMES Python.h
185      PATHS
186        "${PYTHON_ROOT_DIR}"
187        "C:/python${_CURRENT_VERSION}"
188        "C:/python${_CURRENT_VERSION_NOT_DOTS}"
189      PATH_SUFFIXES
190        include
191        python${_CURRENT_VERSION}
192        python${_CURRENT_VERSION_NOT_DOTS}
193    )
194  elseif(VCPKG_TOOLCHAIN)
195    find_path(PYTHON_INCLUDE_DIR
196      NAMES Python.h
197      PATHS
198        "${PYTHON_ROOT_DIR}"
199      PATH_SUFFIXES
200        include
201        python${_CURRENT_VERSION}
202        python${_CURRENT_VERSION_NOT_DOTS}
203      NO_SYSTEM_ENVIRONMENT_PATH
204    )
205  else()
206    find_path(PYTHON_INCLUDE_DIR
207      NAMES Python.h
208      PATHS
209        ${PYTHON_FRAMEWORK_INCLUDES}
210        [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include
211        [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include
212      PATH_SUFFIXES
213        python${_CURRENT_VERSION}mu
214        python${_CURRENT_VERSION}m
215        python${_CURRENT_VERSION}u
216        python${_CURRENT_VERSION}
217  )
218  endif()
219
220  # For backward compatibility, set PYTHON_INCLUDE_PATH.
221  set(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}")
222
223  if(PYTHON_INCLUDE_DIR AND EXISTS "${PYTHON_INCLUDE_DIR}/patchlevel.h")
224    file(STRINGS "${PYTHON_INCLUDE_DIR}/patchlevel.h" python_version_str
225         REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"")
226    string(REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1"
227                         PYTHONLIBS_VERSION_STRING "${python_version_str}")
228    unset(python_version_str)
229  endif()
230
231  if(PYTHON_LIBRARY AND PYTHON_INCLUDE_DIR)
232    break()
233  endif()
234endforeach()
235
236mark_as_advanced(
237  PYTHON_DEBUG_LIBRARY
238  PYTHON_LIBRARY
239  PYTHON_INCLUDE_DIR
240)
241
242# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the
243# cache entries because they are meant to specify the location of a single
244# library. We now set the variables listed by the documentation for this
245# module.
246set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
247set(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}")
248
249# These variables have been historically named in this module different from
250# what SELECT_LIBRARY_CONFIGURATIONS() expects.
251set(PYTHON_LIBRARY_DEBUG "${PYTHON_DEBUG_LIBRARY}")
252set(PYTHON_LIBRARY_RELEASE "${PYTHON_LIBRARY}")
253include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
254select_library_configurations(PYTHON)
255# SELECT_LIBRARY_CONFIGURATIONS() sets ${PREFIX}_FOUND if it has a library.
256# Unset this, this prefix doesn't match the module prefix, they are different
257# for historical reasons.
258unset(PYTHON_FOUND)
259
260include(FindPackageHandleStandardArgs)
261find_package_handle_standard_args(PythonLibs
262                                  REQUIRED_VARS PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS
263                                  VERSION_VAR PYTHONLIBS_VERSION_STRING)
264
265# PYTHON_ADD_MODULE(<name> src1 src2 ... srcN) is used to build modules for python.
266# PYTHON_WRITE_MODULES_HEADER(<filename>) writes a header file you can include
267# in your sources to initialize the static python modules
268function(PYTHON_ADD_MODULE _NAME )
269  get_property(_TARGET_SUPPORTS_SHARED_LIBS
270    GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
271  option(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE)
272  option(PYTHON_MODULE_${_NAME}_BUILD_SHARED
273    "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS})
274
275  # Mark these options as advanced
276  mark_as_advanced(PYTHON_ENABLE_MODULE_${_NAME}
277    PYTHON_MODULE_${_NAME}_BUILD_SHARED)
278
279  if(PYTHON_ENABLE_MODULE_${_NAME})
280    if(PYTHON_MODULE_${_NAME}_BUILD_SHARED)
281      set(PY_MODULE_TYPE MODULE)
282    else()
283      set(PY_MODULE_TYPE STATIC)
284      set_property(GLOBAL  APPEND  PROPERTY  PY_STATIC_MODULES_LIST ${_NAME})
285    endif()
286
287    set_property(GLOBAL  APPEND  PROPERTY  PY_MODULES_LIST ${_NAME})
288    add_library(${_NAME} ${PY_MODULE_TYPE} ${ARGN})
289#    target_link_libraries(${_NAME} ${PYTHON_LIBRARIES})
290
291    if(PYTHON_MODULE_${_NAME}_BUILD_SHARED)
292      set_target_properties(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}")
293      if(WIN32 AND NOT CYGWIN)
294        set_target_properties(${_NAME} PROPERTIES SUFFIX ".pyd")
295      endif()
296    endif()
297
298  endif()
299endfunction()
300
301function(PYTHON_WRITE_MODULES_HEADER _filename)
302
303  get_property(PY_STATIC_MODULES_LIST  GLOBAL  PROPERTY PY_STATIC_MODULES_LIST)
304
305  get_filename_component(_name "${_filename}" NAME)
306  string(REPLACE "." "_" _name "${_name}")
307  string(TOUPPER ${_name} _nameUpper)
308  set(_filename ${CMAKE_CURRENT_BINARY_DIR}/${_filename})
309
310  set(_filenameTmp "${_filename}.in")
311  file(WRITE ${_filenameTmp} "/*Created by cmake, do not edit, changes will be lost*/\n")
312  file(APPEND ${_filenameTmp}
313"#ifndef ${_nameUpper}
314#define ${_nameUpper}
315
316#include <Python.h>
317
318#ifdef __cplusplus
319extern \"C\" {
320#endif /* __cplusplus */
321
322")
323
324  foreach(_currentModule ${PY_STATIC_MODULES_LIST})
325    file(APPEND ${_filenameTmp} "extern void init${PYTHON_MODULE_PREFIX}${_currentModule}(void);\n\n")
326  endforeach()
327
328  file(APPEND ${_filenameTmp}
329"#ifdef __cplusplus
330}
331#endif /* __cplusplus */
332
333")
334
335
336  foreach(_currentModule ${PY_STATIC_MODULES_LIST})
337    file(APPEND ${_filenameTmp} "int ${_name}_${_currentModule}(void) \n{\n  static char name[]=\"${PYTHON_MODULE_PREFIX}${_currentModule}\"; return PyImport_AppendInittab(name, init${PYTHON_MODULE_PREFIX}${_currentModule});\n}\n\n")
338  endforeach()
339
340  file(APPEND ${_filenameTmp} "void ${_name}_LoadAllPythonModules(void)\n{\n")
341  foreach(_currentModule ${PY_STATIC_MODULES_LIST})
342    file(APPEND ${_filenameTmp} "  ${_name}_${_currentModule}();\n")
343  endforeach()
344  file(APPEND ${_filenameTmp} "}\n\n")
345  file(APPEND ${_filenameTmp} "#ifndef EXCLUDE_LOAD_ALL_FUNCTION\nvoid CMakeLoadAllPythonModules(void)\n{\n  ${_name}_LoadAllPythonModules();\n}\n#endif\n\n#endif\n")
346
347# with configure_file() cmake complains that you may not use a file created using file(WRITE) as input file for configure_file()
348  execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_filenameTmp}" "${_filename}" OUTPUT_QUIET ERROR_QUIET)
349
350endfunction()
351