File: FindPythonExtensions.cmake

package info (click to toggle)
cvc4 1.8-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid
  • size: 69,876 kB
  • sloc: cpp: 274,686; sh: 5,833; python: 1,893; java: 929; lisp: 763; ansic: 275; perl: 214; makefile: 22; awk: 2
file content (503 lines) | stat: -rw-r--r-- 18,960 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
#.rst
# Define functions to create Python modules and executables.
#
# This file defines CMake functions to build Python extension modules and
# stand-alone executables.  To use it, first include this file.
#
#   find_package(PythonExtensions)
#
# The following variables are defined:
# ::
#
#   PYTHON_PREFIX                     - absolute path to the current Python
#                                       distribution's prefix
#   PYTHON_SITE_PACKAGES_DIR          - absolute path to the current Python
#                                       distribution's site-packages directory
#   PYTHON_RELATIVE_SITE_PACKAGES_DIR - path to the current Python
#                                       distribution's site-packages directory
#                                       relative to its prefix
#   PYTHON_SEPARATOR                  - separator string for file path
#                                       components.  Equivalent to ``os.sep`` in
#                                       Python.
#   PYTHON_PATH_SEPARATOR             - separator string for PATH-style
#                                       environment variables.  Equivalent to
#                                       ``os.pathsep`` in Python.
#
# The following functions are defined:
#
#   python_extension_module(<Target>
#                           [LINKED_MODULES_VAR <LinkedModVar>]
#                           [FORWARD_DECL_MODULES_VAR <ForwardDeclModVar>])
#
# For libraries meant to be used as Python extension modules, either dynamically
# loaded or directly linked.  Amend the configuration of the library target
# (created using ``add_library``) with additional options needed to build and
# use the referenced library as a Python extension module.
#
# Only extension modules that are configured to be built as MODULE libraries can
# be runtime-loaded through the standard Python import mechanism.  All other
# modules can only be included in standalone applications that are written to
# expect their presence.  In addition to being linked against the libraries for
# these modules, such applications must forward declare their entry points and
# initialize them prior to use.  To generate these forward declarations and
# initializations, see ``python_modules_header``.
#
# If ``<Target>`` does not refer to a target, then it is assumed to refer to an
# extension module that is not linked at all, but compiled along with other
# source files directly into an executable.  Adding these modules does not cause
# any library configuration modifications, and they are not added to the list of
# linked modules.  They still must be forward declared and initialized, however,
# and so are added to the forward declared modules list.
#
# Options:
#
# ``LINKED_MODULES_VAR <LinkedModVar>``
#   Name of the variable referencing a list of extension modules whose libraries
#   must be linked into the executables of any stand-alone applications that use
#   them.  By default, the global property ``PY_LINKED_MODULES_LIST`` is used.
#
# ``FORWARD_DECL_MODULES_VAR <ForwardDeclModVar>``
#   Name of the variable referencing a list of extension modules whose entry
#   points must be forward declared and called by any stand-alone applications
#   that use them.  By default, the global property
#   ``PY_FORWARD_DECL_MODULES_LIST`` is used.
#
#
#   python_standalone_executable(<Target>)
#
# For standalone executables that initialize their own Python runtime
# (such as when building source files that include one generated by Cython with
# the --embed option).  Amend the configuration of the executable target
# (created using ``add_executable``) with additional options needed to properly
# build the referenced executable.
#
#   python_modules_header(<Name> [HeaderFilename]
#                         [FORWARD_DECL_MODULES_LIST <ForwardDeclModList>]
#                         [HEADER_OUTPUT_VAR <HeaderOutputVar>]
#                         [INCLUDE_DIR_OUTPUT_VAR <IncludeDirOutputVar>])
#
# Generate a header file that contains the forward declarations and
# initialization routines for the given list of Python extension modules.
# ``<Name>`` is the logical name for the header file (no file extensions).
# ``<HeaderFilename>`` is the actual destination filename for the header file
# (e.g.: decl_modules.h).
#
# If only ``<Name>`` is provided, and it ends in the ".h" extension, then it
# is assumed to be the ``<HeaderFilename>``.  The filename of the header file
# without the extension is used as the logical name.  If only ``<Name>`` is
# provided, and it does not end in the ".h" extension, then the
# ``<HeaderFilename>`` is assumed to ``<Name>.h``.
#
# The exact contents of the generated header file depend on the logical
# ``<Name>``.  It should be set to a value that corresponds to the target
# application, or for the case of multiple applications, some identifier that
# conveyes its purpose.  It is featured in the generated multiple inclusion
# guard as well as the names of the generated initialization routines.
#
# The generated header file includes forward declarations for all listed
# modules, as well as implementations for the following class of routines:
#
# ``int <Name>_<Module>(void)``
#   Initializes the python extension module, ``<Module>``.  Returns an integer
#   handle to the module.
#
# ``void <Name>_LoadAllPythonModules(void)``
#   Initializes all listed python extension modules.
#
# ``void CMakeLoadAllPythonModules(void);``
#   Alias for ``<Name>_LoadAllPythonModules`` whose name does not depend on
#   ``<Name>``.  This function is excluded during preprocessing if the
#   preprocessing macro ``EXCLUDE_LOAD_ALL_FUNCTION`` is defined.
#
# ``void Py_Initialize_Wrapper();``
#   Wrapper arpund ``Py_Initialize()`` that initializes all listed python
#   extension modules.  This function is excluded during preprocessing if the
#   preprocessing macro ``EXCLUDE_PY_INIT_WRAPPER`` is defined.  If this
#   function is generated, then ``Py_Initialize()`` is redefined to a macro
#   that calls this function.
#
# Options:
#
# ``FORWARD_DECL_MODULES_LIST <ForwardDeclModList>``
#   List of extension modules for which to generate forward declarations of
#   their entry points and their initializations.  By default, the global
#   property ``PY_FORWARD_DECL_MODULES_LIST`` is used.

# ``HEADER_OUTPUT_VAR <HeaderOutputVar>``
#   Name of the variable to set to the path to the generated header file.  By
#   default, ``<Name>`` is used.
#
# ``INCLUDE_DIR_OUTPUT_VAR <IncludeDirOutputVar>``
#   Name of the variable to set to the path to the directory containing the
#   generated header file.  By default, ``<Name>_INCLUDE_DIRS`` is used.
#
# Defined variables:
#
# ``<HeaderOutputVar>``
#   The path to the generated header file
#
# ``<IncludeDirOutputVar>``
#   Directory containing the generated header file
#
# Example usage:
#
# .. code-block:: cmake
#
#   find_package(PythonInterp)
#   find_package(PythonLibs)
#   find_package(PythonExtensions)
#   find_package(Cython)
#   find_package(Boost COMPONENTS python)
#
#   # Simple Cython Module -- no executables
#   add_cython_target(_module.pyx)
#   add_library(_module MODULE ${_module})
#   python_extension_module(_module)
#
#   # Mix of Cython-generated code and C++ code using Boost Python
#   # Stand-alone executable -- no modules
#   include_directories(${Boost_INCLUDE_DIRS})
#   add_cython_target(main.pyx CXX EMBED_MAIN)
#   add_executable(main boost_python_module.cxx ${main})
#   target_link_libraries(main ${Boost_LIBRARIES})
#   python_standalone_executable(main)
#
#   # stand-alone executable with three extension modules:
#   # one statically linked, one dynamically linked, and one loaded at runtime
#   #
#   # Freely mixes Cython-generated code, code using Boost-Python, and
#   # hand-written code using the CPython API.
#
#   # module1 -- statically linked
#   add_cython_target(module1.pyx)
#   add_library(module1 STATIC ${module1})
#   python_extension_module(module1
#                           LINKED_MODULES_VAR linked_module_list
#                           FORWARD_DECL_MODULES_VAR fdecl_module_list)
#
#   # module2 -- dynamically linked
#   include_directories({Boost_INCLUDE_DIRS})
#   add_library(module2 SHARED boost_module2.cxx)
#   target_link_libraries(module2 ${Boost_LIBRARIES})
#   python_extension_module(module2
#                           LINKED_MODULES_VAR linked_module_list
#                           FORWARD_DECL_MODULES_VAR fdecl_module_list)
#
#   # module3 -- loaded at runtime
#   add_cython_target(module3a.pyx)
#   add_library(module1 MODULE ${module3a} module3b.cxx)
#   target_link_libraries(module3 ${Boost_LIBRARIES})
#   python_extension_module(module3
#                           LINKED_MODULES_VAR linked_module_list
#                           FORWARD_DECL_MODULES_VAR fdecl_module_list)
#
#   # application executable -- generated header file + other source files
#   python_modules_header(modules
#                         FORWARD_DECL_MODULES_LIST ${fdecl_module_list})
#   include_directories(${modules_INCLUDE_DIRS})
#
#   add_cython_target(mainA)
#   add_cython_target(mainC)
#   add_executable(main ${mainA} mainB.cxx ${mainC} mainD.c)
#
#   target_link_libraries(main ${linked_module_list} ${Boost_LIBRARIES})
#   python_standalone_executable(main)
#
#=============================================================================
# Copyright 2011 Kitware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================

find_package(PythonInterp REQUIRED)
find_package(PythonLibs)
include(targetLinkLibrariesWithDynamicLookup)

set(_command "
import distutils.sysconfig
import itertools
import os
import os.path
import site
import sys

result = None
rel_result = None
candidate_lists = []

try:
    candidate_lists.append((distutils.sysconfig.get_python_lib(),))
except AttributeError: pass

try:
    candidate_lists.append(site.getsitepackages())
except AttributeError: pass

try:
    candidate_lists.append((site.getusersitepackages(),))
except AttributeError: pass

candidates = itertools.chain.from_iterable(candidate_lists)

for candidate in candidates:
    rel_candidate = os.path.relpath(
      candidate, sys.prefix)
    if not rel_candidate.startswith(\"..\"):
        result = candidate
        rel_result = rel_candidate
        break

sys.stdout.write(\";\".join((
    os.sep,
    os.pathsep,
    sys.prefix,
    result,
    rel_result,
)))
")

execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "${_command}"
                OUTPUT_VARIABLE _list
                RESULT_VARIABLE _result)

list(GET _list 0 _item)
set(PYTHON_SEPARATOR "${_item}")
mark_as_advanced(PYTHON_SEPARATOR)

list(GET _list 1 _item)
set(PYTHON_PATH_SEPARATOR "${_item}")
mark_as_advanced(PYTHON_PATH_SEPARATOR)

list(GET _list 2 _item)
set(PYTHON_PREFIX "${_item}")
mark_as_advanced(PYTHON_PREFIX)

list(GET _list 3 _item)
set(PYTHON_SITE_PACKAGES_DIR "${_item}")
mark_as_advanced(PYTHON_SITE_PACKAGES_DIR)

list(GET _list 4 _item)
set(PYTHON_RELATIVE_SITE_PACKAGES_DIR "${_item}")
mark_as_advanced(PYTHON_RELATIVE_SITE_PACKAGES_DIR)

function(python_extension_module _target)
  set(one_ops LINKED_MODULES_VAR FORWARD_DECL_MODULES_VAR)
  cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN})

  set(_lib_type "NA")
  if(TARGET ${_target})
    get_property(_lib_type TARGET ${_target} PROPERTY TYPE)
  endif()

  set(_is_non_lib TRUE)

  set(_is_static_lib FALSE)
  if(_lib_type STREQUAL "STATIC_LIBRARY")
      set(_is_static_lib TRUE)
      set(_is_non_lib FALSE)
  endif()

  set(_is_shared_lib FALSE)
  if(_lib_type STREQUAL "SHARED_LIBRARY")
      set(_is_shared_lib TRUE)
      set(_is_non_lib FALSE)
  endif()

  set(_is_module_lib FALSE)
  if(_lib_type STREQUAL "MODULE_LIBRARY")
      set(_is_module_lib TRUE)
      set(_is_non_lib FALSE)
  endif()

  if(_is_static_lib OR _is_shared_lib OR _is_non_lib)

    if(_is_static_lib OR _is_shared_lib)
      if(_args_LINKED_MODULES_VAR)
        set(${_args_LINKED_MODULES_VAR}
            ${${_args_LINKED_MODULES_VAR}} ${_target} PARENT_SCOPE)
      else()
        set_property(GLOBAL APPEND PROPERTY PY_LINKED_MODULES_LIST ${_target})
      endif()
    endif()

    if(_args_FORWARD_DECL_MODULES_VAR)
      set(${_args_FORWARD_DECL_MODULES_VAR}
          ${${_args_FORWARD_DECL_MODULES_VAR}} ${_target} PARENT_SCOPE)
    else()
      set_property(GLOBAL APPEND PROPERTY
                   PY_FORWARD_DECL_MODULES_LIST ${_target})
    endif()
  endif()

  if(NOT _is_non_lib)
    include_directories("${PYTHON_INCLUDE_DIRS}")
  endif()

  if(_is_module_lib)
    set_target_properties(${_target} PROPERTIES
                          PREFIX "${PYTHON_MODULE_PREFIX}")
  endif()

  if(_is_module_lib OR _is_shared_lib)
    if(_is_module_lib AND WIN32 AND NOT CYGWIN)
      set_target_properties(${_target} PROPERTIES SUFFIX ".pyd")
    endif()

    target_link_libraries_with_dynamic_lookup(${_target} ${PYTHON_LIBRARIES})
  endif()
endfunction()

function(python_standalone_executable _target)
  include_directories(${PYTHON_INCLUDE_DIRS})
  target_link_libraries(${_target} ${PYTHON_LIBRARIES})
endfunction()

function(python_modules_header _name)
  set(one_ops FORWARD_DECL_MODULES_LIST
              HEADER_OUTPUT_VAR
              INCLUDE_DIR_OUTPUT_VAR)
  cmake_parse_arguments(_args "" "${one_ops}" "" ${ARGN})

  list(GET _args_UNPARSED_ARGUMENTS 0 _arg0)
  # if present, use arg0 as the input file path
  if(_arg0)
    set(_source_file ${_arg0})

  # otherwise, must determine source file from name, or vice versa
  else()
    get_filename_component(_name_ext "${_name}" EXT)

    # if extension provided, _name is the source file
    if(_name_ext)
      set(_source_file ${_name})
      get_filename_component(_name "${_source_file}" NAME_WE)

    # otherwise, assume the source file is ${_name}.h
    else()
      set(_source_file ${_name}.h)
    endif()
  endif()

  if(_args_FORWARD_DECL_MODULES_LIST)
    set(static_mod_list ${_args_FORWARD_DECL_MODULES_LIST})
  else()
    get_property(static_mod_list GLOBAL PROPERTY PY_FORWARD_DECL_MODULES_LIST)
  endif()

  string(REPLACE "." "_" _header_name "${_name}")
  string(TOUPPER ${_header_name} _header_name_upper)
  set(_header_name_upper "_${_header_name_upper}_H")
  set(generated_file ${CMAKE_CURRENT_BINARY_DIR}/${_source_file})

  set(generated_file_tmp "${generated_file}.in")
  file(WRITE ${generated_file_tmp}
       "/* Created by CMake. DO NOT EDIT; changes will be lost. */\n")

  set(_chunk "")
  set(_chunk "${_chunk}#ifndef ${_header_name_upper}\n")
  set(_chunk "${_chunk}#define ${_header_name_upper}\n")
  set(_chunk "${_chunk}\n")
  set(_chunk "${_chunk}#include <Python.h>\n")
  set(_chunk "${_chunk}\n")
  set(_chunk "${_chunk}#ifdef __cplusplus\n")
  set(_chunk "${_chunk}extern \"C\" {\n")
  set(_chunk "${_chunk}#endif /* __cplusplus */\n")
  set(_chunk "${_chunk}\n")
  set(_chunk "${_chunk}#if PY_MAJOR_VERSION < 3\n")
  file(APPEND ${generated_file_tmp} "${_chunk}")

  foreach(_module ${static_mod_list})
    file(APPEND ${generated_file_tmp}
         "PyMODINIT_FUNC init${PYTHON_MODULE_PREFIX}${_module}(void);\n")
  endforeach()

  file(APPEND ${generated_file_tmp} "#else /* PY_MAJOR_VERSION >= 3*/\n")

  foreach(_module ${static_mod_list})
    file(APPEND ${generated_file_tmp}
         "PyMODINIT_FUNC PyInit_${PYTHON_MODULE_PREFIX}${_module}(void);\n")
  endforeach()

  set(_chunk "")
  set(_chunk "${_chunk}#endif /* PY_MAJOR_VERSION >= 3*/\n\n")
  set(_chunk "${_chunk}#ifdef __cplusplus\n")
  set(_chunk "${_chunk}}\n")
  set(_chunk "${_chunk}#endif /* __cplusplus */\n")
  set(_chunk "${_chunk}\n")
  file(APPEND ${generated_file_tmp} "${_chunk}")

  foreach(_module ${static_mod_list})
    set(_import_function "${_header_name}_${_module}")
    set(_prefixed_module "${PYTHON_MODULE_PREFIX}${_module}")

    set(_chunk "")
    set(_chunk "${_chunk}int ${_import_function}(void)\n")
    set(_chunk "${_chunk}{\n")
    set(_chunk "${_chunk}  static char name[] = \"${_prefixed_module}\";\n")
    set(_chunk "${_chunk}  #if PY_MAJOR_VERSION < 3\n")
    set(_chunk "${_chunk}  return PyImport_AppendInittab(")
    set(_chunk "${_chunk}name, init${_prefixed_module});\n")
    set(_chunk "${_chunk}  #else /* PY_MAJOR_VERSION >= 3 */\n")
    set(_chunk "${_chunk}  return PyImport_AppendInittab(")
    set(_chunk "${_chunk}name, PyInit_${_prefixed_module});\n")
    set(_chunk "${_chunk}  #endif /* PY_MAJOR_VERSION >= 3 */\n")
    set(_chunk "${_chunk}}\n\n")
    file(APPEND ${generated_file_tmp} "${_chunk}")
  endforeach()

  file(APPEND ${generated_file_tmp}
       "void ${_header_name}_LoadAllPythonModules(void)\n{\n")
  foreach(_module ${static_mod_list})
    file(APPEND ${generated_file_tmp} "  ${_header_name}_${_module}();\n")
  endforeach()
  file(APPEND ${generated_file_tmp} "}\n\n")

  set(_chunk "")
  set(_chunk "${_chunk}#ifndef EXCLUDE_LOAD_ALL_FUNCTION\n")
  set(_chunk "${_chunk}void CMakeLoadAllPythonModules(void)\n")
  set(_chunk "${_chunk}{\n")
  set(_chunk "${_chunk}  ${_header_name}_LoadAllPythonModules();\n")
  set(_chunk "${_chunk}}\n")
  set(_chunk "${_chunk}#endif /* !EXCLUDE_LOAD_ALL_FUNCTION */\n\n")

  set(_chunk "${_chunk}#ifndef EXCLUDE_PY_INIT_WRAPPER\n")
  set(_chunk "${_chunk}static void Py_Initialize_Wrapper()\n")
  set(_chunk "${_chunk}{\n")
  set(_chunk "${_chunk}  ${_header_name}_LoadAllPythonModules();\n")
  set(_chunk "${_chunk}  Py_Initialize();\n")
  set(_chunk "${_chunk}}\n")
  set(_chunk "${_chunk}#define Py_Initialize Py_Initialize_Wrapper\n")
  set(_chunk "${_chunk}#endif /* !EXCLUDE_PY_INIT_WRAPPER */\n\n")

  set(_chunk "${_chunk}#endif /* !${_header_name_upper} */\n")
  file(APPEND ${generated_file_tmp} "${_chunk}")

  # with configure_file() cmake complains that you may not use a file created
  # using file(WRITE) as input file for configure_file()
  execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
                  "${generated_file_tmp}" "${generated_file}"
                  OUTPUT_QUIET ERROR_QUIET)

  set(_header_output_var ${_name})
  if(_args_HEADER_OUTPUT_VAR)
    set(_header_output_var ${_args_HEADER_OUTPUT_VAR})
  endif()
  set(${_header_output_var} ${generated_file} PARENT_SCOPE)

  set(_include_dir_var ${_name}_INCLUDE_DIRS)
  if(_args_INCLUDE_DIR_OUTPUT_VAR)
    set(_include_dir_var ${_args_INCLUDE_DIR_OUTPUT_VAR})
  endif()
  set(${_include_dirs_var} ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
endfunction()