-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmeson.build
More file actions
1092 lines (987 loc) · 43 KB
/
Copy pathmeson.build
File metadata and controls
1092 lines (987 loc) · 43 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
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
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
## scikit-plots/meson.build
# Authors: The scikit-plots developers
# SPDX-License-Identifier: BSD-3-Clause
######################################################################
## Project
## https://mesonbuild.com/Syntax.html#syntax
######################################################################
# Project configuration
project(
'scikit-plots',
'c', 'cpp', 'cython', #'python',
# Note that the git commit hash cannot be added dynamically here
# That only happens when importing from a git repository.
# See `lightnumpy/__init__.py`
version: run_command(
# ['python', 'lightnumpy/_build_utils/version.py'],
# This should become `lightnumpy/_version.py` in 'scikit-plots'
['lightnumpy/_build_utils/gitversion.py'],
check: true,
).stdout().strip(),
meson_version: '>= 1.5.0',
license: 'BSD-3-Clause', # Valid SPDX license expression: 'MIT', 'Apache-2.0', 'GPL-3.0-or-later'
# license-files = ['LICENSE', 'LICENSES/...'], # list[file] COPYING, COPYRIGHT
default_options: [
'b_ndebug=if-release',
'buildtype=debugoptimized',
'pkgconfig.relocatable=true',
'c_std=c17', # Set C standard to C17
'cpp_std=c++17', # Set C++ standard to C++17
'fortran_std=legacy',
# 'blas=openblas', # 'scipy-openblas'
# 'lapack=openblas', # 'scipy-openblas'
# https://mesonbuild.com/Builtin-options.html#details-for-warning_level
# 'warning_level=3', # You can specify warning levels here if needed
# 'werror=true', # Treat warnings as errors globally
],
)
release_version = meson.project_version()
## Get the directory relative to the top-level project directory
# project_root = meson.project_source_root()
## Get the directory relative to the current meson.build file
# current_dir = meson.current_source_dir()
## Get the directory relative to the build directory
# build_dir = meson.current_build_dir()
######################################################################
## BLAS/LAPACK dependency
######################################################################
# TODO: 64-bit BLAS and LAPACK
#
# Note that this works as long as BLAS and LAPACK are detected properly via
# pkg-config. By default we look for OpenBLAS, other libraries can be configured via
# `meson configure -Dblas=blas -Dlapack=lapack` (example to build with Netlib
# BLAS and LAPACK).
# For MKL and for auto-detecting one of multiple libs, we'll need a custom
# dependency in Meson (like is done for scalapack) - see
# https://github.com/mesonbuild/meson/issues/2835
blas_name = get_option('blas')
lapack_name = get_option('lapack')
allow_noblas = get_option('allow-noblas')
# This is currently injected directly into CFLAGS/CXXFLAGS for wheel builds
# (see cibuildwheel settings in pyproject.toml), but used by CI jobs already
blas_symbol_suffix = get_option('blas-symbol-suffix')
use_ilp64 = get_option('use-ilp64')
if use_ilp64
blas_interface = ['interface: ilp64']
else
blas_interface = ['interface: lp64']
endif
# pkg-config uses a lower-case name while CMake uses a capitalized name, so try
# that too to make the fallback detection with CMake work
blas_order = get_option('blas-order')
if blas_order == ['auto']
blas_order = []
if host_machine.system() == 'darwin'
blas_order += 'accelerate'
endif
if host_machine.cpu_family() == 'x86_64'
blas_order += 'mkl'
endif
blas_order += ['openblas', 'flexiblas', 'blis', 'blas']
endif
lapack_order = get_option('lapack-order')
if lapack_order == ['auto']
lapack_order = []
if host_machine.system() == 'darwin'
lapack_order += 'accelerate'
endif
if host_machine.cpu_family() == 'x86_64'
lapack_order += 'mkl'
endif
lapack_order += ['openblas', 'flexiblas', 'lapack']
endif
# MKL-specific options
_threading_opt = get_option('mkl-threading')
if _threading_opt == 'auto'
# Switch default to iomp once conda-forge missing openmp.pc issue is fixed
mkl_opts = ['threading: seq']
else
mkl_opts = ['threading: ' + _threading_opt]
endif
blas_opts = {'mkl': mkl_opts}
mkl_version_req = '>=2023.0' # see gh-24824
mkl_may_use_sdl = not use_ilp64 and _threading_opt in ['auto', 'iomp']
# Note that we can only use a BLAS which provides a CBLAS interface. So disable
# BLAS completely if CBLAS is not found.
# First try scipy-openblas, and if found don't look for cblas or lapack, we
# know what's inside the scipy-openblas wheels already.
if blas_name == 'openblas' or blas_name == 'auto'
blas = dependency('scipy-openblas', required: false)
if blas.found()
blas = dependency('scipy-openblas', method: 'pkg-config', required: false)
endif
if blas.found()
blas_name = 'scipy-openblas'
endif
endif
if blas_name == 'auto'
foreach _name : blas_order
if _name == 'mkl'
blas = dependency('mkl',
modules: ['cblas'] + blas_interface + mkl_opts,
required: false, # may be required, but we need to emit a custom error message
version: mkl_version_req,
)
# Insert a second try with MKL, because we may be rejecting older versions
# or missing it because no pkg-config installed. If so, we need to retry
# with MKL SDL, and drop the version constraint (this always worked).
if not blas.found() and mkl_may_use_sdl
blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false)
endif
else
if _name == 'flexiblas' and use_ilp64
_name = 'flexiblas64'
endif
blas = dependency(_name, modules: ['cblas'] + blas_interface, required: false)
endif
if blas.found()
break
endif
endforeach
else
if blas_name == 'mkl'
blas = dependency('mkl',
modules: ['cblas'] + blas_interface + mkl_opts,
required: false,
version: mkl_version_req,
)
# Same deal as above - try again for MKL
if not blas.found() and mkl_may_use_sdl
blas = dependency('mkl', modules: ['cblas', 'sdl: true'], required: false)
endif
else
blas = dependency(blas_name, modules: ['cblas'] + blas_interface, required: false)
endif
endif
have_blas = blas.found()
if have_blas
_args_blas = ['-DHAVE_CBLAS'] # note: used for C and C++ via `blas_dep` below
if use_ilp64
_args_blas += ['-DHAVE_BLAS_ILP64']
if 'openblas' in blas.name()
_args_blas += ['-DOPENBLAS_ILP64_NAMING_SCHEME']
endif
endif
if blas_symbol_suffix == 'auto'
if blas_name == 'scipy-openblas' and use_ilp64
blas_symbol_suffix = '64_'
else
blas_symbol_suffix = blas.get_variable('symbol_suffix', default_value: '')
endif
message(f'BLAS symbol suffix: @blas_symbol_suffix@')
endif
if blas_symbol_suffix != ''
_args_blas += ['-DBLAS_SYMBOL_SUFFIX=' + blas_symbol_suffix]
endif
blas_dep = declare_dependency(
dependencies: [blas],
compile_args: _args_blas,
)
else
if allow_noblas
blas_dep = []
else
error('No BLAS library detected! Install one, or use the ' + \
'`allow-noblas` build option (note, this may be up to 100x slower ' + \
'for some linear algebra operations).')
endif
endif
if 'mkl' in blas.name() or blas.name() == 'accelerate' or blas_name == 'scipy-openblas'
# For these libraries we know that they contain LAPACK, and it's desirable to
# use that - no need to run the full detection twice.
lapack = blas
else
if lapack_name == 'auto'
foreach _name : lapack_order
lapack = dependency(_name, modules: ['lapack'] + blas_interface, required: false)
if lapack.found()
break
endif
endforeach
else
lapack = dependency(lapack_name, modules: ['lapack'] + blas_interface, required: false)
endif
endif
have_lapack = lapack.found()
if not have_lapack and not allow_noblas
error('No LAPACK library detected! Install one, or use the ' + \
'`allow-noblas` build option (note, this may be up to 100x slower ' + \
'for some linear algebra operations).')
else
lapack_dep = declare_dependency(dependencies: [lapack, blas_dep])
endif
######################################################################
## Fortran Compiler Setup
######################################################################
# Adding at project level causes many spurious -lgfortran flags.
add_languages('fortran', native: false)
ff = meson.get_compiler('fortran')
if ff.has_argument('-Wno-conversion')
add_project_arguments(
'-Wno-conversion',
language: ['fortran'],
)
endif
######################################################################
## Fortran Global compiler flags/options argument
######################################################################
# Fortran compiler options
# The default list of warnings to ignore from Fortran code. There is a lot of
# old, vendored code that is very bad and we want to compile it silently (at
# least with GCC and Clang)
_global_fortran_args = [
# Define warning flags for Fortran compilation
'-Wno-argument-mismatch', # Suppress warnings about mismatched argument types in subroutine/function calls
'-Wno-conversion', # Suppress warnings about implicit type conversions
'-Wno-intrinsic-shadow', # Suppress warnings about shadowing intrinsic names
'-Wno-maybe-uninitialized', # Suppress warnings about variables that might be used uninitialized
'-Wno-surprising', # Suppress warnings about non-standard Fortran practices
'-Wno-uninitialized', # Suppress warnings about uninitialized variables
'-Wno-unused-dummy-argument', # Suppress warnings about dummy arguments that are unused
'-Wno-unused-label', # Suppress warnings about unused labels
'-Wno-unused-variable', # Suppress warnings about unused variables
'-Wno-tabs', # Suppress warnings about tabs in the source code (often used in legacy code)
]
# Compiler options for Fortran
_global_fortran_args = ff.get_supported_arguments(
_global_fortran_args
)
add_project_arguments(
_global_fortran_args,
language: ['fortran'],
)
# # Apply fortran arguments if supported
# foreach arg : _global_fortran_args
# if ff.has_argument(arg)
# add_project_arguments(arg, language: 'fortran')
# else
# # Debug message for compiler IDs
# message('fortran compiler (' + ff.get_id() + ') does not support argument: ' + arg)
# endif
# endforeach
######################################################################
## C and C++ Compiler Setup
######################################################################
cc = meson.get_compiler('c')
cpp = meson.get_compiler('cpp')
# C Compiler version checks
cc_version = cc.version()
# Detect which C and C++ compiler is being used
cc_id = cc.get_id()
cpp_id = cpp.get_id() # Possible values: 'gcc', 'clang', 'msvc', etc.
# Check compiler is recent enough (see the SciPy Toolchain Roadmap for details)
if cc_id == 'gcc'
if not cc_version.version_compare('>=9.1')
error('scikit-plots requires GCC >= 9.1')
endif
elif cc_id == 'clang' or cc_id == 'clang-cl'
if not cc_version.version_compare('>=12.0')
error('scikit-plots requires Clang >= 12.0')
endif
elif cc_id == 'msvc'
if not cc_version.version_compare('>=19.20')
error('scikit-plots requires MSVC >= 19.20 (Visual Studio 2019 or newer)')
endif
endif
######################################################################
## Compiler Flags: C strict aliasing flags
######################################################################
# Add default compile flags for any compiler that supports them.
# Note that MSVC does not support strict aliasing at all, and neither do the
# Intel compilers on Windows, so the `-fno` flavor of the flag should be fine.
add_project_arguments(
cc.get_supported_arguments('-fno-strict-aliasing'),
language : ['c'],
)
######################################################################
## Compiler Flags: Clang trapping math flags
######################################################################
# Clang defaults to a non-strict floating error point model, but we need strict
# behavior. `-ftrapping-math` is equivalent to `-ffp-exception-behavior=strict`.
# This flag is also required to prevent the activation of SIMD partial load workarounds.
# For further clarification, refer to gh-24461.
cc_id = cc.get_id()
if cc_id.startswith('clang')
# Determine the compiler flags for trapping math exceptions.
trapping_math = {
'clang-cl': '/clang:-ftrapping-math',
}.get(cc_id, '-ftrapping-math')
# Check if the compiler supports the trapping math flag.
if cc.has_argument(trapping_math)
# TODO: Consider upgrading the vendored Meson to 1.3.0 to support the parameter `werror`
# Detect whether the compiler actually supports strict handling of floating-point exceptions
# by treating warnings as errors.
if cc.compiles('int main() { return 0; }', args: [trapping_math, '-Werror'])
trapping_math = [trapping_math, '-DNPY_HAVE_CLANG_FPSTRICT']
else
# Suppress warnings about unsupported floating-point optimization.
trapping_math = [trapping_math, '-Wno-unsupported-floating-point-opt']
# Inform the user about the workaround.
message(
'Clang version does not strictly enforce floating-point exception handling. ' +
'Performance may be impacted. Consider upgrading Clang.'
)
endif
add_project_arguments(
trapping_math,
language: ['c', 'cpp']
)
endif
endif
######################################################################
## C and C++ Global compiler flags/options argument
######################################################################
# List of global arguments for C and C++
_global_args = [
'-DDEBUG', # Define DEBUG macro to enable debug mode
'-W', # Enable all warnings
'-Werror=unused-variable', # Treat unused variables as errors to enforce code quality
'-Wno-cast-align', # Suppress warnings if a pointer is cast to a type with different alignment
'-Wno-cast-qual', # Suppress warnings if a pointer is cast to a type with different qualifiers
'-Wno-conversion', # Suppress warnings about type conversions
'-Wno-double-promotion', # Suppress warnings if a float is promoted to double
'-Wno-error=unused-function', # Suppress errors for unused functions
'-Wno-float-equal', # Suppress warnings if floating-point values are compared for equality
'-Wno-format-truncation', # Suppress warnings about format string truncations
'-Wno-misleading-indentation', # Suppress warnings about misleading indentation
'-Wno-parentheses', # Suppress warnings about unnecessary parentheses
'-Wno-pointer-arith', # Suppress warnings about pointer arithmetic
'-Wno-redundant-decls', # Suppress warnings about redundant declarations
'-Wno-sequence-point', # Suppress warnings about potential sequence point issues
'-Wno-shadow', # Suppress warnings if a local variable shadows another variable
'-Wno-sign-compare', # Suppress warnings about comparisons between signed and unsigned integers
'-Wno-switch', # Suppress warnings about switch statement cases that are not handled
'-Wno-undef', # Suppress warnings if an undefined macro is used
'-Wno-unused-but-set-parameter', # Suppress warnings about parameters that are set but not used
'-Wno-unused-function', # Suppress warnings about unused functions
'-Wno-unused-label', # Suppress warnings about unused labels
'-Wno-unused-parameter', # Suppress warnings about unused parameters
'-Wno-unused-result', # Suppress warnings about unused results
'-Wno-unused-variable', # Suppress warnings about unused variables
'-Wno-write-strings', # Treat string literals as `const char[]`
'-Wno-discarded-qualifiers', # to suppress warnings about discarded qualifiers (like const, volatile, etc.).
]
# Additional arguments for C
_global_c_args = cc.get_supported_arguments(
_global_args + [
'-Wno-implicit-function-declaration', # Suppress warnings about implicit function declarations
]
)
# Additional arguments for C++
_global_cpp_args = cpp.get_supported_arguments(
# GCC/Clang flags
_global_args + [
'-std=c++17',
'-Wno-class-memaccess', # Suppress warnings about accessing class members inappropriately
'-Wno-int-in-bool-context', # Suppress warnings about int used in boolean context
'-Wno-non-virtual-dtor', # Suppress warnings about non-virtual destructors
# invalid in MSVC (cl) as they are specific to GCC/Clang
'-Wno-cpp', # Suppress warnings about C++ preprocessor directives
'-Wno-pedantic', # Suppress strict ISO C++ compliance warnings
'-Wno-terminate', # Suppress warnings about code that might terminate unexpectedly
]
)
if host_machine.system() == 'linux' or host_machine.system() == 'darwin'
add_project_link_arguments('-pthread', language: ['c', 'cpp']) # Add pthread support for POSIX systems
endif
# Enable multithreading if std::thread is supported
if (cpp.has_function('std::thread') or
cpp.compiles('#include <thread>\nint main() { std::thread t; return 0; }', name: 'std::thread support'))
# Enable multithreading with STL parallel execution policies
_global_cpp_args += ['-DNUMCPP_USE_MULTITHREAD']
endif
# Apply C arguments if supported
foreach arg : _global_c_args
if cc.has_argument(arg)
add_project_arguments(arg, language: 'c')
else
# Debug message for compiler IDs
message('C compiler (' + cc_id + ') does not support argument: ' + arg)
endif
endforeach
# Apply C++ arguments if supported
foreach arg : _global_cpp_args
if cpp.has_argument(arg)
add_project_arguments(arg, language: 'cpp')
else
# Debug message for compiler IDs
message('C++ compiler (' + cpp_id + ') does not support argument: ' + arg)
endif
endforeach
######################################################################
## C and C++ Math Library functions, symbols
######################################################################
# We need -lm for all C code (assuming it uses math functions, which is safe to
# assume for scikit-image). For C++ it isn't needed, because libstdc++/libc++ is
# guaranteed to depend on it. For Fortran code, Meson already adds `-lm`.
dep_math = cc.find_library('m', required : false)
if dep_math.found()
add_project_link_arguments(
['-lm'], language : ['c'],
)
endif
# Intel compilers default to fast-math, so disable it if we detect Intel
# compilers. A word of warning: this may not work with the conda-forge
# compilers, because those have the annoying habit of including lots of flags
# that are gcc-specific in CFLAGS/CXXFLAGS/FFLAGS, which throws off the
# detection logic below. You have to remove the wrong flags (only `-isystem`
# is actually needed, everything else shouldn't be there).
_intel_cflags = []
_intel_fflags = []
if cc.get_id() in ['intel', 'intel-llvm']
_intel_cflags += cc.get_supported_arguments('-fp-model=strict')
elif cc.get_id() in ['intel-cl', 'intel-llvm-cl']
_intel_cflags += cc.get_supported_arguments('/fp:strict')
endif
if ff.get_id() in ['intel', 'intel-llvm']
_intel_fflags = ff.get_supported_arguments('-fp-model=strict')
minus0_arg = ['-assume', 'minus0']
if ff.has_multi_arguments(minus0_arg)
_intel_fflags += minus0_arg
endif
elif ff.get_id() in ['intel-cl', 'intel-llvm-cl']
# Intel Fortran on Windows does things differently, so deal with that
# (also specify dynamic linking and the right name mangling)
_intel_fflags = ff.get_supported_arguments(
'/fp:strict', '/MD', '/names:lowercase', '/assume:underscore',
'/assume:minus0'
)
endif
add_project_arguments(_intel_cflags, language: ['c', 'cpp'])
add_project_arguments(_intel_fflags, language: 'fortran')
######################################################################
## C and C++ Symbol Visibility
######################################################################
# Hide symbols when building on Linux with GCC. For Python extension modules,
# we only need `PyInit_*` to be public; anything else may cause problems.
# So we use a linker script to avoid exporting those symbols (this is in addition
# to Meson using `-fvisibility=hidden` for C and `-fvisibility-inlines-hidden` for C++ code).
# See gh-15996 for details.
_linker_script = meson.project_source_root() / 'lightnumpy/_build_utils/link-version-pyinit.map'
version_link_args = [
'-Wl,--version-script=' + _linker_script,
]
# Note that FreeBSD only accepts version scripts when -shared is passed,
# hence we need to pass that to `cc.links` explicitly (the flag is already present
# for `extension_module` invocations).
if not cc.links('', name: '-Wl,--version-script', args: ['-shared'] + version_link_args)
version_link_args = []
endif
######################################################################
## C 32-bit platforms when atomic operations
######################################################################
# Determine whether it is necessary to link libatomic with gcc. This
# could be the case on 32-bit platforms when atomic operations are used
# on 64-bit types or on RISC-V using 8-bit atomics, so we explicitly
# check for both 64 bit and 8 bit operations. The check is adapted from
# SciPy, who copied it from Mesa.
null_dep = dependency('', required : false)
atomic_dep = null_dep
code_non_lockfree = '''
#include <stdint.h>
int main() {
struct {
void *p;
uint8_t u8v;
} x;
x.p = NULL;
x.u8v = 0;
uint8_t res = __atomic_load_n(x.u8v, __ATOMIC_SEQ_CST);
__atomic_store_n(x.u8v, 1, ATOMIC_SEQ_CST);
void *p = __atomic_load_n(x.p, __ATOMIC_SEQ_CST);
__atomic_store_n((void **)x.p, NULL, __ATOMIC_SEQ_CST)
return 0;
}
'''
if cc.get_id() != 'msvc'
if not cc.links(
code_non_lockfree,
name : 'Check atomic builtins without -latomic'
)
atomic_dep = cc.find_library('atomic', required: false)
if atomic_dep.found()
# We're not sure that with `-latomic` things will work for all compilers,
# so verify and only keep libatomic as a dependency if this works. It is
# possible the build will fail later otherwise - unclear under what
# circumstances (compilers, runtimes, etc.) exactly and this may need to
# be extended when support is added for new CPUs
if not cc.links(
code_non_lockfree,
dependencies: atomic_dep,
name : 'Check atomic builtins with -latomic'
)
atomic_dep = null_dep
endif
endif
endif
endif
######################################################################
## Platform OS detection
######################################################################
# Platform detection
is_windows = host_machine.system() == 'windows'
is_mingw = is_windows and cc.get_id() == 'gcc'
# is_mingw = is_windows and cc.get_define('__MINGW32__') != ''
if is_mingw and ff.get_id() != 'gcc'
error(
'If you are using GCC on Windows, you must also use GFortran! ' +
'Detected: @0@'.format(ff.get_id())
)
endif
######################################################################
## macOS 14
######################################################################
macOS13_3_or_later = false
if host_machine.system() == 'darwin'
r = run_command('xcrun', '-sdk', 'macosx', '--show-sdk-version', check: true)
sdkVersion = r.stdout().strip()
macOS13_3_or_later = sdkVersion.version_compare('>=13.3')
endif
if host_machine.system() == 'darwin'
# Check if the compiler supports the '-Wl,-ld_classic' argument (new linker in macOS 14)
if cc.has_link_argument('-Wl,-ld_classic')
# New linker introduced in macOS 14 not working yet with at least OpenBLAS in Spack,
# see gh-24964 (and linked scipy issue from there).
add_project_link_arguments('-Wl,-ld_classic', language : ['c', 'cpp', 'fortran'])
endif
# Check if the compiler supports the '-Wl,-dead_strip' argument (linker option to strip unused symbols)
if cc.has_link_argument('-Wl,-dead_strip')
# Allow linker to strip unused symbols
add_project_link_arguments('-Wl,-dead_strip', language : ['c', 'cpp', 'fortran'])
endif
endif
######################################################################
## python
######################################################################
# Import the Python module from Meson to interact with the Python installation
# https://mesonbuild.com/Python-module.html
mod_py = import('python')
# NOTE: with Meson >=0.64.0 we can add `pure: false` here and remove that line
# everywhere else, see https://github.com/mesonbuild/meson/pull/10783.
# py = find_program('python3', 'python', required: true) # Find Python cross-platform
py = mod_py.find_installation(pure: false) # Find system Python
# Get the Python Dependencies
dep_py = py.dependency()
# Emit a warning for 32-bit Python installs on Windows; users are getting
# unexpected from-source builds there because we no longer provide wheels.
if is_windows and py.has_variable('EXT_SUFFIX')
if py.get_variable('EXT_SUFFIX').contains('win32')
warning(
'You are building from source on a 32-bit Python install. ' +
'lightnumpy does not provide 32-bit wheels; install 64-bit Python ' +
'if you are having issues!'
)
endif
endif
######################################################################
## python headers 'Python.h'
######################################################################
if not cc.has_header('Python.h', dependencies: dep_py)
error('Cannot compile `Python.h`. ' +
'Perhaps you need to install python-dev|python-devel')
endif
# # Attempt to get the Python include directory
# _py_inc_dir = meson.get_external_property(
# 'python-include-dir',
# 'not-given'
# )
# if _py_inc_dir == 'not-given'
# _py_inc_dir = run_command(
# py,
# [
# '-c',
# '''\
# import sysconfig
# print(sysconfig.get_path("include"))
# '''
# ],
# check: true
# ).stdout().strip()
# endif
# # Use the include directory in your build setup
# inc_dir_py = include_directories(_py_inc_dir)
# Print the include directory
# message('python include dir: @0@'.format(_py_inc_dir))
######################################################################
## pybind11 is a lightweight header-only library
## that exposes C++11 types in Python and vice versa
## https://github.com/pybind/pybind11
## https://pybind11.readthedocs.io/_/downloads/en/latest/pdf/
## pybind11/pybind11.h includes Python.h,
## as such it must be the first file included in any source file
## or header for the same reasons as 'Python.h'.
######################################################################
# python3 -m pybind11 --includes
# pybind11 — Seamless operability between C++11 and Python
dep_pybind11 = dependency('pybind11', version: '>=2.13.0')
######################################################################
## pythran
######################################################################
# Search for pythran
pythran = find_program(
'pythran',
native: true,
version: '>=0.14.0',
required: get_option('pythran').enabled(),
)
if get_option('pythran').enabled()
# xsimd is unvendored from pythran by conda-forge, and due to a compiler
# activation bug the default <prefix>/include/ may not be visible (see
# gh-15698). Hence look for xsimd explicitly.
dep_xsimd = dependency('xsimd', required: false)
endif
######################################################################
## pythran args
######################################################################
# Pythran build flags
if get_option('pythran').enabled()
# Base Pythran-specific flags
_pythran_base_args = [
'-DENABLE_PYTHON_MODULE', # Enable Python module support
'-D__PYTHRAN__=3', # Define Pythran version
'-DPYTHRAN_BLAS_NONE', # Disable BLAS
]
# Pythran base and C++ warning flags
# _global_pythran_cpp_args = _pythran_base_args + _global_cpp_args
# add_project_arguments(
# _global_pythran_cpp_args,
# language: ['pythran'],
# )
endif
######################################################################
## pythran include dir
######################################################################
# Pythran include directory
if get_option('pythran').enabled()
_pythran_inc_dir = meson.get_external_property(
'pythran-include-dir',
'not-given'
)
if incdir_pythran == 'not-given'
# If not specified, try to query Pythran from the build python
_pythran_inc_dir = run_command(py,
[
'-c',
'''\
import os; os.chdir("..")
import pythran
print(os.path.dirname(pythran.__file__))
'''
],
check: true
).stdout().strip()
endif
inc_dir_pythran = include_directories(_pythran_inc_dir)
message(
'pythran include dir: @0@'.format(_pythran_inc_dir)
)
endif
######################################################################
## cython
######################################################################
# Find the Cython program, which is needed to compile .pyx files to .c or .cpp files
cy = meson.get_compiler('cython')
# generator() doesn't accept compilers, only found programs - cast it as cli_cython.
cli_cython = find_program(cy.cmd_array()[0])
# Scipy variant of Cython command
# cli_cython = find_program('lightnumpy/_build_utils/cythoner.py')
######################################################################
## Common Cython arguments
######################################################################
# cython_args = ['-3', '--fast-fail', '--output-file', '@OUTPUT@', '--include-dir', '@BUILD_ROOT@', '@INPUT@']
# Define the arguments for the Cython command. These arguments will be passed
# to the Cython compiler when generating the C source files.
cython_c_args = [
# '-O2', # Optimization level
# '-X boundscheck=' + boundscheck, # Control bounds checking (True/False)
'-X language_level=3', # Ensure Cython targets Python3 like '-3'
# Prevents using negative indexing, which can provide a speedup for array handling.
'-X wraparound=False', # Disable negative indexing (wraparound)
# Skips checking for uninitialized variables, improving performance at the cost of safety.
'-X initializedcheck=False', # Disable check for uninitialized variables
# Skips checking for None values, improving performance when you're sure that variables won’t be None.
'-X nonecheck=False', # Disable None checks
# Enables C-style division (ignores Python division safety), improving performance.
'-X cdivision=True', # Enable C division
# Disables profiling support, which improves speed if profiling isn’t needed.
'-X profile=False', # Disable profiling
'--fast-fail', # Halt on first error during compilation
# Specifies the include directory where Cython can find the necessary headers.
# Needed for cython imports across subpackages, e.g. cluster pyx that
# cimports metrics pxd
# '--include-dir', '@BUILD_ROOT@', # Placeholder for Meson to replace later
'--include-dir', meson.global_build_root(), # Directly resolves to the build root path
# '--output-file', '@OUTPUT@', # Specify output file for generated C code
# '@INPUT@', # Input file placeholder managed by Meson
]
# If the Cython version is 3.1.0 or newer, add the option for free threading compatibility
if cy.version().version_compare('>=3.1.0')
cython_c_args += ['-Xfreethreading_compatible=True']
endif
# Define additional arguments specifically for generating C++ files with Cython
cython_cpp_args = cython_c_args + ['--cplus'] # The '--cplus' flag tells Cython to generate C++ code
######################################################################
## Cython generator/compiler
## pyx -> c, pyx -> cpp generators, depending on copied pxd files and init
## https://mesonbuild.com/Reference-manual_functions.html#generator
## https://mesonbuild.com/Reference-manual_functions.html#custom_target
######################################################################
_gen_cython_args = [
# '--include-dir', '@BUILD_ROOT@', # Placeholder for Meson to replace later
'--output-file', '@OUTPUT@', # Specify output file for generated C code
'@INPUT@', # Input file placeholder managed by Meson
]
# Create a generator for converting .pyx files to .c files using the defined Cython arguments
gen_cython_c = generator(
cli_cython,
arguments : _gen_cython_args + cython_c_args, # Use the previously defined arguments
output : '@BASENAME@.c', # The output will be a .c file with the same base name as the input .pyx file
# depends : _cython_tree # Optional: Specify dependencies like .pxd files, if any
)
# Create a generator for converting .pyx files to .cpp files (C++ code) using Cython arguments
gen_cython_cpp = generator(
cli_cython,
arguments : _gen_cython_args + cython_cpp_args, # Use the C++ specific arguments
output : '@BASENAME@.cpp', # The output will be a .cpp file with the same base name as the input .pyx file
# depends : [_cython_tree] # Optional: Specify dependencies like .pxd files, if any
)
# Conditional generation with Pythran, a tool that accelerates Python code.
# This block is only executed if the 'use_pythran' option is enabled.
if get_option('pythran').enabled()
# Define a generator for Pythran to convert Python files into C++ code
# Note: The arguments need to be updated when Pythran supports running without the GIL (Global Interpreter Lock)
pythran_gen = generator(
pythran,
arguments : ['-E', '@INPUT@', '-o', '@OUTPUT@'], # '-E' expands macros, '@INPUT@' is the input file, and '@OUTPUT@' is the output
output : '@BASENAME@.cpp', # Output will be a .cpp file
)
endif
######################################################################
## Set common build flags for C and C++ code
######################################################################
# Adapted from Scipy. mingw is untested and not officially supported. If you
# ever bump into issues when trying to compile for mingw, please open an issue
# in the scikit-learn issue tracker
cython_c_flags = [
'-DCYTHON_CCOMPLEX=0', # see gh-18975 for why we need this
]
if is_mingw
is_mingw_built_python = run_command(
py, ['-c', 'import sysconfig; print(sysconfig.get_platform())'],
check: true
).stdout().strip().startswith('mingw')
if not is_mingw_built_python
# For mingw-w64, link statically against the UCRT.
_gcc_link_args = ['-lucrt', '-static']
add_project_link_arguments(_gcc_link_args, language: ['c', 'cpp', 'fortran'])
# Force gcc to float64 long doubles for compatibility with MSVC
# builds, for C only.
add_project_arguments('-mlong-double-64', language: 'c')
endif
# Make fprintf("%zd") work (see https://github.com/rgommers/scipy/issues/118)
add_project_arguments('-D__USE_MINGW_ANSI_STDIO=1', language: ['c', 'cpp'])
endif
if is_mingw
###############################################################
# Manual add of MS_WIN64 macro when not using MSVC.
# https://bugs.python.org/issue28267
bitness = run_command(
'_build_utils/gcc_build_bitness.py',
check: true
).stdout().strip()
if bitness == '64'
add_project_arguments(
'-DMS_WIN64',
language: ['c', 'cpp'],
)
endif
###############################################################
# Silence warnings emitted by PyOS_snprintf for (%zd), see
# https://github.com/rgommers/scipy/issues/118.
# Use as c_args for extensions containing Cython code
cython_c_flags += ['-Wno-format-extra-args', '-Wno-format']
# Flag needed to work around BLAS and LAPACK Gfortran dependence on
# undocumented C feature when passing single character string arguments. See:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90329
# https://github.com/wch/r-source/blob/838f9d5a7be08f2a8c08e47bcd28756f5d0aac90/src/gnuwin32/MkRules.rules#L121
add_project_arguments(
'-fno-optimize-sibling-calls',
language: ['fortran']
)
endif
# Deal with M_PI & friends; add `use_math_defines` to c_args or cpp_args
# Cython doesn't always get this right itself (see, e.g., gh-16800), so
# explicitly add the define as a compiler flag for Cython-generated code.
if is_windows
use_math_defines = ['-D_USE_MATH_DEFINES']
else
use_math_defines = []
endif
# Define C and C++ specific arguments
cython_c_flags += [use_math_defines]
# Adapted from Numpy.
# Same as NPY_CXX_FLAGS (TODO: extend for what ccompiler_opt adds)
cython_cpp_flags = cython_c_flags + [
'-D__STDC_VERSION__=0', # for compatibility with C headers
]
# if cc.get_argument_syntax() != 'msvc'
# cython_cpp_flags += [
# '-fno-exceptions', # no exception support
# '-fno-rtti', # no runtime type information
# ]
# endif
######################################################################
## numpy include dir
######################################################################
# When cross-compiling scikitplots, the compiler needs access to NumPy and Pythran
# headers for the host platform (where the package will actually run). These
# headers may be incompatible with any corresponding headers that might be
# installed on the build system (where the compilation is performed). To make
# sure that the compiler finds the right headers, paths can be configured in
# the 'properties' section of a Meson cross file:
#
# [properties]
# numpy-include-dir = '/path/to/host/numpy/includes'
# pythran-include-dir = '/path/to/host/pythran/includes'
#
# If a cross file is not provided or does not specify either of these
# properties, fall back to running Python on the build system to query NumPy or
# Pythran directly for the appropriate paths. This will detect appropriate
# paths for native builds. (This might even work for certain build/host cross
# combinations, but don't rely on that.)
#
# For more information about cross compilation in Meson, including a definition
# of "build" and "host" in this context, refer to
#
# https://mesonbuild.com/Cross-compilation.html
# NumPy include directory - needed in all submodules
# The chdir is needed because within numpy there's an `import signal`
# statement, and we don't want that to pick up scipy's signal module rather
# than the stdlib module. The try-except is needed because when things are
# split across drives on Windows, there is no relative path and an exception
# gets raised. There may be other such cases, so add a catch-all and switch to
# an absolute path. Relative paths are needed when for example a virtualenv is
# placed inside the source tree; Meson rejects absolute paths to places inside
# the source tree.
# For cross-compilation it is often not possible to run the Python interpreter
# in order to retrieve numpy's include directory. It can be specified in the
# cross file instead:
# [properties]
# numpy-include-dir = '/abspath/to/host-pythons/site-packages/numpy/core/include'
#
# This uses the path as is, and avoids running the interpreter.
_np_inc_dir = meson.get_external_property(
'numpy-include-dir',
'not-given',
)
if _np_inc_dir == 'not-given'
_np_inc_dir = run_command(py,
[
'-c',
'''\
import os
import numpy as np
try:
# get absolute path
_np_inc_dir = np.get_include()
if not os.path.exists(_np_inc_dir):
raise FileNotFoundError("")
except Exception as e:
os.chdir('.')
_np_inc_dir = np.get_include()
# get relative path
_np_inc_dir = os.path.relpath(_np_inc_dir)
print(_np_inc_dir)
'''
],
check: true
).stdout().strip()
# We do need an absolute path to feed to `cc.find_library` below
_np_inc_dir_abs = run_command(py,
[
'-c',
'import numpy; print(numpy.get_include())'
],
check: true
).stdout().strip()
else
_np_inc_dir_abs = _np_inc_dir
endif