forked from SFTtech/openage
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpython.cmake
More file actions
381 lines (311 loc) · 13.2 KB
/
python.cmake
File metadata and controls
381 lines (311 loc) · 13.2 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
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
# Copyright 2014-2016 the openage authors. See copying.md for legal info.
# provides macros for defining python extension modules and pxdgen sources.
# and a 'finalize' function that must be called in the end.
function(python_init)
# filled by pxdgen; written to bin/py/pxdgen_sources for use by pxdgen.py.
set_property(GLOBAL PROPERTY SFT_PXDGEN_SOURCES)
# filled by add_cython_modules. used by cythonize.py.
set_property(GLOBAL PROPERTY SFT_CYTHON_MODULES)
set_property(GLOBAL PROPERTY SFT_CYTHON_MODULES_EMBED)
# filled by pxdgen and add_pxd. for use as depends list for cythonize.py.
set_property(GLOBAL PROPERTY SFT_PXD_FILES)
# filled by pxdgen. for use as output list for the pxdgen target.
set_property(GLOBAL PROPERTY SFT_GENERATED_PXD_FILES)
# filled with all .py filenames; used for installing.
set_property(GLOBAL PROPERTY SFT_PY_FILES)
# filled with the relative source dirs of the above py files.
set_property(GLOBAL PROPERTY SFT_PY_FILES_RELSRCDIRS)
# filled with all .py filenames that should not be installed
set_property(GLOBAL PROPERTY SFT_PY_FILES_NOINSTALL)
# filled with all cython module target names; used for in-place creation.
set_property(GLOBAL PROPERTY SFT_CYTHON_MODULE_TARGETS)
endfunction()
function(add_cython_modules)
# adds a new module for cython compilation, by relative filename.
# synoposis:
# add_cython_modules(
# test.pyx
# EMBED __main__.pyx
# STANDALONE EMBED foo/bar.pyx
# NOINSTALL STANDALONE foo/test.pyx
# )
#
# test.pyx is compiled to a shared library linked against PYEXT_LINK_LIBRARY
# __main__.pyx is compiled to a executable with embedded python interpreter,
# linked against libpython and PYEXT_LINK_LIBRARY.
# foo/bar.pyx is compiled to a executable with embedded pytthon interpreter,
# linked only against libpython.
# foo/test.pyx is compiled to a shared library linked against nothing, and will
# not be installed.
file(RELATIVE_PATH REL_CURRENT_SOURCE_DIR
"${CMAKE_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}")
set(EMBED_NEXT FALSE)
set(STANDALONE_NEXT FALSE)
set(NOINSTALL_NEXT FALSE)
foreach(source ${ARGN})
if(source STREQUAL "EMBED")
set(EMBED_NEXT TRUE)
elseif(source STREQUAL "STANDALONE")
set(STANDALONE_NEXT TRUE)
elseif(source STREQUAL "NOINSTALL")
set(NOINSTALL_NEXT TRUE)
else()
if(NOT IS_ABSOLUTE "${source}")
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
endif()
if(NOT "${source}" MATCHES ".*\\.pyx?$")
message(FATAL_ERROR "non-.py/.pyx file given to add_cython_modules: ${source}")
endif()
get_filename_component(OUTPUTNAME "${source}" NAME_WE)
string(REGEX REPLACE "\\.pyx?$" ".cpp" CPPNAME "${source}")
set_source_files_properties("${CPPNAME}" PROPERTIES GENERATED ON)
# construct some hopefully unique target name
file(RELATIVE_PATH TARGETNAME "${CMAKE_SOURCE_DIR}" "${source}")
string(REGEX REPLACE "\\.pyx?$" "" TARGETNAME "${TARGETNAME}")
string(REGEX REPLACE "/" "_" TARGETNAME "${TARGETNAME}")
# generate the pretty module name
file(RELATIVE_PATH PRETTY_MODULE_NAME "${CMAKE_SOURCE_DIR}" "${source}")
string(REGEX REPLACE "\\.pyx?$" "" PRETTY_MODULE_NAME "${PRETTY_MODULE_NAME}")
string(REGEX REPLACE "/" "." PRETTY_MODULE_NAME "${PRETTY_MODULE_NAME}")
set(PRETTY_MODULE_PROPERTIES "")
if(EMBED_NEXT)
set(PRETTY_MODULE_PROPERTIES "${PRETTY_MODULE_PROPERTIES} [embedded interpreter]")
set_property(GLOBAL APPEND PROPERTY SFT_CYTHON_MODULES_EMBED "${source}")
add_executable("${TARGETNAME}" "${CPPNAME}")
# TODO: use full ldflags and cflags provided by python${VERSION}-config
target_link_libraries("${TARGETNAME}" "${PYEXT_LIBRARY}")
else()
set_property(GLOBAL APPEND PROPERTY SFT_CYTHON_MODULES "${source}")
add_library("${TARGETNAME}" MODULE "${CPPNAME}")
set_target_properties("${TARGETNAME}" PROPERTIES
PREFIX ""
SUFFIX "${PYEXT_SUFFIX}"
)
endif()
if(NOINSTALL_NEXT)
set(PRETTY_MODULE_PROPERTIES "${PRETTY_MODULE_PROPERTIES} [noinstall]")
else()
install(
TARGETS "${TARGETNAME}"
DESTINATION "${CMAKE_PY_INSTALL_PREFIX}/${REL_CURRENT_SOURCE_DIR}"
)
endif()
set_target_properties("${TARGETNAME}" PROPERTIES
COMPILE_FLAGS "${PYEXT_CXXFLAGS}"
INCLUDE_DIRECTORIES "${PYEXT_INCLUDE_DIRS}"
OUTPUT_NAME "${OUTPUTNAME}"
)
if (STANDALONE_NEXT)
set(PRETTY_MODULE_PROPERTIES "${PRETTY_MODULE_PROPERTIES} [standalone]")
else()
set_target_properties("${TARGETNAME}" PROPERTIES LINK_DEPENDS_NO_SHARED 1)
target_link_libraries("${TARGETNAME}" "${PYEXT_LINK_LIBRARY}")
endif()
# Since this module is not embedded with python interpreter,
# Mac OS X requires a link flag to resolve undefined symbols
if(NOT EMBED_NEXT AND APPLE)
set_target_properties("${TARGETNAME}" PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" )
endif()
add_dependencies("${TARGETNAME}" cythonize)
set_property(GLOBAL APPEND PROPERTY SFT_CYTHON_MODULE_TARGETS "${TARGETNAME}")
pretty_print_target("cython module" "${PRETTY_MODULE_NAME}" "${PRETTY_MODULE_PROPERTIES}")
# Reset the flags before processing the next cython module
set(EMBED_NEXT FALSE)
set(NOINSTALL_NEXT FALSE)
set(STANDALONE_NEXT FALSE)
endif()
endforeach()
endfunction()
function(pxdgen)
# add a C++ header file as pxdgen source file
foreach(source ${ARGN})
if(NOT IS_ABSOLUTE "${source}")
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
endif()
if(NOT "${source}" MATCHES ".*\\.h$")
message(FATAL_ERROR "non-.h file given to pxdgen: ${source}")
endif()
string(REGEX REPLACE "\\.h$" ".pxd" PXDNAME "${source}")
set_source_files_properties("${PXDNAME}" PROPERTIES GENERATED ON)
set_property(GLOBAL APPEND PROPERTY SFT_PXDGEN_SOURCES "${source}")
set_property(GLOBAL APPEND PROPERTY SFT_PXD_FILES "${PXDNAME}")
set_property(GLOBAL APPEND PROPERTY SFT_GENERATED_PXD_FILES "${PXDNAME}")
endforeach()
endfunction()
function(add_pxds)
# add a .pxd or other additional Cython source
foreach(source ${ARGN})
if(NOT IS_ABSOLUTE "${source}")
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
endif()
if(NOT "${source}" MATCHES ".*\\.px[id]$")
message(FATAL_ERROR "non-pxd/pxi file given to add_pyd: ${source}")
endif()
set_property(GLOBAL APPEND PROPERTY SFT_PXD_FILES "${source}")
endforeach()
endfunction()
function(add_py_modules)
# add a .py file for installing
file(RELATIVE_PATH REL_CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
set(NOINSTALL_NEXT FALSE)
foreach(source ${ARGN})
if(source STREQUAL "NOINSTALL")
set(NOINSTALL_NEXT TRUE)
else()
if(NOT ${source} MATCHES ".*\\.py$")
message(FATAL_ERROR "non-Python file given to add_py_modules: ${source}")
endif()
if(NOT IS_ABSOLUTE ${source})
set(source "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
endif()
if(NOINSTALL_NEXT)
set_property(GLOBAL APPEND PROPERTY SFT_PY_FILES_NOINSTALL "${source}")
set(NOINSTALL_NEXT FALSE)
endif()
set_property(GLOBAL APPEND PROPERTY SFT_PY_FILES "${source}")
set_property(GLOBAL APPEND PROPERTY SFT_PY_FILES_RELSRCDIRS "${REL_CURRENT_SOURCE_DIR}")
endif()
endforeach()
endfunction()
function(python_finalize)
# pxdgen (.h -> .pxd)
get_property(pxdgen_sources GLOBAL PROPERTY SFT_PXDGEN_SOURCES)
get_property(generated_pxd_list GLOBAL PROPERTY SFT_GENERATED_PXD_FILES)
write_on_change("${CMAKE_BINARY_DIR}/py/pxdgen_sources" "${pxdgen_sources}")
set(PXDGEN_TIMEFILE "${CMAKE_BINARY_DIR}/py/pxdgen_timefile")
add_custom_command(OUTPUT "${PXDGEN_TIMEFILE}" ${generated_pxd_list}
COMMAND "${PYTHON}" -m buildsystem.pxdgen
--file-list "${CMAKE_BINARY_DIR}/py/pxdgen_sources"
COMMAND "${CMAKE_COMMAND}" -E touch "${PXDGEN_TIMEFILE}"
DEPENDS ${pxdgen_sources} "${CMAKE_BINARY_DIR}/py/pxdgen_sources"
COMMENT "pxdgen: generating .pxd files from headers"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
add_custom_target(pxdgen ALL DEPENDS "${PXDGEN_TIMEFILE}")
# cythonize (.pyx -> .cpp)
get_property(cython_modules GLOBAL PROPERTY SFT_CYTHON_MODULES)
write_on_change("${CMAKE_BINARY_DIR}/py/cython_modules" "${cython_modules}")
get_property(cython_modules_embed GLOBAL PROPERTY SFT_CYTHON_MODULES_EMBED)
write_on_change("${CMAKE_BINARY_DIR}/py/cython_modules_embed" "${cython_modules_embed}")
get_property(pxd_list GLOBAL PROPERTY SFT_PXD_FILES)
write_on_change("${CMAKE_BINARY_DIR}/py/pxd_list" "${pxd_list}")
set(CYTHONIZE_TIMEFILE "${CMAKE_BINARY_DIR}/py/cythonize_timefile")
add_custom_command(OUTPUT "${CYTHONIZE_TIMEFILE}"
COMMAND "${PYTHON}" -m buildsystem.cythonize
"${CMAKE_BINARY_DIR}/py/cython_modules"
"${CMAKE_BINARY_DIR}/py/cython_modules_embed"
"${CMAKE_BINARY_DIR}/py/pxd_list"
COMMAND "${CMAKE_COMMAND}" -E touch "${CYTHONIZE_TIMEFILE}"
DEPENDS
"${PXDGEN_TIMEFILE}"
${cython_modules}
${cython_modules_embed}
${pxd_list}
"${CMAKE_BINARY_DIR}/py/cython_modules"
"${CMAKE_BINARY_DIR}/py/cython_modules_embed"
"${CMAKE_BINARY_DIR}/py/pxd_list"
COMMENT "cythonize.py: compiling .pyx files to .cpp"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
add_custom_target(cythonize ALL DEPENDS "${CYTHONIZE_TIMEFILE}")
# py compile (.py -> .pyc)
set_property(GLOBAL APPEND PROPERTY SFT_PY_FILES_RELSRCDIRS "lol test")
get_property(py_files GLOBAL PROPERTY SFT_PY_FILES)
get_property(py_files_srcdirs GLOBAL PROPERTY SFT_PY_FILES_RELSRCDIRS)
get_property(py_files_noinstall GLOBAL PROPERTY SFT_PY_FILES_NOINSTALL)
write_on_change("${CMAKE_BINARY_DIR}/py/py_files" "${py_files}")
set(COMPILEPY_TIMEFILE "${CMAKE_BINARY_DIR}/py/compilepy_timefile")
add_custom_command(OUTPUT "${COMPILEPY_TIMEFILE}"
COMMAND "${PYTHON}" -m buildsystem.compilepy
"${CMAKE_BINARY_DIR}/py/py_files"
"${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}"
COMMAND "${CMAKE_COMMAND}" -E touch "${COMPILEPY_TIMEFILE}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
DEPENDS "${CMAKE_BINARY_DIR}/py/py_files" ${py_files}
COMMENT "compiling .py files to .pyc files"
)
add_custom_target(compilepy ALL DEPENDS "${COMPILEPY_TIMEFILE}")
# determine the compiled file name for all source files
# avoid doing this call for each file, instead, batch-process.
# BUT: i'm unsure when exactly this is called again
# (if a new file was added to the py_files?)
py_exec("from importlib import util; print(';'.join(util.cache_from_source(f) for f in open('${CMAKE_BINARY_DIR}/py/py_files').read().split(';')))" py_compiled_files)
list(LENGTH py_files py_files_count)
math(EXPR py_files_count_range "${py_files_count} - 1")
foreach(idx RANGE ${py_files_count_range})
list(GET py_files ${idx} pyfile)
list(GET py_compiled_files ${idx} pycfile)
list(GET py_files_srcdirs ${idx} pyrelsrcdir)
# install if it's not in that list.
list(FIND py_files_noinstall "${pyfile}" do_install)
if(do_install)
install(
FILES "${pyfile}"
DESTINATION "${CMAKE_PY_INSTALL_PREFIX}/${pyrelsrcdir}"
)
install(
FILES "${pycfile}"
DESTINATION "${CMAKE_PY_INSTALL_PREFIX}/${pyrelsrcdir}/__pycache__"
)
endif()
endforeach()
# inplace module install (bin/module.so -> module.so)
get_property(cython_module_targets GLOBAL PROPERTY SFT_CYTHON_MODULE_TARGETS)
set(cython_module_files_expr)
foreach(cython_module_target ${cython_module_targets})
list(APPEND cython_module_files_expr "$<TARGET_FILE:${cython_module_target}>")
endforeach()
file(GENERATE
OUTPUT "${CMAKE_BINARY_DIR}/py/inplace_module_list"
CONTENT "${cython_module_files_expr}"
)
set(INPLACEMODULES_TIMEFILE "${CMAKE_BINARY_DIR}/py/inplacemodules_timefile")
add_custom_command(OUTPUT "${INPLACEMODULES_TIMEFILE}"
COMMAND "${PYTHON}" -m buildsystem.inplacemodules
"${CMAKE_BINARY_DIR}/py/inplace_module_list"
"${CMAKE_BINARY_DIR}"
DEPENDS
"${CMAKE_BINARY_DIR}/py/inplace_module_list"
${cython_module_targets}
COMMAND "${CMAKE_COMMAND}" -E touch "${INPLACEMODULES_TIMEFILE}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "creating in-place modules"
)
add_custom_target(inplacemodules ALL DEPENDS "${INPLACEMODULES_TIMEFILE}")
# cleaning of all in-sourcedir stuff
add_custom_target(cleancython
COMMAND "${PYTHON}" -m buildsystem.inplacemodules --clean
"${CMAKE_BINARY_DIR}/py/inplace_module_list"
"${CMAKE_BINARY_DIR}"
COMMAND "${PYTHON}" -m buildsystem.cythonize --clean
"${CMAKE_BINARY_DIR}/py/cython_modules"
"${CMAKE_BINARY_DIR}/py/cython_modules_embed"
"${CMAKE_BINARY_DIR}/py/pxd_list"
# general deleters to catch files that have already been un-listed.
COMMAND find openage -name "*.cpp" -type f -print -delete
COMMAND find openage -name "*.html" -type f -print -delete
COMMAND find openage -name "*.so" -type f -print -delete
COMMAND "${CMAKE_COMMAND}" -E remove "${CYTHONIZE_TIMEFILE}"
COMMAND "${CMAKE_COMMAND}" -E remove "${INPLACEMODULES_TIMEFILE}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
add_custom_target(cleanpxdgen
COMMAND find libopenage -name "*.pxd" -type f -print -delete
COMMAND find libopenage -name "__init__.py" -type f -print -delete
COMMAND "${CMAKE_COMMAND}" -E remove "${PXDGEN_TIMEFILE}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
# check for any unlisted .py files, and error.
execute_process(
COMMAND "${PYTHON}" -m buildsystem.check_py_file_list
${CMAKE_BINARY_DIR}/py/py_files
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE res
)
if(NOT res EQUAL 0)
message(FATAL_ERROR ".py file listing inconsistent")
endif()
endfunction()
python_init()