File: DunePythonCommonMacros.cmake

package info (click to toggle)
dune-common 2.10.0-4
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 5,804 kB
  • sloc: cpp: 52,256; python: 3,979; sh: 1,658; makefile: 17
file content (187 lines) | stat: -rw-r--r-- 9,151 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
# SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
# SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception

# The python extension of the Dune cmake build system
#
# .. cmake_module::
#
#    This module is the main entry point for the python extension of the Dune cmake
#    build system. It handles the detection of the python installation, defines installation
#    rules for python packages in Dune modules and provides virtual environments to
#    run python code from cmake.
#
#    To disable any Python-related features use -DCMAKE_DISABLE_FIND_PACKAGE_Python3=TRUE
#
#    If you want to use Dune modules that provide Python functionality, you should be aware
#    of some facts:
#
#    * CMake looks for your python interpreter during configure. If you want to have it
#      work with a virtual environment, you should activate your virtualenv before configure.
#    * Each module has an additional target :code:`make install_python`, that installs python packages
#      defined in the Dune module. You can customize the install location with
#      :ref:`DUNE_PYTHON_INSTALL_LOCATION`. This is also included in :code:`make install`.
#    * There is additional functionality, that automatically sets up a virtual environment
#      at configure time, you can read more at :ref:`DunePythonVirtualenv`.
#
#    After the module :code:`DunePythonCommonMacros` is run (which happens automatically when
#    configuring dune-common) the following python-related variables will be set and available
#    for use in downstream modules:
#
#    * All variables set by :code:`FindPythonInterp.cmake` and :code:`FindPythonLibs.cmake`
#    * :code:`DUNE_PYTHON_SYSTEM_IS_VIRTUALENV`: True if the given system interpreter resides in
#      virtual environment.
#
#    For documentation on how to customize the build process, check the input variable
#    reference for any variables prefixed with :code:`DUNE_PYTHON`. To learn how to write build
#    system code for Dune modules shipping python, have a look at the command reference for
#    commands prefixed :code:`dune_python`.
#
# .. cmake_variable:: DUNE_PYTHON_INSTALL_LOCATION
#
#    This variable can be used to control where Dune should install python
#    packages. Possible values are:
#
#    * :code:`user`: installs into the users home directory through :code:`pip --user`. Note, that
#      this is incompatible with using virtual environments (as per pip docs).
#    * :code:`system`: into the standard paths of the interpreter which was found
#      by cmake.
#    * :code:`none`: Never install any python packages.
#
#    The default value in use depends on the system interpreter to run in a virtual environment
#    or not: If it does, :code:`system` is the default, if it does not :code:`none` is the default.
#    This rather unintuitive default originates from the strong belief, that installing
#    python packages into the system locations at :code:`/usr/...` should be discouraged.
#
include_guard(GLOBAL)

# unless the user has defined the variable, unversioned names (like python3) are found
# first, to match what users most probably use later on to call the executable
if(NOT DEFINED Python3_FIND_UNVERSIONED_NAMES)
  set(Python3_FIND_UNVERSIONED_NAMES "FIRST")
endif()

# include code from CMake 3.20 to back-port using unversioned Python first
if(${CMAKE_VERSION} VERSION_LESS "3.20")
  list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}/FindPython3")
endif()

# Include all the other parts of the python extension to avoid that users need
# to explicitly include parts of our build system.
include(DunePythonFindPackage)
include(DunePythonInstallPackage)
include(DunePythonTestCommand)

# Find the Python Interpreter and libraries
find_package(Python3 COMPONENTS Interpreter Development)

# this option enables the build of Python bindings for DUNE modules per default
option(DUNE_ENABLE_PYTHONBINDINGS "Enable Python bindings for DUNE" ON)

# this option enables pre-compilation of certain modules in dune-common and dune-geometry
option(DUNE_ENABLE_PYTHONMODULE_PRECOMPILE "Enable module precompilation for certain Python modules in DUNE (can be set as environment variable)" $ENV{DUNE_ENABLE_PYTHONMODULE_PRECOMPILE})

# if python bindings are disabled then this option has to be disabled also
if(NOT DUNE_ENABLE_PYTHONBINDINGS)
  set(DUNE_ENABLE_PYTHONMODULE_PRECOMPILE OFF)
endif()

# helper message used below in various user messages
set(DUNE_PYTHON_BINDINGS_USER_NOTICE "If you do not plan to use the Dune Python bindings you can ignore this information")

if(Python3_Interpreter_FOUND)
  include(DuneExecuteProcess)
  include(DunePathHelper)
  dune_module_path(MODULE dune-common
                   RESULT scriptdir
                   SCRIPT_DIR)

  # Check presence of python packages required by the buildsystem
  dune_python_find_package(PACKAGE pip)

  # Add python related meta targets
  add_custom_target(test_python COMMAND ctest CMD_ARGS -L python)
  add_custom_target(install_python)

  ##### Python bindings specific part begin ################
  # first we test if all requirements are satisfied, if not, Python bindings are
  # disabled and the user gets an informative message explaining why
  if((DUNE_ENABLE_PYTHONBINDINGS) AND (NOT ${Python3_Development.Module_FOUND}))
    message(STATUS "Python bindings disabled")
    message(NOTICE
      "   ----------------------------------------------------------------------------------------\n"
      "   Found a Python interpreter but the Python bindings also requires the Python libraries.\n"
      "   On Linux systems they may be installed in form of a package like python3-dev, python3-devel, python-dev or python-devel (depending on your distribution).\n"
      "   ${DUNE_PYTHON_BINDINGS_USER_NOTICE}.\n"
      "   ----------------------------------------------------------------------------------------\n"
    )
    set(DUNE_ENABLE_PYTHONBINDINGS OFF CACHE BOOL "Disabled Python bindings (requirements not satisfied)" FORCE)
    return()
  endif()

  # the Python bindings currently require the following minimum Python version
  set(DUNE_PYTHON_BINDINGS_MIN_PYTHON_VERSION 3.7)
  if((DUNE_ENABLE_PYTHONBINDINGS) AND (Python3_VERSION VERSION_LESS ${DUNE_PYTHON_BINDINGS_MIN_PYTHON_VERSION}))
    message(STATUS "Python bindings disabled")
    message(NOTICE
      "   ----------------------------------------------------------------------------------------\n"
      "   Python bindings require at least Python version ${DUNE_PYTHON_BINDINGS_MIN_PYTHON_VERSION} but only version ${Python3_VERSION} was found.\n"
      "   ${DUNE_PYTHON_BINDINGS_USER_NOTICE}.\n"
      "   ----------------------------------------------------------------------------------------\n"
    )
    set(DUNE_ENABLE_PYTHONBINDINGS OFF CACHE BOOL "Disabled Python bindings (requirements not satisfied)" FORCE)
    return()
  endif()

  if(DUNE_ENABLE_PYTHONBINDINGS)
    include_directories("${Python3_INCLUDE_DIRS}")
    include(DuneAddPybind11Module)
  endif()
  ##### Python bindings end ################

  # Set up the Dune-internal virtualenv
  include(DunePythonVirtualenv)

  # Determine where to install python packages
  if(DUNE_PYTHON_SYSTEM_IS_VIRTUALENV)
    set(DUNE_PYTHON_INSTALL_LOCATION "system" CACHE STRING "Location of where to install python packages")
  else()
    set(DUNE_PYTHON_INSTALL_LOCATION "user" CACHE STRING "Location of where to install python packages")
  endif()

  if(NOT(("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "user") OR
         ("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "system") OR
         ("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "none") OR
         ("${DUNE_PYTHON_INSTALL_LOCATION}" MATCHES "--target")   # this allows to provide a folder, i.e., --target /home/foo/site-packages
    ))
    message(FATAL_ERROR "DUNE_PYTHON_INSTALL_LOCATION must be user|system|none|--target <target>.")
  endif()

  if(("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "user") AND DUNE_PYTHON_SYSTEM_IS_VIRTUALENV)
    message(FATAL_ERROR "Specifying 'user' as install location is incompatible with using virtual environments (as per pip docs)")
  endif()

else()
  message(STATUS "Python bindings disabled")
  message(NOTICE
        "   ----------------------------------------------------------------------------------------\n"
        "   Python bindings require a Python3 interpreter.\n"
        "   ${DUNE_PYTHON_BINDINGS_USER_NOTICE}.\n"
        "   ----------------------------------------------------------------------------------------\n"
  )
  set(DUNE_ENABLE_PYTHONBINDINGS OFF CACHE BOOL "Disabled Python bindings (requirements not satisfied)" FORCE)
endif()

include(DuneSymlinkOrCopy)

# TODO: This function should have dune prefix and use named arguments
function(add_python_targets base)
  if(Python3_Interpreter_FOUND)
    if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
      message(WARNING "Source and binary dir are the same, skipping symlink!")
    else()
      foreach(file ${ARGN})
        dune_symlink_to_source_files(FILES ${file}.py)
      endforeach()
    endif()
  endif()
endfunction()