-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathkwiver-setup-python.cmake
More file actions
307 lines (269 loc) · 10.6 KB
/
Copy pathkwiver-setup-python.cmake
File metadata and controls
307 lines (269 loc) · 10.6 KB
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
###
# Finds the python binaries, libs, include, and site-packages paths
#
# The purpose of this file is to export variables that will be used in
# kwiver/CMake/utils/kwiver-utils-python.cmake and
# kwiver/sprokit/conf/sprokit-macro-python.cmake (the latter will eventually be
# consolidated into the former)
#
# User options defined in this file:
#
# KWIVER_PYTHON_MAJOR_VERSION
# The major python version to target (either 2 or 3)
#
#
# Calls find_packages to on python interpreter/libraries which defines:
#
# PYTHON_EXECUTABLE
# PYTHON_INCLUDE_DIR
# PYTHON_LIBRARIES
# PYTHON_LIBRARIES_DEBUG
#
# Exported variables used by python utility functions are:
#
# PYTHON_VERSION
# the major/minor python version
#
# PYTHON_ABI_FLAGS
# Python abstract binary interface flags (used internally for defining
# subsequent variables, but settable by the user as an advanced setting)
#
# python_site_packages
# Location where python packages are installed relative to your python
# install directory. For example:
# Windows system install: Lib\site-packages
# Debian system install: lib/python2.7/dist-packages
# Debian virtualenv install: lib/python3.5/site-packages
#
# python_sitename
# The basename of the python_site_packages directory. This is either
# site-packages (in most cases) or dist-packages (if your python was
# configured by a debian package manager). If you are using a python
# virtualenv (you should be) then this will be site-packages
#
# kwiver_python_subdir
# basename of the python lib folder (that contains site-packages).
# Depends on the python major/minor version and the ABI flags
# (e.g. python2.7, python3.5m)
#
# kwiver_python_output_path
# The location in the build tree to copy/symlink python modules Depends on
# the value of `kwiver_python_subdir`.
# (e.g. build/lib/python2.7, build/lib/python3.5m)
#
# kwiver_python_install_path
# The base location in the install tree where python files/modules are
# to be installed.
# (e.g. ${CMAKE_INSTALL_PREFIX}/lib/python3)
#
# sprokit_python_output_path
# Similar to `kwiver_python_output_path`. Used by sprokit to define extra
# python output paths. This may be removed in the future.
# (e.g. build/lib)
#
###
# Private helper function to execute `python -c "<cmd>"`
#
# Runs a python command and populates an outvar with the result of stdout.
# Be careful of indentation if `cmd` is multiline.
#
function(_pycmd outvar cmd)
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" -c "${cmd}"
RESULT_VARIABLE _exitcode
OUTPUT_VARIABLE _output)
if(NOT ${_exitcode} EQUAL 0)
message(ERROR "Failed when running python code: \"\"\"
${cmd}\"\"\"")
message(FATAL_ERROR "Python command failed with error code: ${_exitcode}")
endif()
# Remove supurflous newlines (artifacts of print)
string(STRIP "${_output}" _output)
set(${outvar} "${_output}" PARENT_SCOPE)
endfunction()
###
# Private helper function to check if a python package is installed
function(_ensure_pypackage_exists package)
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" -c "import ${package}"
RESULT_VARIABLE _exitcode
OUTPUT_VARIABLE _output)
if(NOT ${_exitcode} EQUAL 0)
message(FATAL_ERROR "${package} is missing !
Please install ${package} in the python virtual environment associated with the build")
endif()
endfunction()
###
# Python major version user option
#
# Respect the PYTHON_VERSION_MAJOR version if it is set
# TODO: When is PYTHON_VERSION_MAJOR ever set? It currently does not show up.
if (PYTHON_VERSION_MAJOR)
set(DEFAULT_PYTHON_MAJOR ${PYTHON_VERSION_MAJOR})
else()
set(DEFAULT_PYTHON_MAJOR "3")
endif()
set(KWIVER_PYTHON_MAJOR_VERSION "${DEFAULT_PYTHON_MAJOR}" CACHE STRING "Python version to use: 3 or 2")
set_property(CACHE KWIVER_PYTHON_MAJOR_VERSION PROPERTY STRINGS "3" "2")
###
# Detect major version change (part1)
#
# Clear cached variables when the user changes major python versions.
# When this happens, we need to re-find the bin, include, and libs
#
if (NOT __prev_kwiver_pyversion STREQUAL KWIVER_PYTHON_MAJOR_VERSION)
# but dont clobber initial settings in the instance they are specified via
# commandline (e.g cmake -DPYTHON_EXECUTABLE=/my/special/python)
if (__prev_kwiver_pyversion)
message(STATUS "The Python version changed; refinding the interpreter")
message(STATUS "The previous Python version was: \"${__prev_kwiver_pyversion}\"")
unset(__prev_kwiver_pyversion CACHE)
unset(PYTHON_EXECUTABLE CACHE)
unset(PYTHON_INCLUDE_DIR CACHE)
unset(PYTHON_LIBRARIES CACHE)
unset(PYTHON_LIBRARIES_DEBUG CACHE)
unset(PYTHON_ABIFLAGS CACHE)
endif()
endif()
###
#
# Mark the previous version so we can determine when python versions change
#
set(__prev_kwiver_pyversion "${KWIVER_PYTHON_MAJOR_VERSION}" CACHE INTERNAL
"allows us to determine if the user changes python version")
###
# Python interpreter and libraries
#
# note, 3.8 is a minimum version
# when building extension modules we need to link to Development.Module instead
# of Development . This links to libpython as interface instead of directly
# allowing to build python wheels which should not link directly to libpython
set(_requested_python_components Interpreter Development.Module)
if((NOT SKBUILD) OR MSVC)
set(_requested_python_components ${_requested_python_components} Development.Embed)
endif()
find_package(Python 3.8 REQUIRED COMPONENTS ${_requested_python_components})
set(PYTHON_EXECUTABLE ${Python_EXECUTABLE} CACHE FILEPATH "Path to Python executable")
set(PYTHON_INCLUDE_DIR ${Python_INCLUDE_DIRS} CACHE STRING "Paths to Python include directories")
set(PYTHON_LIBRARIES ${Python_LIBRARIES} CACHE STRING "Paths to Python libraries")
set(PYTHON_LIBRARIES ${Python_LIBRARIES} CACHE STRING "Paths to Python libraries")
set(PYTHON_LIBRARIES_DEBUG PYTHON_LIBRARIES_DEBUG_NOT_FOUND CACHE FILEPATH "Path to Python debug libraries")
###
# Python site-packages
#
# Get canonical directory for python site packages (relative to install
# location). It varies from system to system.
#
_pycmd(python_site_packages "import sysconfig; import os; print(os.path.relpath(sysconfig.get_path('purelib'), sysconfig.get_config_vars()['base']))")
message(STATUS "python_site_packages = ${python_site_packages}")
# Current usage determines most of the path in alternate ways.
# All we need to supply is the '*-packages' directory name.
# Customers could be converted to accept a larger part of the path from this function.
get_filename_component(python_sitename ${python_site_packages} NAME)
###
# Python install path
set(kwiver_python_install_path "${CMAKE_INSTALL_PREFIX}/${python_site_packages}")
message(STATUS "kwiver_python_install_path = ${kwiver_python_install_path}")
###
# Python major/minor version
#
# Use the executable to find the major/minor version.
# If you want to change this, then change the executable.
#
_pycmd(PYTHON_VERSION "import sys; import re; print(re.match(r'^[0-9]+\.[0-9]+', sys.version)[0])")
# assert that the right python version was found
if(NOT PYTHON_VERSION MATCHES "^${KWIVER_PYTHON_MAJOR_VERSION}.*")
message(STATUS "KWIVER_PYTHON_MAJOR_VERSION = ${KWIVER_PYTHON_MAJOR_VERSION}")
message(STATUS "PYTHON_VERSION = ${PYTHON_VERSION}")
message(FATAL_ERROR "Requested python \"${KWIVER_PYTHON_MAJOR_VERSION}\" but got \"${PYTHON_VERSION}\"")
endif()
###
# Python ABI Flags
#
# See PEP 3149 - ABI (application binary interface) version tagged .so files
# https://www.python.org/dev/peps/pep-3149/
#
# In python 3, we can determine what the ABI flags are
_pycmd(_python_abi_flags "import sysconfig; print(sysconfig.get_config_var('ABIFLAGS'))")
set(PYTHON_ABIFLAGS "${_python_abi_flags}"
CACHE STRING "The ABI flags for the version of Python being used")
mark_as_advanced(PYTHON_ABIFLAGS)
###
# Python dependencies
#
# Add python packages needed to execute the bindings
# to requirements.txt file
#
# TODO: Just copy the requirements/* stuff into the build tree? Why is this necessary?
#
#list(APPEND PYTHON_REQS "numpy>=1.13.0,<=1.19.0")
#
#if(SKBUILD)
# list(APPEND PYTHON_REQS "scikit-build<=0.11.1")
#endif()
#
#if(KWIVER_ENABLE_PYTORCH)
# list(APPEND PYTHON_REQS "opencv-python>=3.4.2.17,<=4.0.0"
# "pillow>=7.0.0,<=7.1.2"
# "scipy>=1.2,<=1.5"
# "torch==1.4.0"
# "torchvision==0.5.0"
# )
#endif()
###
# PyBind11
#
#
#
find_package(pybind11 REQUIRED)
###
# Python Dependencies
#
# sets the python dependencies defined in python/requirements.txt
# to be a custom command of the python libraries target
# a venv will be created to encapsulate the pip installed dependencies
# from the larger system, while still providing the tests access to their dependencies
#
if (KWIVER_ENABLE_TESTS)
_ensure_pypackage_exists("pytest")
endif()
###
# Python package build locations
#
# defines paths used to determine where the kwiver/sprokit/vital python
# packages will be generated in the build tree. (TODO: python modules should
# use a setup.py file to install themselves to the right location)
#
#set(kwiver_python_subdir "python${PYTHON_VERSION}${PYTHON_ABIFLAGS}")
# Instead of contructing the directory with ABIFLAGS just use what python gives us
get_filename_component(python_lib_subdir ${python_site_packages} DIRECTORY)
get_filename_component(python_subdir ${python_lib_subdir} NAME)
set(kwiver_python_subdir ${python_subdir})
set(kwiver_python_output_path "${KWIVER_BINARY_DIR}/${python_lib_subdir}")
# Currently needs to be separate because sprokit may have CONFIGURATIONS that
# are placed between lib and `kwiver_python_subdir`
set(sprokit_python_output_path "${KWIVER_BINARY_DIR}/lib")
set(KWIVER_PYTHON_VERSION "${PYTHON_VERSION}" CACHE STRING "" )
mark_as_advanced(KWIVER_PYTHON_VERSION)
###
# Status string for debugging
#
set(PYTHON_CONFIG_STATUS "
PYTHON_CONFIG_STATUS
* KWIVER_PYTHON_MAJOR_VERSION = \"${KWIVER_PYTHON_MAJOR_VERSION}\"
* PYTHON_EXECUTABLE = \"${PYTHON_EXECUTABLE}\"
* PYTHON_INCLUDE_DIR = \"${PYTHON_INCLUDE_DIR}\"
* PYTHON_LIBRARIES = \"${PYTHON_LIBRARIES}\"
* PYTHON_LIBRARIES_DEBUG = \"${PYTHON_LIBRARIES_DEBUG}\"
* PYTHON_ABIFLAGS = \"${PYTHON_ABIFLAGS}\"
* PYTHON_VERSION = \"${PYTHON_VERSION}\"
* python_site_packages = \"${python_site_packages}\"
* python_sitename = \"${python_sitename}\"
* kwiver_python_subdir = \"${kwiver_python_subdir}\"
* kwiver_python_install_path = \"${kwiver_python_install_path}\"
* kwiver_python_output_path = \"${kwiver_python_output_path}\"
* sprokit_python_output_path = \"${sprokit_python_output_path}\"
")
message(STATUS "${PYTHON_CONFIG_STATUS}")
_ensure_pypackage_exists("pygccxml")
_ensure_pypackage_exists("castxml")