-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathmeson.build
More file actions
460 lines (427 loc) · 16 KB
/
Copy pathmeson.build
File metadata and controls
460 lines (427 loc) · 16 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
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
project('scs', 'c', default_options: ['b_lto=true'])
py = import('python').find_installation(pure: false)
cc = meson.get_compiler('c')
fs = import('fs')
# Check for submodule before doing anything else
if not fs.exists('scs_source/README.md')
error('Missing the `scs_source` submodule! Run `git submodule update --init` to fix this.')
endif
# Simpler check for numpy
incdir_numpy = run_command(py,['-c',
'''import os
import numpy as np
try:
incdir = os.path.relpath(np.get_include())
except Exception:
incdir = np.get_include()
print(incdir)
'''], check: true).stdout().strip()
# Get BLAS
#
# link_mkl links every extension against a dynamic MKL from the environment
# (conda/source builds). mkl_static_prefix builds only _scs_mkl, with MKL
# linked statically, while every other extension uses the platform BLAS: the
# x86-64 Linux wheel configuration (see pyproject.toml for why).
blas_deps = []
mkl_blas_deps = []
mkl_pkg_name = ''
mkl_static_prefix = get_option('mkl_static_prefix')
if get_option('link_mkl') and mkl_static_prefix != ''
error('link_mkl and mkl_static_prefix are mutually exclusive.')
endif
if get_option('link_mkl')
if get_option('use_blas64') and get_option('int32')
error('MKL BLAS64 requires 64-bit SCS integers. Re-run Meson with -Dint32=false.')
endif
# Link against MKL component libraries. The integer width must match:
# use_blas64=false (default) -> LP64 (32-bit BLAS integers)
# use_blas64=true -> ILP64 (64-bit BLAS integers)
#
# Note: PARDISO integer width is independent — it is controlled by the
# pardiso vs pardiso_64 entry point (selected via DLONG), not by the
# interface layer. See linsys/mkl/direct/private.c for details.
# Prefer Intel OpenMP (iomp) for multi-threaded MKL, fall back to
# sequential if iomp is not available.
#
# TODO: On Windows the conda MKL iomp .pc file (mkl-dynamic-*-iomp)
# has broken Cflags (raw path without -I prefix). Revisit once Intel
# ships a fixed pkg-config file; until then Windows gets sequential MKL.
if get_option('use_blas64')
_mkl_iomp = 'mkl-dynamic-ilp64-iomp'
_mkl_seq = 'mkl-dynamic-ilp64-seq'
else
_mkl_iomp = 'mkl-dynamic-lp64-iomp'
_mkl_seq = 'mkl-dynamic-lp64-seq'
endif
if host_machine.system() == 'windows'
# On Windows the conda MKL iomp .pc file has broken Cflags (raw path
# without -I prefix). Use sequential MKL until Intel ships a fix.
mkl_blas_deps = [dependency(_mkl_seq, required : false)]
if mkl_blas_deps[0].found()
mkl_pkg_name = _mkl_seq
endif
else
mkl_blas_deps = [dependency(_mkl_iomp, required : false)]
if not mkl_blas_deps[0].found()
mkl_blas_deps = [dependency(_mkl_seq, required : false)]
if mkl_blas_deps[0].found()
mkl_pkg_name = _mkl_seq
endif
else
mkl_pkg_name = _mkl_iomp
endif
endif
if not mkl_blas_deps[0].found()
mkl_blas_deps = [cc.find_library('mkl_rt', required : false)]
endif
if not mkl_blas_deps[0].found()
mkl_blas_deps = [dependency('mkl-sdl', required : false)]
endif
if not mkl_blas_deps[0].found() and not get_option('sdist_mode')
error('link_mkl was requested but MKL was not found.')
endif
endif
if get_option('link_mkl')
blas_deps = mkl_blas_deps
else
if host_machine.system() == 'darwin'
blas_deps = [dependency('Accelerate')]
else
blas_deps = [cc.find_library('openblas', static: get_option('link_blas_statically'), required : false)]
if not blas_deps[0].found()
blas_deps = [dependency(['openblas', 'OpenBLAS'], static: get_option('link_blas_statically'), required : false)]
endif
endif
# try to find blas/cblas (e.g., Linux)
if not blas_deps[0].found()
blas_deps = [cc.find_library('blas', static: get_option('link_blas_statically'), required : false)]
if not blas_deps[0].found()
blas_deps = [dependency('blas', static: get_option('link_blas_statically'), required : false)]
endif
lapack_dep = cc.find_library('lapack', static: get_option('link_blas_statically'), required : false)
if not lapack_dep.found()
lapack_dep = dependency('lapack', static: get_option('link_blas_statically'), required : false)
endif
if lapack_dep.found()
blas_deps += lapack_dep
endif
cblas_dep = cc.find_library('cblas', static: get_option('link_blas_statically'), required : false)
if not cblas_dep.found()
cblas_dep = dependency('cblas', static: get_option('link_blas_statically'), required : false)
endif
if cblas_dep.found()
blas_deps += cblas_dep
endif
endif
endif
# Since nothing above was required, we stop here if failed.
# When creating an sdist we are not compiling / linking, so don't need to fail.
if not blas_deps[0].found() and not get_option('sdist_mode')
error('OpenBLAS or Netlib BLAS/CBLAS is required on all platforms, and was not found.')
endif
# Common
common_c_args = cc.get_supported_arguments(
'-Wno-unused-result',
'-fno-math-errno', # math fns need not set errno; SCS never checks it
'-funroll-loops', # matches scs.mk; benefits tight ADMM iteration loops
) + ['-DPYTHON', '-DCTRLC=1']
common_includes = [
'scs',
'scs_source/include',
'scs_source/linsys',
incdir_numpy
]
if get_option('native_arch')
native_flag = cc.get_supported_arguments('-march=native')
if native_flag.length() > 0
common_c_args += native_flag
else
warning('native_arch requested but -march=native is not supported by this compiler')
endif
endif
_base_deps = [dependency('threads')]
if get_option('use_openmp')
_base_deps += dependency('openmp')
endif
_deps = [blas_deps] + _base_deps
is_linux = host_machine.system() == 'linux'
if is_linux
_deps += cc.find_library('rt', required : true)
endif
if get_option('use_lapack')
common_c_args += '-DUSE_LAPACK=1'
endif
use_spectral_cones = get_option('use_spectral_cones')
if use_spectral_cones
if not get_option('use_lapack')
error('Spectral cones require LAPACK. Please re-run Meson with -Duse_lapack=true')
endif
common_c_args += '-DUSE_SPECTRAL_CONES=1'
endif
if get_option('use_singleprec')
common_c_args += '-DSFLOAT=1'
endif
if get_option('use_blas64')
if not get_option('link_mkl')
# Declaring 64-bit BLAS integers while linking an LP64 BLAS (the standard
# Accelerate/OpenBLAS builds) corrupts every BLAS call; only the MKL ILP64
# configuration is verified.
error('use_blas64=true requires link_mkl=true (ILP64 MKL).')
endif
common_c_args += '-DBLAS64=1'
endif
if get_option('use_extraverbose')
common_c_args += '-DVERBOSITY=999'
endif
is_gpu_build = get_option('use_gpu') or get_option('link_cudss')
use_32bit_ints = get_option('int32')
if is_gpu_build and not use_32bit_ints
error('GPU builds require 32-bit integers. Please re-run Meson with -Dint32=true')
endif
if not use_32bit_ints
common_c_args += '-DDLONG=1'
endif
cuda_dep = dependency('cuda', required: is_gpu_build)
if is_gpu_build and not cuda_dep.found()
error('GPU build requested but CUDA toolkit was not found.')
endif
# Sources
scs_core_sources = files(
'scs_source/src/aa.c',
'scs_source/src/cones.c',
'scs/py_ctrlc.c',
'scs_source/src/exp_cone.c',
'scs_source/src/linalg.c',
'scs_source/src/normalize.c',
'scs_source/src/rw.c',
'scs_source/src/scs_version.c',
'scs_source/src/scs.c',
'scs_source/src/util.c'
)
common_linsys_sources = files(
'scs_source/linsys/scs_matrix.c',
'scs_source/linsys/csparse.c'
)
spectral_cone_sources = []
if use_spectral_cones
spectral_cone_sources = files(
'scs_source/src/spectral_cones/logdeterminant/log_cone_Newton.c',
'scs_source/src/spectral_cones/logdeterminant/log_cone_IPM.c',
'scs_source/src/spectral_cones/logdeterminant/log_cone_wrapper.c',
'scs_source/src/spectral_cones/logdeterminant/logdet_cone.c',
'scs_source/src/spectral_cones/nuclear/ell1_cone.c',
'scs_source/src/spectral_cones/nuclear/nuclear_cone.c',
'scs_source/src/spectral_cones/sum-largest/sum_largest_cone.c',
'scs_source/src/spectral_cones/sum-largest/sum_largest_eval_cone.c',
'scs_source/src/spectral_cones/util_spectral_cones.c',
)
endif
amd_sources = files(
'scs_source/linsys/external/amd/amd_1.c',
'scs_source/linsys/external/amd/amd_2.c',
'scs_source/linsys/external/amd/amd_aat.c',
'scs_source/linsys/external/amd/amd_control.c',
'scs_source/linsys/external/amd/amd_defaults.c',
'scs_source/linsys/external/amd/amd_dump.c',
'scs_source/linsys/external/amd/amd_global.c',
'scs_source/linsys/external/amd/amd_info.c',
'scs_source/linsys/external/amd/amd_order.c',
'scs_source/linsys/external/amd/amd_post_tree.c',
'scs_source/linsys/external/amd/amd_postorder.c',
'scs_source/linsys/external/amd/amd_preprocess.c',
'scs_source/linsys/external/amd/amd_valid.c',
'scs_source/linsys/external/amd/SuiteSparse_config.c'
)
# Build modules
scs_dir = py.get_install_dir() / 'scs'
py.extension_module(
'_scs_direct',
'scs/scspy.c',
'scs_source/linsys/cpu/direct/private.c',
'scs_source/linsys/external/qdldl/qdldl.c',
common_linsys_sources,
scs_core_sources,
amd_sources,
spectral_cone_sources,
c_args: common_c_args,
include_directories: common_includes + [
'scs_source/linsys/cpu/direct',
'scs_source/linsys/external/qdldl',
'scs_source/linsys/external/amd'
],
dependencies: _deps,
install_dir: scs_dir,
install: true,
)
py.extension_module(
'_scs_indirect',
'scs/scspy.c',
'scs_source/linsys/cpu/indirect/private.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
c_args: common_c_args + ['-DPY_INDIRECT', '-DINDIRECT=1'],
include_directories: common_includes + ['scs_source/linsys/cpu/indirect'],
dependencies: _deps,
install_dir: scs_dir,
install: true,
)
if get_option('use_lapack')
py.extension_module(
'_scs_dense',
'scs/scspy.c',
'scs_source/linsys/cpu/dense/private.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
c_args: common_c_args + ['-DPY_DENSE'],
include_directories: common_includes + ['scs_source/linsys/cpu/dense'],
dependencies: _deps,
install_dir: scs_dir,
install: true,
)
endif
if get_option('use_gpu')
gpu_c_args = common_c_args + ['-DPY_GPU=1', '-DINDIRECT=1']
cublas_dep = cc.find_library('cublas', required: false)
if not cublas_dep.found()
cublas_dep = dependency('cublas', required: true)
endif
cusparse_dep = cc.find_library('cusparse', required: false)
if not cusparse_dep.found()
cusparse_dep = dependency('cusparse', required: true)
endif
# Scope the CUDA libraries to this target rather than mutating the shared
# `_deps`, so they don't leak into _scs_mkl / _scs_accelerate / _scs_cudss
# when use_gpu is combined with those backends.
gpu_deps = _deps + [cuda_dep, cublas_dep, cusparse_dep]
if get_option('gpu_atrans')
gpu_c_args += '-DGPU_TRANSPOSE_MAT=1'
endif
py.extension_module(
'_scs_gpu',
'scs/scspy.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
# In Meson, sources with a `.cu` extension are compiled with nvcc by default.
# To compile `.c` files with nvcc, they must be explicitly targeted.
# It is strongly recommended to rename CUDA-C files to `.cu`.
# Meson's fs module has no glob(), so these are listed explicitly; keep in
# sync with the .c files under scs_source/linsys/gpu{,/indirect}.
'scs_source/linsys/gpu/gpu.c',
'scs_source/linsys/gpu/indirect/private.c',
c_args: gpu_c_args,
dependencies: gpu_deps,
include_directories: [
common_includes, 'scs_source/linsys/gpu/', 'scs_source/linsys/gpu/indirect'
],
install: true,
install_dir: scs_dir,
)
endif
if get_option('link_mkl')
# The MKL backend calls MKL_Set_Interface_Layer() for a runtime interface
# check. This symbol is only exported by mkl_rt (the single dynamic library),
# not by component libraries (mkl_intel_lp64 etc.) that pkg-config may link.
# Add mkl_rt explicitly so the symbol is always available.
mkl_rt_dep = dependency('mkl-sdl', required : false)
if not mkl_rt_dep.found()
mkl_rt_dep = cc.find_library('mkl_rt', required : false)
endif
if not mkl_rt_dep.found() and mkl_pkg_name != ''
# Search next to the pkg-config-provided MKL component libraries.
_mkl_libdir = mkl_blas_deps[0].get_variable(pkgconfig: 'libdir', default_value: '')
if _mkl_libdir != ''
mkl_rt_dep = cc.find_library('mkl_rt', dirs: [_mkl_libdir], required : false)
endif
endif
if not mkl_rt_dep.found()
error('link_mkl requires mkl_rt (or mkl-sdl). _scs_mkl calls MKL_Set_Interface_Layer() at startup and cannot be built safely without it.')
endif
_mkl_deps = _deps + [mkl_rt_dep]
# The core's reference to MKL_Set_Interface_Layer is weak (static MKL has
# no mkl_rt), so with --as-needed the linker would drop mkl_rt, the
# symbol would resolve to NULL and the interface-layer guard would be
# skipped. Keep mkl_rt a hard dependency of the dynamic build.
_mkl_link_args = is_linux ? ['-Wl,--no-as-needed'] : []
elif mkl_static_prefix != ''
# Intel's mkl-static archives: LP64, sequential, linked as a group (they
# reference each other) with every MKL symbol hidden so an MKL already in
# the process is never interposed. The core's MKL_Set_Interface_Layer
# reference is weak, so the mkl_rt-only runtime check is skipped.
if get_option('use_blas64')
error('mkl_static_prefix links the LP64 interface; use link_mkl for ILP64 MKL builds.')
endif
_mkl_lib = mkl_static_prefix / 'lib'
_mkl_archives = []
foreach _a : ['libmkl_intel_lp64.a', 'libmkl_sequential.a', 'libmkl_core.a']
if not fs.exists(_mkl_lib / _a)
error('mkl_static_prefix: ' + (_mkl_lib / _a) + ' not found (pip install mkl-static).')
endif
_mkl_archives += _mkl_lib / _a
endforeach
_mkl_deps = _base_deps + [cc.find_library('dl'), cc.find_library('m'), cc.find_library('rt')]
_mkl_link_args = ['-Wl,--start-group'] + _mkl_archives + ['-Wl,--end-group', '-Wl,--exclude-libs,ALL']
# Intel Simplified Software License: the notice ships with the binaries.
install_data('LICENSE-INTEL-MKL.txt', install_dir: scs_dir)
endif
if get_option('link_mkl') or mkl_static_prefix != ''
py.extension_module(
'_scs_mkl',
'scs/scspy.c',
'scs_source/linsys/mkl/direct/private.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
c_args: common_c_args + ['-DPY_MKL', '-DSCS_MKL=1'],
include_directories: common_includes + ['scs_source/linsys/mkl/direct'],
dependencies: _mkl_deps,
link_args: _mkl_link_args,
install_dir: scs_dir,
install: true,
)
endif
# Apple Accelerate backend (macOS only, requires 32-bit ints)
if host_machine.system() == 'darwin'
# Filter out DLONG from c_args since Accelerate requires 32-bit integers
accel_c_args = []
foreach arg : common_c_args
if arg != '-DDLONG=1'
accel_c_args += arg
endif
endforeach
py.extension_module(
'_scs_accelerate',
'scs/scspy.c',
'scs_source/linsys/accelerate/direct/private.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
c_args: accel_c_args + ['-DPY_ACCELERATE'],
include_directories: common_includes + ['scs_source/linsys/accelerate/direct'],
dependencies: _deps,
install_dir: scs_dir,
install: true,
)
endif
if get_option('link_cudss')
cudss_dep = dependency('cudss', required: true)
# Scope the CUDA libraries to this target rather than mutating the shared
# `_deps` (see the use_gpu block above).
cudss_deps = _deps + [cuda_dep, cudss_dep]
py.extension_module(
'_scs_cudss',
'scs/scspy.c',
'scs_source/linsys/cudss/direct/private.c',
common_linsys_sources,
scs_core_sources,
spectral_cone_sources,
c_args: common_c_args + ['-DPY_CUDSS'],
include_directories: common_includes + ['scs_source/linsys/cudss/direct'],
dependencies: cudss_deps,
install_dir: scs_dir,
install: true,
)
endif
py.install_sources('scs/py/__init__.py', subdir: 'scs')