pybind11NewTools.cmake 9.36 KB
Newer Older
1
2
3
4
5
6
7
# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules
#
# Copyright (c) 2020 Wenzel Jakob <wenzel@inf.ethz.ch> and Henry Schreiner
#
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.

8
9
10
11
12
13
if(CMAKE_VERSION VERSION_LESS 3.12)
  message(FATAL_ERROR "You cannot use the new FindPython module with CMake < 3.12")
endif()

include_guard(GLOBAL)

14
15
16
17
18
19
20
get_property(
  is_config
  TARGET pybind11::headers
  PROPERTY IMPORTED)

if(pybind11_FIND_QUIETLY)
  set(_pybind11_quiet QUIET)
21
22
else()
  set(_pybind11_quiet "")
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
endif()

if(NOT Python_FOUND
   AND NOT Python3_FOUND
   AND NOT Python2_FOUND)
  if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)
    set(Python_FIND_IMPLEMENTATIONS CPython PyPy)
  endif()

  # GitHub Actions like activation
  if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation})
    set(Python_ROOT_DIR "$ENV{pythonLocation}")
  endif()

  find_package(Python REQUIRED COMPONENTS Interpreter Development ${_pybind11_quiet})

  # If we are in submodule mode, export the Python targets to global targets.
  # If this behavior is not desired, FindPython _before_ pybind11.
  if(NOT is_config)
    set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)
    set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE)
    if(TARGET Python::Module)
      set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)
    endif()
  endif()
endif()

if(Python_FOUND)
  set(_Python
      Python
      CACHE INTERNAL "" FORCE)
elseif(Python3_FOUND AND NOT Python2_FOUND)
  set(_Python
      Python3
      CACHE INTERNAL "" FORCE)
elseif(Python2_FOUND AND NOT Python3_FOUND)
  set(_Python
      Python2
      CACHE INTERNAL "" FORCE)
else()
  message(AUTHOR_WARNING "Python2 and Python3 both present, pybind11 in "
                         "PYBIND11_NOPYTHON mode (manually activate to silence warning)")
  set(_pybind11_nopython ON)
  return()
endif()

if(PYBIND11_MASTER_PROJECT)
  if(${_Python}_INTERPRETER_ID MATCHES "PyPy")
    message(STATUS "PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})")
  else()
    message(STATUS "${_Python} ${${_Python}_VERSION}")
  endif()
endif()

77
78
79
80
81
82
83
84
85
86
# If a user finds Python, they may forget to include the Interpreter component
# and the following two steps require it. It is highly recommended by CMake
# when finding development libraries anyway, so we will require it.
if(NOT DEFINED ${_Python}_EXECUTABLE)
  message(
    FATAL_ERROR
      "${_Python} was found without the Interpreter component. Pybind11 requires this component.")

endif()

87
if(NOT ${_Python}_EXECUTABLE STREQUAL PYBIND11_PYTHON_EXECUTABLE_LAST)
88
89
90
  # Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed
  unset(PYTHON_IS_DEBUG CACHE)
  unset(PYTHON_MODULE_EXTENSION CACHE)
91
  set(PYBIND11_PYTHON_EXECUTABLE_LAST
92
93
94
95
      "${${_Python}_EXECUTABLE}"
      CACHE INTERNAL "Python executable during the last CMake run")
endif()

96
97
98
99
100
101
102
103
104
105
if(NOT DEFINED PYTHON_IS_DEBUG)
  # Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter
  execute_process(
    COMMAND "${${_Python}_EXECUTABLE}" "-c"
            "import sys; sys.exit(hasattr(sys, 'gettotalrefcount'))"
    RESULT_VARIABLE _PYTHON_IS_DEBUG)
  set(PYTHON_IS_DEBUG
      "${_PYTHON_IS_DEBUG}"
      CACHE INTERNAL "Python debug status")
endif()
106
107
108

# Get the suffix - SO is deprecated, should use EXT_SUFFIX, but this is
# required for PyPy3 (as of 7.3.1)
109
110
if(NOT DEFINED PYTHON_MODULE_EXTENSION)
  execute_process(
111
112
113
    COMMAND
      "${${_Python}_EXECUTABLE}" "-c"
      "from distutils import sysconfig as s;print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))"
114
115
116
117
118
119
120
121
122
    OUTPUT_VARIABLE _PYTHON_MODULE_EXTENSION
    ERROR_VARIABLE _PYTHON_MODULE_EXTENSION_ERR
    OUTPUT_STRIP_TRAILING_WHITESPACE)

  if(_PYTHON_MODULE_EXTENSION STREQUAL "")
    message(
      FATAL_ERROR "pybind11 could not query the module file extension, likely the 'distutils'"
                  "package is not installed. Full error message:\n${_PYTHON_MODULE_EXTENSION_ERR}")
  endif()
123

124
125
126
127
128
  # This needs to be available for the pybind11_extension function
  set(PYTHON_MODULE_EXTENSION
      "${_PYTHON_MODULE_EXTENSION}"
      CACHE INTERNAL "")
endif()
129
130
131
132
133
134

# Python debug libraries expose slightly different objects before 3.8
# https://docs.python.org/3.6/c-api/intro.html#debugging-builds
# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib
if(PYTHON_IS_DEBUG)
  set_property(
135
    TARGET pybind11::pybind11
136
137
138
139
140
141
142
    APPEND
    PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)
endif()

# Check on every access - since Python2 and Python3 could have been used - do nothing in that case.

if(DEFINED ${_Python}_INCLUDE_DIRS)
143
144
145
146
147
148
149
150
151
152
  # Only add Python for build - must be added during the import for config
  # since it has to be re-discovered.
  #
  # This needs to be a target to be included after the local pybind11
  # directory, just in case there there is an installed pybind11 sitting
  # next to Python's includes. It also ensures Python is a SYSTEM library.
  add_library(pybind11::python_headers INTERFACE IMPORTED)
  set_property(
    TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES
                                             "$<BUILD_INTERFACE:${${_Python}_INCLUDE_DIRS}>")
153
154
155
  set_property(
    TARGET pybind11::pybind11
    APPEND
156
    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers)
157
158
159
  set(pybind11_INCLUDE_DIRS
      "${pybind11_INCLUDE_DIR}" "${${_Python}_INCLUDE_DIRS}"
      CACHE INTERNAL "Directories where pybind11 and possibly Python headers are located")
160
161
162
163
164
165
166
167
168
169
endif()

if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
  set_property(
    TARGET pybind11::pybind11
    APPEND
    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python2_no_register)
endif()

# In CMake 3.18+, you can find these separately, so include an if
170
if(TARGET ${_Python}::Python)
171
172
173
  set_property(
    TARGET pybind11::embed
    APPEND
174
    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
endif()

# CMake 3.15+ has this
if(TARGET ${_Python}::Module)
  set_property(
    TARGET pybind11::module
    APPEND
    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module)
else()
  set_property(
    TARGET pybind11::module
    APPEND
    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper)
endif()

190
191
# WITHOUT_SOABI and WITH_SOABI will disable the custom extension handling used by pybind11.
# WITH_SOABI is passed on to python_add_library.
192
function(pybind11_add_module target_name)
193
194
  cmake_parse_arguments(PARSE_ARGV 1 ARG
                        "STATIC;SHARED;MODULE;THIN_LTO;OPT_SIZE;NO_EXTRAS;WITHOUT_SOABI" "" "")
195

196
197
198
199
  if(ARG_STATIC)
    set(lib_type STATIC)
  elseif(ARG_SHARED)
    set(lib_type SHARED)
200
  else()
201
    set(lib_type MODULE)
202
203
204
  endif()

  if("${_Python}" STREQUAL "Python")
205
    python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
206
  elseif("${_Python}" STREQUAL "Python3")
207
    python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
208
  elseif("${_Python}" STREQUAL "Python2")
209
    python2_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})
210
211
212
213
214
215
  else()
    message(FATAL_ERROR "Cannot detect FindPython version: ${_Python}")
  endif()

  target_link_libraries(${target_name} PRIVATE pybind11::headers)

216
  if(lib_type STREQUAL "MODULE")
217
218
219
220
221
222
223
224
225
226
227
228
229
    target_link_libraries(${target_name} PRIVATE pybind11::module)
  else()
    target_link_libraries(${target_name} PRIVATE pybind11::embed)
  endif()

  if(MSVC)
    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
  endif()

  if(DEFINED ${_Python}_VERSION AND ${_Python}_VERSION VERSION_LESS 3)
    target_link_libraries(${target_name} PRIVATE pybind11::python2_no_register)
  endif()

230
231
232
233
234
235
236
237
238
239
240
241
  # -fvisibility=hidden is required to allow multiple modules compiled against
  # different pybind versions to work properly, and for some features (e.g.
  # py::module_local).  We force it on everything inside the `pybind11`
  # namespace; also turning it on for a pybind module compilation here avoids
  # potential warnings or issues from having mixed hidden/non-hidden types.
  if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
    set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET "hidden")
  endif()

  if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET)
    set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET "hidden")
  endif()
242

243
  # If we don't pass a WITH_SOABI or WITHOUT_SOABI, use our own default handling of extensions
244
  if(NOT ARG_WITHOUT_SOABI AND NOT "WITH_SOABI" IN_LIST ARG_UNPARSED_ARGUMENTS)
245
246
247
    pybind11_extension(${target_name})
  endif()

248
249
250
251
252
253
254
255
256
257
258
259
260
  if(ARG_NO_EXTRAS)
    return()
  endif()

  if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
    if(ARG_THIN_LTO)
      target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)
    else()
      target_link_libraries(${target_name} PRIVATE pybind11::lto)
    endif()
  endif()

  if(NOT MSVC AND NOT ${CMAKE_BUILD_TYPE} MATCHES Debug|RelWithDebInfo)
261
    # Strip unnecessary sections of the binary on Linux/macOS
262
263
264
265
266
267
    pybind11_strip(${target_name})
  endif()

  if(MSVC)
    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)
  endif()
268
269
270
271

  if(ARG_OPT_SIZE)
    target_link_libraries(${target_name} PRIVATE pybind11::opt_size)
  endif()
272
273
274
endfunction()

function(pybind11_extension name)
275
276
  # The extension is precomputed
  set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX "${PYTHON_MODULE_EXTENSION}")
277
278

endfunction()