From bb2399bba9f048ee69a9213c1e2b43784ac40e47 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Thu, 7 Sep 2023 18:06:01 -0400 Subject: [PATCH 01/12] Restore linker flags when testing for functions. Omitting these causes detection for pthread builds to fail with static libraries since the pthread flags are not passed to the linker. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c7d3c092..7e9a3884 100755 --- a/setup.py +++ b/setup.py @@ -466,7 +466,7 @@ def has_function(self, function, includes=None, objects=None, libraries=None, "a.out", output_dir=tmpdir, libraries=libraries, - # extra_preargs=linker_flags, + extra_preargs=linker_flags, library_dirs=library_dirs, ) From e2c0b0134f846133da8ed7a95259894232c22f1f Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 02/12] Explicitly set language level 3 in pxd file. This resolves some warnings about the new behavior in Cython 3. --- pyfftw/pyfftw.pxd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index d99cfae0..6d0d1936 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -1,3 +1,5 @@ +# cython: language_level=3 +# # Copyright 2014 Knowledge Economy Developments Ltd # # Henry Gomersall From 00ca3919a2a2a61ad2814bfa0292b612fd45e3d1 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 03/12] Mark cdef functions as noexcept and nogil as needed. This fixes errors in Cython 3 when using these functions in nogil contexts or casting to function pointers which are declared nogil. We also mark some basic C callbacks as noexcept since Cython 3 updates non-extern cdef functions to implicitly pass exceptions. The noexcept updates require Cython>=3. --- pyfftw/pyfftw.pxd | 18 +++++++++--------- pyfftw/pyfftw.pyx | 16 ++++++++-------- pyproject.toml | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index 6d0d1936..d2d74f55 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -144,21 +144,21 @@ cdef extern from 'fftw3.h': int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, double *_in, double *_out, - int *kind, unsigned flags) + int *kind, unsigned flags) nogil # Single precision real planner fftwf_plan fftwf_plan_guru_r2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, float *_in, float *_out, - int *kind, unsigned flags) + int *kind, unsigned flags) nogil # Long double precision real planner fftwl_plan fftwl_plan_guru_r2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, long double *_in, long double *_out, - int *kind, unsigned flags) + int *kind, unsigned flags) nogil # Double precision complex new array execute void fftw_execute_dft(fftw_plan, @@ -240,12 +240,12 @@ cdef extern from 'fftw3.h': void fftwl_plan_with_nthreads(int n) # cleanup routines - void fftw_cleanup() - void fftwf_cleanup() - void fftwl_cleanup() - void fftw_cleanup_threads() - void fftwf_cleanup_threads() - void fftwl_cleanup_threads() + void fftw_cleanup() nogil + void fftwf_cleanup() nogil + void fftwl_cleanup() nogil + void fftw_cleanup_threads() nogil + void fftwf_cleanup_threads() nogil + void fftwl_cleanup_threads() nogil # wisdom functions void fftw_export_wisdom(void (*write_char)(char c, void *), void *data) diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index 8701e47d..37934618 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -146,7 +146,7 @@ cdef void* _fftw_plan_null( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags): + int *direction, unsigned flags) with gil: raise RuntimeError("Undefined planner. This is a bug") @@ -192,7 +192,7 @@ IF HAVE_DOUBLE: int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags): + int *direction, int flags) nogil: return fftw_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -241,7 +241,7 @@ IF HAVE_SINGLE: int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags): + int *direction, int flags) nogil: return fftwf_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -290,7 +290,7 @@ IF HAVE_LONG: int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags): + int *direction, int flags) nogil: return fftwl_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -301,7 +301,7 @@ IF HAVE_LONG: # ========= # -cdef void _fftw_execute_null(void *_plan, void *_in, void *_out): +cdef void _fftw_execute_null(void *_plan, void *_in, void *_out) with gil: raise RuntimeError("Undefined executor. This is a bug") @@ -722,7 +722,7 @@ def scheme_functions(scheme): raise NotImplementedError(msg) # Set the cleanup routine -cdef void _cleanup(): +cdef void _cleanup() noexcept nogil: IF HAVE_DOUBLE: fftw_cleanup() IF HAVE_SINGLE: @@ -1988,14 +1988,14 @@ cdef class FFTW: with nogil: fftw_execute(plan, input_pointer, output_pointer) -cdef void count_char(char c, void *counter_ptr): +cdef void count_char(char c, void *counter_ptr) noexcept nogil: ''' On every call, increment the derefenced counter_ptr. ''' (counter_ptr)[0] += 1 -cdef void write_char_to_string(char c, void *string_location_ptr): +cdef void write_char_to_string(char c, void *string_location_ptr) noexcept nogil: ''' Write the passed character c to the memory location pointed to by the contents of string_location_ptr (i.e. a pointer diff --git a/pyproject.toml b/pyproject.toml index 67a5800c..c8ddf4d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,7 +167,7 @@ test-command = "pytest --import-mode=append {project}" requires = [ "wheel", "setuptools<=59.4.0", - "Cython>=0.29.18", + "Cython>=3", # NumPy dependencies - to update these, sync from # https://github.com/scipy/oldest-supported-numpy/ From 2b3030508ecfaaa10e4d5b4d365562a0458f1b5d Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 04/12] Use packaging Version instead of deprecated distutils LooseVersion. --- pyproject.toml | 2 +- tests/test_pyfftw_dask_interface.py | 1 - tests/test_pyfftw_numpy_interface.py | 6 +++--- tests/test_pyfftw_scipy_fft.py | 6 +++--- tests/test_pyfftw_scipy_interface.py | 8 ++++---- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c8ddf4d7..51639424 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ build-verbosity = 2 # Note: Tests are run within a docker container on Linux builds # This will have a different -test-requires = "pytest scipy dask" +test-requires = "pytest scipy dask packaging" # Import-mode=append to use installed (wheel) version of pyfftw # rather than the local module test-command = "pytest --import-mode=append {project}" diff --git a/tests/test_pyfftw_dask_interface.py b/tests/test_pyfftw_dask_interface.py index 1f13764d..d68319c3 100644 --- a/tests/test_pyfftw_dask_interface.py +++ b/tests/test_pyfftw_dask_interface.py @@ -50,7 +50,6 @@ from .test_pyfftw_numpy_interface import complex_dtypes, real_dtypes from ._get_default_args import get_default_args -from distutils.version import LooseVersion import unittest import numpy diff --git a/tests/test_pyfftw_numpy_interface.py b/tests/test_pyfftw_numpy_interface.py index 2921b64d..91d29306 100644 --- a/tests/test_pyfftw_numpy_interface.py +++ b/tests/test_pyfftw_numpy_interface.py @@ -37,14 +37,14 @@ from .test_pyfftw_base import run_test_suites, np_fft from ._get_default_args import get_default_args -from distutils.version import LooseVersion +from packaging.version import Version import unittest import numpy import warnings import copy warnings.filterwarnings('always') -if LooseVersion(numpy.version.version) <= LooseVersion('1.6.2'): +if Version(numpy.version.version) <= Version('1.6.2'): # We overwrite the broken _cook_nd_args with a fixed version. from ._cook_nd_args import _cook_nd_args numpy.fft.fftpack._cook_nd_args = _cook_nd_args @@ -131,7 +131,7 @@ def rfft2_fix(a, s=None, axes=(-2, -1), norm=None): acquired_names = ('fftfreq', 'fftshift', 'ifftshift') -if LooseVersion(numpy.version.version) >= LooseVersion('1.8'): +if Version(numpy.version.version) >= Version('1.8'): acquired_names += ('rfftfreq', ) diff --git a/tests/test_pyfftw_scipy_fft.py b/tests/test_pyfftw_scipy_fft.py index f2354d5b..b06949c3 100644 --- a/tests/test_pyfftw_scipy_fft.py +++ b/tests/test_pyfftw_scipy_fft.py @@ -38,8 +38,8 @@ except ImportError: scipy_version = '0.0.0' -from distutils.version import LooseVersion -has_scipy_fft = LooseVersion(scipy_version) >= '1.4.0' +from packaging.version import Version +has_scipy_fft = Version(scipy_version) >= Version('1.4.0') if has_scipy_fft: import scipy.fft @@ -128,7 +128,7 @@ def test_acquired_names(self): rtol_dict = dict(f=1e-4, d=1e-5, g=1e-5) transform_types = [1, 2, 3, 4] -if LooseVersion(scipy_version) >= '1.6.0': +if Version(scipy_version) >= Version('1.6.0'): # all norm options aside from None scipy_norms = [None, 'ortho', 'forward', 'backward'] else: diff --git a/tests/test_pyfftw_scipy_interface.py b/tests/test_pyfftw_scipy_interface.py index 15d6c6c1..e47662a3 100644 --- a/tests/test_pyfftw_scipy_interface.py +++ b/tests/test_pyfftw_scipy_interface.py @@ -34,7 +34,7 @@ # from pyfftw.interfaces import scipy_fftpack -from distutils.version import LooseVersion +from packaging.version import Version import pyfftw from pyfftw import _supported_types @@ -202,7 +202,7 @@ def test_acquired_names(self): transform_types = [1, 2, 3, 4] @unittest.skipIf(scipy_missing or - (LooseVersion(scipy.__version__) <= LooseVersion('1.2.0')), + (Version(scipy.__version__) <= Version('1.2.0')), 'SciPy >= 1.2.0 is not installed') class InterfacesScipyR2RFFTTest(unittest.TestCase): ''' Class template for building the scipy real to real tests. @@ -273,7 +273,7 @@ def test_normalization_inverses(self): atol=self.atol, rtol=self.rtol)) @unittest.skipIf(scipy_missing or - (LooseVersion(scipy.__version__) <= LooseVersion('1.2.0')), + (Version(scipy.__version__) <= Version('1.2.0')), 'SciPy >= 1.2.0 is not installed') class InterfacesScipyR2RFFTNTest(InterfacesScipyR2RFFTTest): ''' Class template for building the scipy real to real tests. @@ -310,7 +310,7 @@ def test_axes_none(self): self.assertTrue(numpy.allclose(data_hat_p, data_hat_s, atol=self.atol, rtol=self.rtol)) - @unittest.skipIf(LooseVersion(scipy.__version__) <= LooseVersion('1.2.0'), + @unittest.skipIf(Version(scipy.__version__) <= Version('1.2.0'), 'scipy version not new enough') def test_axes_scalar(self): '''Test transformation over a single, scalar axis. From cbb945217e2cc9cb1f97525b95d5cb2895baf475 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 05/12] Use numpy.all instead of deprecated alltrue. This resolves deprecation warnings from NumPy. --- tests/test_pyfftw_builders.py | 20 ++++++++++---------- tests/test_pyfftw_call.py | 24 ++++++++++++------------ tests/test_pyfftw_dask_interface.py | 2 +- tests/test_pyfftw_numpy_interface.py | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/test_pyfftw_builders.py b/tests/test_pyfftw_builders.py index 8db09f43..709a7043 100644 --- a/tests/test_pyfftw_builders.py +++ b/tests/test_pyfftw_builders.py @@ -675,7 +675,7 @@ def test_input_maintained(self): final_input_array = FFTW_object.input_array self.assertTrue( - numpy.alltrue(input_array == final_input_array)) + numpy.all(input_array == final_input_array)) def test_avoid_copy(self): '''Test the avoid_copy flag @@ -887,7 +887,7 @@ def test_call(self): output_array = self.fft() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_positional_input_update(self): @@ -904,7 +904,7 @@ def test_call_with_positional_input_update(self): self.update_arrays(input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_keyword_input_update(self): @@ -920,7 +920,7 @@ def test_call_with_keyword_input_update(self): self.update_arrays(input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_keyword_output_update(self): @@ -938,7 +938,7 @@ def test_call_with_keyword_output_update(self): self.fft.execute() self.assertTrue( - numpy.alltrue(returned_output_array == output_array)) + numpy.all(returned_output_array == output_array)) def test_call_with_positional_updates(self): '''Test the class call with a positional array updates. @@ -957,7 +957,7 @@ def test_call_with_positional_updates(self): self.update_arrays(input_array, output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(returned_output_array == output_array)) + self.assertTrue(numpy.all(returned_output_array == output_array)) def test_call_with_keyword_updates(self): '''Test the class call with a positional output update. @@ -978,7 +978,7 @@ def test_call_with_keyword_updates(self): self.update_arrays(input_array, output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(returned_output_array == output_array)) + self.assertTrue(numpy.all(returned_output_array == output_array)) def test_call_with_different_input_dtype(self): '''Test the class call with an array with a different input dtype @@ -995,7 +995,7 @@ def test_call_with_different_input_dtype(self): self.update_arrays(_input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_list_input(self): '''Test the class call with a list rather than an array @@ -1005,7 +1005,7 @@ def test_call_with_list_input(self): test_output_array = self.fft(self.input_array.tolist()).copy() - self.assertTrue(numpy.alltrue(output_array == test_output_array)) + self.assertTrue(numpy.all(output_array == test_output_array)) def test_call_with_invalid_update(self): @@ -1065,7 +1065,7 @@ def test_call_with_different_striding(self): self.assertTrue( new_input_array[:,:,0].strides != internal_array.strides) - self.assertTrue(numpy.alltrue(test_output_array == new_output)) + self.assertTrue(numpy.all(test_output_array == new_output)) def test_call_with_copy_with_missized_array_error(self): '''Force an input copy with a missized array. diff --git a/tests/test_pyfftw_call.py b/tests/test_pyfftw_call.py index 4370244b..c3c63543 100644 --- a/tests/test_pyfftw_call.py +++ b/tests/test_pyfftw_call.py @@ -70,7 +70,7 @@ def test_call(self): output_array = self.fft() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_positional_input_update(self): @@ -86,7 +86,7 @@ def test_call_with_positional_input_update(self): self.fft.update_arrays(input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_keyword_input_update(self): '''Test the class call with a keyword input update. @@ -101,7 +101,7 @@ def test_call_with_keyword_input_update(self): self.fft.update_arrays(input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_keyword_output_update(self): @@ -118,7 +118,7 @@ def test_call_with_keyword_output_update(self): self.fft.execute() self.assertTrue( - numpy.alltrue(returned_output_array == output_array)) + numpy.all(returned_output_array == output_array)) def test_call_with_positional_updates(self): '''Test the class call with a positional array updates. @@ -137,7 +137,7 @@ def test_call_with_positional_updates(self): self.fft.update_arrays(input_array, output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(returned_output_array == output_array)) + self.assertTrue(numpy.all(returned_output_array == output_array)) def test_call_with_keyword_updates(self): '''Test the class call with a positional output update. @@ -158,7 +158,7 @@ def test_call_with_keyword_updates(self): self.fft.update_arrays(input_array, output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(returned_output_array == output_array)) + self.assertTrue(numpy.all(returned_output_array == output_array)) def test_call_with_different_input_dtype(self): '''Test the class call with an array with a different input dtype @@ -177,7 +177,7 @@ def test_call_with_different_input_dtype(self): self.fft.update_arrays(_input_array, self.output_array) self.fft.execute() - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) def test_call_with_list_input(self): '''Test the class call with a list rather than an array @@ -187,7 +187,7 @@ def test_call_with_list_input(self): test_output_array = self.fft(self.input_array.tolist()).copy() - self.assertTrue(numpy.alltrue(output_array == test_output_array)) + self.assertTrue(numpy.all(output_array == test_output_array)) def test_call_with_invalid_update(self): @@ -232,7 +232,7 @@ def test_call_with_auto_input_alignment(self): self.fft(a_, self.output_array) - self.assertTrue(numpy.alltrue(output_array == self.output_array)) + self.assertTrue(numpy.all(output_array == self.output_array)) # now try with a single byte offset and SIMD off ar, ai = numpy.float32(numpy.random.randn(2, 257)) @@ -285,7 +285,7 @@ def test_call_with_different_striding(self): # Test the test! self.assertTrue(new_input_array.strides != input_array[:,:,0].strides) - self.assertTrue(numpy.alltrue(test_output_array == new_output)) + self.assertTrue(numpy.all(test_output_array == new_output)) def test_call_with_copy_with_missized_array_error(self): '''Force an input copy with a missized array. @@ -406,7 +406,7 @@ def test_call_with_normalisation_precision(self): ref_output = ifft(normalise_idft=False).copy()/numpy.float64(ifft.N) test_output = ifft(normalise_idft=True).copy() - self.assertTrue(numpy.alltrue(ref_output == test_output)) + self.assertTrue(numpy.all(ref_output == test_output)) # ... and single inputs. _input_array = empty_aligned((256, 512), dtype='complex64', n=16) @@ -418,7 +418,7 @@ def test_call_with_normalisation_precision(self): ref_output = ifft(normalise_idft=False).copy()/numpy.float64(ifft.N) test_output = ifft(normalise_idft=True).copy() - self.assertTrue(numpy.alltrue(ref_output == test_output)) + self.assertTrue(numpy.all(ref_output == test_output)) def test_call_with_ortho_on(self): _input_array = empty_aligned((256, 512), dtype='complex128', n=16) diff --git a/tests/test_pyfftw_dask_interface.py b/tests/test_pyfftw_dask_interface.py index d68319c3..3e5a8dbb 100644 --- a/tests/test_pyfftw_dask_interface.py +++ b/tests/test_pyfftw_dask_interface.py @@ -492,7 +492,7 @@ def test_input_maintained(self): input_array, s, **kwargs) self.assertTrue( - numpy.alltrue(input_array == orig_input_array)) + numpy.all(input_array == orig_input_array)) class InterfacesDaskFFTTestFFT2(InterfacesDaskFFTTestFFT): diff --git a/tests/test_pyfftw_numpy_interface.py b/tests/test_pyfftw_numpy_interface.py index 91d29306..45b9106d 100644 --- a/tests/test_pyfftw_numpy_interface.py +++ b/tests/test_pyfftw_numpy_interface.py @@ -652,7 +652,7 @@ def test_input_maintained(self): input_array, s, **kwargs) self.assertTrue( - numpy.alltrue(input_array == orig_input_array)) + numpy.all(input_array == orig_input_array)) def test_on_non_writeable_array_issue_92(self): '''Test to make sure that locked arrays work. From 43d70b78b347db72fe3148dd3c72d3d856955167 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 06/12] Migrate library detection constants to preprocessor definitions. This is part of moving away from Cython's conditional compilation feature. Instead of definining the detected values as part of Cython's compile time environment, we define normal C preprocessor macros with the same names and make these accessible as booleans from Cython. --- pyfftw/pyfftw.pxd | 14 ++++++++++++++ setup.py | 13 +++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index d2d74f55..5356dcbd 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -37,6 +37,20 @@ cimport numpy as np from libc.stdint cimport int64_t +cdef extern from *: + bint HAVE_SINGLE + bint HAVE_DOUBLE + bint HAVE_LONG + bint HAVE_SINGLE_OMP + bint HAVE_DOUBLE_OMP + bint HAVE_LONG_OMP + bint HAVE_SINGLE_THREADS + bint HAVE_DOUBLE_THREADS + bint HAVE_LONG_THREADS + bint HAVE_SINGLE_MULTITHREADING + bint HAVE_DOUBLE_MULTITHREADING + bint HAVE_LONG_MULTITHREADING + ctypedef struct _fftw_iodim: int _n int _is diff --git a/setup.py b/setup.py index 7e9a3884..b13d30a6 100755 --- a/setup.py +++ b/setup.py @@ -608,6 +608,10 @@ def get_extensions(): class custom_build_ext(build_ext): + def build_extension(self, ext, *args, **kwargs): + ext.define_macros = (ext.define_macros or []) + self._pyfftw_define_macros + return super().build_extension(ext, *args, **kwargs) + def build_extensions(self): '''Check for availability of fftw libraries before building the wrapper. @@ -617,7 +621,9 @@ def build_extensions(self): # read out information and modify compiler # define macros, that is which part of wrapper is built - self.cython_compile_time_env = sniffer.compile_time_env + self._pyfftw_define_macros = [ + (k, int(v)) for k, v in sniffer.compile_time_env.items() + ] # call `extend()` to keep argument set neither by sniffer nor by # user. On windows there are includes set automatically, we @@ -648,7 +654,7 @@ def build_extensions(self): self.compiler.set_link_objects(objects) # delegate actual work to standard implementation - build_ext.build_extensions(self) + return super().build_extensions() class CreateChangelogCommand(Command): @@ -825,9 +831,8 @@ def setup_package(): from Cython.Build import cythonize trial_distribution = setup(**setup_args) - cython_compile_time_env = trial_distribution.get_command_obj("build_ext") - setup_args["ext_modules"] = cythonize(get_extensions(), compile_time_env=cython_compile_time_env) + setup_args["ext_modules"] = cythonize(get_extensions()) setup(**setup_args) From 7f267860021e598dc3bd5cc9a4add3cb97b0853c Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 07/12] Reduce use of deprecated Cython conditional compilation directives. This handles simple cases that surround only runtime code and not any definitions. --- pyfftw/pyfftw.pyx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index 37934618..addb20d7 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -70,24 +70,24 @@ _supported_types = [] _supported_nptypes_complex = [] _supported_nptypes_real = [] -IF HAVE_SINGLE: +if HAVE_SINGLE: _supported_types.append('32') _supported_nptypes_complex.append(np.complex64) _supported_nptypes_real.append(np.float32) -IF HAVE_DOUBLE: +if HAVE_DOUBLE: _supported_types.append('64') _supported_nptypes_complex.append(np.complex128) _supported_nptypes_real.append(np.float64) -IF HAVE_LONG: +if HAVE_LONG: _supported_types.append('ld') _supported_nptypes_complex.append(np.clongdouble) _supported_nptypes_real.append(np.longdouble) -IF (HAVE_SINGLE_OMP or HAVE_DOUBLE_OMP or HAVE_LONG_OMP): +if (HAVE_SINGLE_OMP or HAVE_DOUBLE_OMP or HAVE_LONG_OMP): _threading_type = 'OMP' -ELIF (HAVE_SINGLE_THREADS or HAVE_DOUBLE_THREADS or HAVE_LONG_THREADS): +elif (HAVE_SINGLE_THREADS or HAVE_DOUBLE_THREADS or HAVE_LONG_THREADS): _threading_type = 'PTHREADS' -ELSE: +else: _threading_type = None cdef object directions @@ -674,7 +674,7 @@ scheme_directions = { # sufficiently trivial to use -1 in place of None, especially given # that scheme_functions is an internal cdef object. cdef object _scheme_functions = {} -IF HAVE_DOUBLE: +if HAVE_DOUBLE: _scheme_functions.update({ ('c2c', '64'): {'planner': 0, 'executor':0, 'generic_precision':0, 'validator': -1, 'fft_shape_lookup': -1}, @@ -686,7 +686,7 @@ IF HAVE_DOUBLE: 'fft_shape_lookup': _lookup_shape_c2r_arrays}, ('r2r', '64'): {'planner': 9, 'executor':9, 'generic_precision':0, 'validator': -1, 'fft_shape_lookup': -1}}) -IF HAVE_SINGLE: +if HAVE_SINGLE: _scheme_functions.update({ ('c2c', '32'): {'planner':1, 'executor':1, 'generic_precision':1, 'validator': -1, 'fft_shape_lookup': -1}, @@ -698,7 +698,7 @@ IF HAVE_SINGLE: 'fft_shape_lookup': _lookup_shape_c2r_arrays}, ('r2r', '32'): {'planner':10, 'executor':10, 'generic_precision':1, 'validator': -1, 'fft_shape_lookup': -1}}) -IF HAVE_LONG: +if HAVE_LONG: _scheme_functions.update({ ('c2c', 'ld'): {'planner':2, 'executor':2, 'generic_precision':2, 'validator': -1, 'fft_shape_lookup': -1}, From 62fb5e573edc5a8d5e5c34319fe76fc748006a32 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 08/12] Remove conditional compilation surrounding function definitions. As a replacement the functions are always defined, but we conditionally add macros which hide the underlying FFTW calls in cases where these are not available (ensuring that the missing symbols aren't used). The empty Cython wrapper functions will not actually be called in normal usage since the same preprocessor definitions are used both for defining the replacement macros and for selecting whether the functions are used at runtime. --- pyfftw/pyfftw.pxd | 64 +++++++ pyfftw/pyfftw.pyx | 459 +++++++++++++++++++++++----------------------- 2 files changed, 291 insertions(+), 232 deletions(-) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index 5356dcbd..578b147f 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -63,6 +63,70 @@ cdef extern from 'pyfftw_complex.h': ctypedef long double clongdouble[2] cdef extern from 'fftw3.h': + """ + #if !HAVE_DOUBLE + #define fftw_plan_guru_dft(...) (NULL) + #define fftw_plan_guru_dft_r2c(...) (NULL) + #define fftw_plan_guru_dft_c2r(...) (NULL) + #define fftw_plan_guru_r2r(...) (NULL) + #define fftw_execute_dft(...) ((void)0) + #define fftw_execute_dft_r2c(...) ((void)0) + #define fftw_execute_dft_c2r(...) ((void)0) + #define fftw_execute_r2r(...) ((void)0) + #define fftw_destroy_plan(plan) ((void)0) + #define fftw_cleanup() ((void)0) + #define fftw_export_wisdom(...) ((void)0) + #define fftw_import_wisdom_from_string(wisdom) (0) + #define fftw_forget_wisdom() ((void)0) + #endif + + #if !HAVE_SINGLE + #define fftwf_plan_guru_dft(...) (NULL) + #define fftwf_plan_guru_dft_r2c(...) (NULL) + #define fftwf_plan_guru_dft_c2r(...) (NULL) + #define fftwf_plan_guru_r2r(...) (NULL) + #define fftwf_execute_dft(...) ((void)0) + #define fftwf_execute_dft_r2c(...) ((void)0) + #define fftwf_execute_dft_c2r(...) ((void)0) + #define fftwf_execute_r2r(...) ((void)0) + #define fftwf_destroy_plan(plan) ((void)0) + #define fftwf_cleanup() ((void)0) + #define fftwf_export_wisdom(...) ((void)0) + #define fftwf_import_wisdom_from_string(wisdom) (0) + #define fftwf_forget_wisdom() ((void)0) + #endif + + #if !HAVE_LONG + #define fftwl_plan_guru_dft(...) (NULL) + #define fftwl_plan_guru_dft_r2c(...) (NULL) + #define fftwl_plan_guru_dft_c2r(...) (NULL) + #define fftwl_plan_guru_r2r(...) (NULL) + #define fftwl_execute_dft(...) ((void)0) + #define fftwl_execute_dft_r2c(...) ((void)0) + #define fftwl_execute_dft_c2r(...) ((void)0) + #define fftwl_execute_r2r(...) ((void)0) + #define fftwl_destroy_plan(plan) ((void)0) + #define fftwl_cleanup() ((void)0) + #define fftwl_export_wisdom(...) ((void)0) + #define fftwl_import_wisdom_from_string(wisdom) (0) + #define fftwl_forget_wisdom() ((void)0) + #endif + + #if !HAVE_DOUBLE_MULTITHREADING + #define fftw_cleanup_threads() ((void)0) + #define fftw_init_threads() ((void)0) + #endif + + #if !HAVE_SINGLE_MULTITHREADING + #define fftwf_cleanup_threads() ((void)0) + #define fftwf_init_threads() ((void)0) + #endif + + #if !HAVE_LONG_MULTITHREADING + #define fftwl_cleanup_threads() ((void)0) + #define fftwl_init_threads() ((void)0) + #endif + """ # Double precision plans ctypedef struct fftw_plan_struct: diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index addb20d7..c910a3ed 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -151,151 +151,148 @@ cdef void* _fftw_plan_null( raise RuntimeError("Undefined planner. This is a bug") # Complex double precision -IF HAVE_DOUBLE: - cdef void* _fftw_plan_guru_dft( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftw_plan_guru_dft(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction[0], flags) - - # real to complex double precision - cdef void* _fftw_plan_guru_dft_r2c( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftw_plan_guru_dft_r2c(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # complex to real double precision - cdef void* _fftw_plan_guru_dft_c2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftw_plan_guru_dft_c2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # real to real double precision - cdef void* _fftw_plan_guru_r2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, int flags) nogil: - - return fftw_plan_guru_r2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction, flags) - -IF HAVE_SINGLE: - # Complex single precision - cdef void* _fftwf_plan_guru_dft( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwf_plan_guru_dft(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction[0], flags) - - # real to complex single precision - cdef void* _fftwf_plan_guru_dft_r2c( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwf_plan_guru_dft_r2c(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # complex to real single precision - cdef void* _fftwf_plan_guru_dft_c2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwf_plan_guru_dft_c2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # real to real single precision - cdef void* _fftwf_plan_guru_r2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, int flags) nogil: - - return fftwf_plan_guru_r2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction, flags) - -IF HAVE_LONG: - # Complex long double precision - cdef void* _fftwl_plan_guru_dft( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwl_plan_guru_dft(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction[0], flags) - - # real to complex long double precision - cdef void* _fftwl_plan_guru_dft_r2c( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwl_plan_guru_dft_r2c(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # complex to real long double precision - cdef void* _fftwl_plan_guru_dft_c2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, unsigned flags) nogil: - - return fftwl_plan_guru_dft_c2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - flags) - - # real to real long double precision - cdef void* _fftwl_plan_guru_r2r( - int rank, fftw_iodim *dims, - int howmany_rank, fftw_iodim *howmany_dims, - void *_in, void *_out, - int *direction, int flags) nogil: - - return fftwl_plan_guru_r2r(rank, dims, - howmany_rank, howmany_dims, - _in, _out, - direction, flags) +cdef void* _fftw_plan_guru_dft( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftw_plan_guru_dft(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction[0], flags) + +# real to complex double precision +cdef void* _fftw_plan_guru_dft_r2c( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftw_plan_guru_dft_r2c(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# complex to real double precision +cdef void* _fftw_plan_guru_dft_c2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftw_plan_guru_dft_c2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# real to real double precision +cdef void* _fftw_plan_guru_r2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, int flags) nogil: + + return fftw_plan_guru_r2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction, flags) + +# Complex single precision +cdef void* _fftwf_plan_guru_dft( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwf_plan_guru_dft(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction[0], flags) + +# real to complex single precision +cdef void* _fftwf_plan_guru_dft_r2c( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwf_plan_guru_dft_r2c(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# complex to real single precision +cdef void* _fftwf_plan_guru_dft_c2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwf_plan_guru_dft_c2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# real to real single precision +cdef void* _fftwf_plan_guru_r2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, int flags) nogil: + + return fftwf_plan_guru_r2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction, flags) + +# Complex long double precision +cdef void* _fftwl_plan_guru_dft( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwl_plan_guru_dft(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction[0], flags) + +# real to complex long double precision +cdef void* _fftwl_plan_guru_dft_r2c( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwl_plan_guru_dft_r2c(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# complex to real long double precision +cdef void* _fftwl_plan_guru_dft_c2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, unsigned flags) nogil: + + return fftwl_plan_guru_dft_c2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + flags) + +# real to real long double precision +cdef void* _fftwl_plan_guru_r2r( + int rank, fftw_iodim *dims, + int howmany_rank, fftw_iodim *howmany_dims, + void *_in, void *_out, + int *direction, int flags) nogil: + + return fftwl_plan_guru_r2r(rank, dims, + howmany_rank, howmany_dims, + _in, _out, + direction, flags) # Executors # ========= @@ -305,62 +302,59 @@ cdef void _fftw_execute_null(void *_plan, void *_in, void *_out) with gil: raise RuntimeError("Undefined executor. This is a bug") -IF HAVE_DOUBLE: - # Complex double precision - cdef void _fftw_execute_dft(void *_plan, void *_in, void *_out) nogil: +# Complex double precision +cdef void _fftw_execute_dft(void *_plan, void *_in, void *_out) nogil: - fftw_execute_dft(_plan, - _in, _out) + fftw_execute_dft(_plan, + _in, _out) - # real to complex double precision - cdef void _fftw_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +# real to complex double precision +cdef void _fftw_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: - fftw_execute_dft_r2c(_plan, - _in, _out) + fftw_execute_dft_r2c(_plan, + _in, _out) - # complex to real double precision - cdef void _fftw_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +# complex to real double precision +cdef void _fftw_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: - fftw_execute_dft_c2r(_plan, - _in, _out) + fftw_execute_dft_c2r(_plan, + _in, _out) -IF HAVE_SINGLE: - # Complex single precision - cdef void _fftwf_execute_dft(void *_plan, void *_in, void *_out) nogil: +# Complex single precision +cdef void _fftwf_execute_dft(void *_plan, void *_in, void *_out) nogil: - fftwf_execute_dft(_plan, - _in, _out) + fftwf_execute_dft(_plan, + _in, _out) - # real to complex single precision - cdef void _fftwf_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +# real to complex single precision +cdef void _fftwf_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: - fftwf_execute_dft_r2c(_plan, - _in, _out) + fftwf_execute_dft_r2c(_plan, + _in, _out) - # complex to real single precision - cdef void _fftwf_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +# complex to real single precision +cdef void _fftwf_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: - fftwf_execute_dft_c2r(_plan, - _in, _out) + fftwf_execute_dft_c2r(_plan, + _in, _out) -IF HAVE_LONG: - # Complex long double precision - cdef void _fftwl_execute_dft(void *_plan, void *_in, void *_out) nogil: +# Complex long double precision +cdef void _fftwl_execute_dft(void *_plan, void *_in, void *_out) nogil: - fftwl_execute_dft(_plan, - _in, _out) + fftwl_execute_dft(_plan, + _in, _out) - # real to complex long double precision - cdef void _fftwl_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +# real to complex long double precision +cdef void _fftwl_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: - fftwl_execute_dft_r2c(_plan, - _in, _out) + fftwl_execute_dft_r2c(_plan, + _in, _out) - # complex to real long double precision - cdef void _fftwl_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +# complex to real long double precision +cdef void _fftwl_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: - fftwl_execute_dft_c2r(_plan, - _in, _out) + fftwl_execute_dft_c2r(_plan, + _in, _out) # real to real double precision cdef void _fftw_execute_r2r(void *_plan, void *_in, void *_out) nogil: @@ -384,23 +378,20 @@ cdef void _fftw_destroy_null(void *plan): raise RuntimeError("Undefined destroy. This is a bug") -IF HAVE_DOUBLE: - # Double precision - cdef void _fftw_destroy_plan(void *_plan): +# Double precision +cdef void _fftw_destroy_plan(void *_plan): - fftw_destroy_plan(_plan) + fftw_destroy_plan(_plan) -IF HAVE_SINGLE: - # Single precision - cdef void _fftwf_destroy_plan(void *_plan): +# Single precision +cdef void _fftwf_destroy_plan(void *_plan): - fftwf_destroy_plan(_plan) + fftwf_destroy_plan(_plan) -IF HAVE_LONG: - # Long double precision - cdef void _fftwl_destroy_plan(void *_plan): +# Long double precision +cdef void _fftwl_destroy_plan(void *_plan): - fftwl_destroy_plan(_plan) + fftwl_destroy_plan(_plan) # Function lookup tables # ====================== @@ -413,17 +404,17 @@ cdef fftw_generic_plan_guru * _build_planner_list(): for i in range(12): planners[i] = &_fftw_plan_null - IF HAVE_DOUBLE: + if HAVE_DOUBLE: planners[0] = &_fftw_plan_guru_dft planners[3] = &_fftw_plan_guru_dft_r2c planners[6] = &_fftw_plan_guru_dft_c2r planners[9] = &_fftw_plan_guru_r2r - IF HAVE_SINGLE: + if HAVE_SINGLE: planners[1] = &_fftwf_plan_guru_dft planners[4] = &_fftwf_plan_guru_dft_r2c planners[7] = &_fftwf_plan_guru_dft_c2r planners[10] = &_fftwf_plan_guru_r2r - IF HAVE_LONG: + if HAVE_LONG: planners[2] = &_fftwl_plan_guru_dft planners[5] = &_fftwl_plan_guru_dft_r2c planners[8] = &_fftwl_plan_guru_dft_c2r @@ -436,17 +427,17 @@ cdef fftw_generic_execute * _build_executor_list(): for i in range(12): executors[i] = &_fftw_execute_null - IF HAVE_DOUBLE: + if HAVE_DOUBLE: executors[0] = &_fftw_execute_dft executors[3] = &_fftw_execute_dft_r2c executors[6] = &_fftw_execute_dft_c2r executors[9] = &_fftw_execute_r2r - IF HAVE_SINGLE: + if HAVE_SINGLE: executors[1] = &_fftwf_execute_dft executors[4] = &_fftwf_execute_dft_r2c executors[7] = &_fftwf_execute_dft_c2r executors[10] = &_fftwf_execute_r2r - IF HAVE_LONG: + if HAVE_LONG: executors[2] = &_fftwl_execute_dft executors[5] = &_fftwl_execute_dft_r2c executors[8] = &_fftwl_execute_dft_c2r @@ -459,11 +450,11 @@ cdef fftw_generic_destroy_plan * _build_destroyer_list(): for i in range(3): destroyers[i] = &_fftw_destroy_null - IF HAVE_DOUBLE: + if HAVE_DOUBLE: destroyers[0] = &_fftw_destroy_plan - IF HAVE_SINGLE: + if HAVE_SINGLE: destroyers[1] = &_fftwf_destroy_plan - IF HAVE_LONG: + if HAVE_LONG: destroyers[2] = &_fftwl_destroy_plan # nthreads plan setters table @@ -477,13 +468,13 @@ cdef fftw_generic_plan_with_nthreads * _build_nthreads_plan_setters_list(): for i in range(3): nthreads_plan_setters[i] = ( &_fftw_plan_with_nthreads_null) - IF HAVE_DOUBLE_MULTITHREADING: + if HAVE_DOUBLE_MULTITHREADING: nthreads_plan_setters[0] = ( &fftw_plan_with_nthreads) - IF HAVE_SINGLE_MULTITHREADING: + if HAVE_SINGLE_MULTITHREADING: nthreads_plan_setters[1] = ( &fftwf_plan_with_nthreads) - IF HAVE_LONG_MULTITHREADING: + if HAVE_LONG_MULTITHREADING: nthreads_plan_setters[2] = ( &fftwl_plan_with_nthreads) @@ -499,13 +490,13 @@ cdef fftw_generic_set_timelimit * _build_set_timelimit_funcs_list(): set_timelimit_funcs[i] = ( &_fftw_generic_set_timelimit_null) - IF HAVE_DOUBLE: + if HAVE_DOUBLE: set_timelimit_funcs[0] = ( &fftw_set_timelimit) - IF HAVE_SINGLE: + if HAVE_SINGLE: set_timelimit_funcs[1] = ( &fftwf_set_timelimit) - IF HAVE_LONG: + if HAVE_LONG: set_timelimit_funcs[2] = ( &fftwl_set_timelimit) @@ -723,17 +714,17 @@ def scheme_functions(scheme): # Set the cleanup routine cdef void _cleanup() noexcept nogil: - IF HAVE_DOUBLE: + if HAVE_DOUBLE: fftw_cleanup() - IF HAVE_SINGLE: + if HAVE_SINGLE: fftwf_cleanup() - IF HAVE_LONG: + if HAVE_LONG: fftwl_cleanup() - IF HAVE_DOUBLE_MULTITHREADING: + if HAVE_DOUBLE_MULTITHREADING: fftw_cleanup_threads() - IF HAVE_SINGLE_MULTITHREADING: + if HAVE_SINGLE_MULTITHREADING: fftwf_cleanup_threads() - IF HAVE_LONG_MULTITHREADING: + if HAVE_LONG_MULTITHREADING: fftwl_cleanup_threads() # Initialize the module @@ -746,11 +737,11 @@ _build_nthreads_plan_setters_list() _build_validators_list() _build_set_timelimit_funcs_list() -IF HAVE_DOUBLE_MULTITHREADING: +if HAVE_DOUBLE_MULTITHREADING: fftw_init_threads() -IF HAVE_SINGLE_MULTITHREADING: +if HAVE_SINGLE_MULTITHREADING: fftwf_init_threads() -IF HAVE_LONG_MULTITHREADING: +if HAVE_LONG_MULTITHREADING: fftwl_init_threads() Py_AtExit(_cleanup) @@ -2046,16 +2037,20 @@ def export_wisdom(): char* c_wisdomf = NULL char* c_wisdoml = NULL + intptr_t c_wisdom_ptr = 0 + intptr_t c_wisdomf_ptr = 0 + intptr_t c_wisdoml_ptr = 0 + # count the length of the string and extract it manually rather than using # `fftw_export_wisdom_to_string` to avoid calling `free` on the string # potentially allocated by a different C library; see #3 - IF HAVE_DOUBLE: + if HAVE_DOUBLE: fftw_export_wisdom(&count_char, &counter) c_wisdom = malloc(sizeof(char)*(counter + 1)) if c_wisdom == NULL: raise MemoryError # Set the pointers to the string pointers - cdef intptr_t c_wisdom_ptr = c_wisdom + c_wisdom_ptr = c_wisdom fftw_export_wisdom(&write_char_to_string, &c_wisdom_ptr) # Write the last byte as the null byte c_wisdom[counter] = 0 @@ -2063,24 +2058,24 @@ def export_wisdom(): py_wisdom = c_wisdom finally: free(c_wisdom) - IF HAVE_SINGLE: + if HAVE_SINGLE: fftwf_export_wisdom(&count_char, &counterf) c_wisdomf = malloc(sizeof(char)*(counterf + 1)) if c_wisdomf == NULL: raise MemoryError - cdef intptr_t c_wisdomf_ptr = c_wisdomf + c_wisdomf_ptr = c_wisdomf fftwf_export_wisdom(&write_char_to_string, &c_wisdomf_ptr) c_wisdomf[counterf] = 0 try: py_wisdomf = c_wisdomf finally: free(c_wisdomf) - IF HAVE_LONG: + if HAVE_LONG: fftwl_export_wisdom(&count_char, &counterl) c_wisdoml = malloc(sizeof(char)*(counterl + 1)) if c_wisdoml == NULL: raise MemoryError - cdef intptr_t c_wisdoml_ptr = c_wisdoml + c_wisdoml_ptr = c_wisdoml fftwl_export_wisdom(&write_char_to_string, &c_wisdoml_ptr) c_wisdoml[counterl] = 0 try: @@ -2118,11 +2113,11 @@ def import_wisdom(wisdom): bint successf = False bint successl = False - IF HAVE_DOUBLE: + if HAVE_DOUBLE: success = fftw_import_wisdom_from_string(c_wisdom) - IF HAVE_SINGLE: + if HAVE_SINGLE: successf = fftwf_import_wisdom_from_string(c_wisdomf) - IF HAVE_LONG: + if HAVE_LONG: successl = fftwl_import_wisdom_from_string(c_wisdoml) return (success, successf, successl) @@ -2218,9 +2213,9 @@ def forget_wisdom(): Forget all the accumulated wisdom. ''' - IF HAVE_DOUBLE: + if HAVE_DOUBLE: fftw_forget_wisdom() - IF HAVE_SINGLE: + if HAVE_SINGLE: fftwf_forget_wisdom() - IF HAVE_LONG: + if HAVE_LONG: fftwl_forget_wisdom() From 8cf9b559d45fd71bb0338788a0c02fd4507da9bc Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Wed, 13 Sep 2023 16:51:43 -0400 Subject: [PATCH 09/12] Migrate away from deprecated pkg_resources. The current implementation in setuptools uses sysconfig.get_platform directly for the platforms being checked in setup.py. --- setup.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index b13d30a6..30b7d9a4 100755 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ # fallback to distutils for older setuptools releases from distutils.errors import CompileError, LinkError from distutils.extension import Extension -from pkg_resources import get_platform +from sysconfig import get_platform from contextlib import redirect_stderr, redirect_stdout import os @@ -68,7 +68,6 @@ def get_include_dirs(): import numpy - from pkg_resources import get_build_platform include_dirs = [os.path.join(os.getcwd(), 'include'), os.path.join(os.getcwd(), 'pyfftw'), @@ -78,24 +77,22 @@ def get_include_dirs(): if 'PYFFTW_INCLUDE' in os.environ: include_dirs.append(os.environ['PYFFTW_INCLUDE']) - if get_build_platform().startswith("linux"): + if get_platform().startswith("linux"): include_dirs.append('/usr/include') - if get_build_platform() in ('win32', 'win-amd64'): + if get_platform() in ('win32', 'win-amd64'): include_dirs.append(os.path.join(os.getcwd(), 'include', 'win')) - if get_build_platform().startswith('freebsd'): + if get_platform().startswith('freebsd'): include_dirs.append('/usr/local/include') return include_dirs def get_package_data(): - from pkg_resources import get_build_platform - package_data = {} - if get_build_platform() in ('win32', 'win-amd64'): + if get_platform() in ('win32', 'win-amd64'): if 'PYFFTW_WIN_CONDAFORGE' in os.environ: # fftw3.dll, fftw3f.dll will already be on the path (via the # conda environment's \bin subfolder) @@ -109,10 +106,8 @@ def get_package_data(): def get_library_dirs(): - from pkg_resources import get_build_platform - library_dirs = [] - if get_build_platform() in ('win32', 'win-amd64'): + if get_platform() in ('win32', 'win-amd64'): library_dirs.append(os.path.join(os.getcwd(), 'pyfftw')) library_dirs.append(os.path.join(sys.prefix, 'bin')) @@ -120,7 +115,7 @@ def get_library_dirs(): library_dirs.append(os.environ['PYFFTW_LIB_DIR']) library_dirs.append(os.path.join(sys.prefix, 'lib')) - if get_build_platform().startswith('freebsd'): + if get_platform().startswith('freebsd'): library_dirs.append('/usr/local/lib') return library_dirs @@ -532,8 +527,7 @@ def has_library(self, root_name, function, function_args): def lib_full_name(self, root_lib): # TODO use self.compiler.library_filename - from pkg_resources import get_build_platform - if get_build_platform() in ('win32', 'win-amd64'): + if get_platform() in ('win32', 'win-amd64'): lib_pre = '' lib_ext = '.lib' else: From a2bbefcad1b87ab2c6fcb59cd98d78f3489bdb86 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Thu, 14 Sep 2023 15:24:38 -0400 Subject: [PATCH 10/12] Prefix preprocessor definitions with "PYFFTW". Ensure we avoid any collisions now that these are left until C preprocessing. --- pyfftw/pyfftw.pxd | 36 ++++++++++----------- pyfftw/pyfftw.pyx | 82 +++++++++++++++++++++++------------------------ setup.py | 2 +- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index 578b147f..59af0f9a 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -38,18 +38,18 @@ cimport numpy as np from libc.stdint cimport int64_t cdef extern from *: - bint HAVE_SINGLE - bint HAVE_DOUBLE - bint HAVE_LONG - bint HAVE_SINGLE_OMP - bint HAVE_DOUBLE_OMP - bint HAVE_LONG_OMP - bint HAVE_SINGLE_THREADS - bint HAVE_DOUBLE_THREADS - bint HAVE_LONG_THREADS - bint HAVE_SINGLE_MULTITHREADING - bint HAVE_DOUBLE_MULTITHREADING - bint HAVE_LONG_MULTITHREADING + bint PYFFTW_HAVE_SINGLE + bint PYFFTW_HAVE_DOUBLE + bint PYFFTW_HAVE_LONG + bint PYFFTW_HAVE_SINGLE_OMP + bint PYFFTW_HAVE_DOUBLE_OMP + bint PYFFTW_HAVE_LONG_OMP + bint PYFFTW_HAVE_SINGLE_THREADS + bint PYFFTW_HAVE_DOUBLE_THREADS + bint PYFFTW_HAVE_LONG_THREADS + bint PYFFTW_HAVE_SINGLE_MULTITHREADING + bint PYFFTW_HAVE_DOUBLE_MULTITHREADING + bint PYFFTW_HAVE_LONG_MULTITHREADING ctypedef struct _fftw_iodim: int _n @@ -64,7 +64,7 @@ cdef extern from 'pyfftw_complex.h': cdef extern from 'fftw3.h': """ - #if !HAVE_DOUBLE + #if !PYFFTW_HAVE_DOUBLE #define fftw_plan_guru_dft(...) (NULL) #define fftw_plan_guru_dft_r2c(...) (NULL) #define fftw_plan_guru_dft_c2r(...) (NULL) @@ -80,7 +80,7 @@ cdef extern from 'fftw3.h': #define fftw_forget_wisdom() ((void)0) #endif - #if !HAVE_SINGLE + #if !PYFFTW_HAVE_SINGLE #define fftwf_plan_guru_dft(...) (NULL) #define fftwf_plan_guru_dft_r2c(...) (NULL) #define fftwf_plan_guru_dft_c2r(...) (NULL) @@ -96,7 +96,7 @@ cdef extern from 'fftw3.h': #define fftwf_forget_wisdom() ((void)0) #endif - #if !HAVE_LONG + #if !PYFFTW_HAVE_LONG #define fftwl_plan_guru_dft(...) (NULL) #define fftwl_plan_guru_dft_r2c(...) (NULL) #define fftwl_plan_guru_dft_c2r(...) (NULL) @@ -112,17 +112,17 @@ cdef extern from 'fftw3.h': #define fftwl_forget_wisdom() ((void)0) #endif - #if !HAVE_DOUBLE_MULTITHREADING + #if !PYFFTW_HAVE_DOUBLE_MULTITHREADING #define fftw_cleanup_threads() ((void)0) #define fftw_init_threads() ((void)0) #endif - #if !HAVE_SINGLE_MULTITHREADING + #if !PYFFTW_HAVE_SINGLE_MULTITHREADING #define fftwf_cleanup_threads() ((void)0) #define fftwf_init_threads() ((void)0) #endif - #if !HAVE_LONG_MULTITHREADING + #if !PYFFTW_HAVE_LONG_MULTITHREADING #define fftwl_cleanup_threads() ((void)0) #define fftwl_init_threads() ((void)0) #endif diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index c910a3ed..ace06cac 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -70,22 +70,22 @@ _supported_types = [] _supported_nptypes_complex = [] _supported_nptypes_real = [] -if HAVE_SINGLE: +if PYFFTW_HAVE_SINGLE: _supported_types.append('32') _supported_nptypes_complex.append(np.complex64) _supported_nptypes_real.append(np.float32) -if HAVE_DOUBLE: +if PYFFTW_HAVE_DOUBLE: _supported_types.append('64') _supported_nptypes_complex.append(np.complex128) _supported_nptypes_real.append(np.float64) -if HAVE_LONG: +if PYFFTW_HAVE_LONG: _supported_types.append('ld') _supported_nptypes_complex.append(np.clongdouble) _supported_nptypes_real.append(np.longdouble) -if (HAVE_SINGLE_OMP or HAVE_DOUBLE_OMP or HAVE_LONG_OMP): +if (PYFFTW_HAVE_SINGLE_OMP or PYFFTW_HAVE_DOUBLE_OMP or PYFFTW_HAVE_LONG_OMP): _threading_type = 'OMP' -elif (HAVE_SINGLE_THREADS or HAVE_DOUBLE_THREADS or HAVE_LONG_THREADS): +elif (PYFFTW_HAVE_SINGLE_THREADS or PYFFTW_HAVE_DOUBLE_THREADS or PYFFTW_HAVE_LONG_THREADS): _threading_type = 'PTHREADS' else: _threading_type = None @@ -404,17 +404,17 @@ cdef fftw_generic_plan_guru * _build_planner_list(): for i in range(12): planners[i] = &_fftw_plan_null - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: planners[0] = &_fftw_plan_guru_dft planners[3] = &_fftw_plan_guru_dft_r2c planners[6] = &_fftw_plan_guru_dft_c2r planners[9] = &_fftw_plan_guru_r2r - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: planners[1] = &_fftwf_plan_guru_dft planners[4] = &_fftwf_plan_guru_dft_r2c planners[7] = &_fftwf_plan_guru_dft_c2r planners[10] = &_fftwf_plan_guru_r2r - if HAVE_LONG: + if PYFFTW_HAVE_LONG: planners[2] = &_fftwl_plan_guru_dft planners[5] = &_fftwl_plan_guru_dft_r2c planners[8] = &_fftwl_plan_guru_dft_c2r @@ -427,17 +427,17 @@ cdef fftw_generic_execute * _build_executor_list(): for i in range(12): executors[i] = &_fftw_execute_null - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: executors[0] = &_fftw_execute_dft executors[3] = &_fftw_execute_dft_r2c executors[6] = &_fftw_execute_dft_c2r executors[9] = &_fftw_execute_r2r - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: executors[1] = &_fftwf_execute_dft executors[4] = &_fftwf_execute_dft_r2c executors[7] = &_fftwf_execute_dft_c2r executors[10] = &_fftwf_execute_r2r - if HAVE_LONG: + if PYFFTW_HAVE_LONG: executors[2] = &_fftwl_execute_dft executors[5] = &_fftwl_execute_dft_r2c executors[8] = &_fftwl_execute_dft_c2r @@ -450,11 +450,11 @@ cdef fftw_generic_destroy_plan * _build_destroyer_list(): for i in range(3): destroyers[i] = &_fftw_destroy_null - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: destroyers[0] = &_fftw_destroy_plan - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: destroyers[1] = &_fftwf_destroy_plan - if HAVE_LONG: + if PYFFTW_HAVE_LONG: destroyers[2] = &_fftwl_destroy_plan # nthreads plan setters table @@ -468,13 +468,13 @@ cdef fftw_generic_plan_with_nthreads * _build_nthreads_plan_setters_list(): for i in range(3): nthreads_plan_setters[i] = ( &_fftw_plan_with_nthreads_null) - if HAVE_DOUBLE_MULTITHREADING: + if PYFFTW_HAVE_DOUBLE_MULTITHREADING: nthreads_plan_setters[0] = ( &fftw_plan_with_nthreads) - if HAVE_SINGLE_MULTITHREADING: + if PYFFTW_HAVE_SINGLE_MULTITHREADING: nthreads_plan_setters[1] = ( &fftwf_plan_with_nthreads) - if HAVE_LONG_MULTITHREADING: + if PYFFTW_HAVE_LONG_MULTITHREADING: nthreads_plan_setters[2] = ( &fftwl_plan_with_nthreads) @@ -490,13 +490,13 @@ cdef fftw_generic_set_timelimit * _build_set_timelimit_funcs_list(): set_timelimit_funcs[i] = ( &_fftw_generic_set_timelimit_null) - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: set_timelimit_funcs[0] = ( &fftw_set_timelimit) - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: set_timelimit_funcs[1] = ( &fftwf_set_timelimit) - if HAVE_LONG: + if PYFFTW_HAVE_LONG: set_timelimit_funcs[2] = ( &fftwl_set_timelimit) @@ -665,7 +665,7 @@ scheme_directions = { # sufficiently trivial to use -1 in place of None, especially given # that scheme_functions is an internal cdef object. cdef object _scheme_functions = {} -if HAVE_DOUBLE: +if PYFFTW_HAVE_DOUBLE: _scheme_functions.update({ ('c2c', '64'): {'planner': 0, 'executor':0, 'generic_precision':0, 'validator': -1, 'fft_shape_lookup': -1}, @@ -677,7 +677,7 @@ if HAVE_DOUBLE: 'fft_shape_lookup': _lookup_shape_c2r_arrays}, ('r2r', '64'): {'planner': 9, 'executor':9, 'generic_precision':0, 'validator': -1, 'fft_shape_lookup': -1}}) -if HAVE_SINGLE: +if PYFFTW_HAVE_SINGLE: _scheme_functions.update({ ('c2c', '32'): {'planner':1, 'executor':1, 'generic_precision':1, 'validator': -1, 'fft_shape_lookup': -1}, @@ -689,7 +689,7 @@ if HAVE_SINGLE: 'fft_shape_lookup': _lookup_shape_c2r_arrays}, ('r2r', '32'): {'planner':10, 'executor':10, 'generic_precision':1, 'validator': -1, 'fft_shape_lookup': -1}}) -if HAVE_LONG: +if PYFFTW_HAVE_LONG: _scheme_functions.update({ ('c2c', 'ld'): {'planner':2, 'executor':2, 'generic_precision':2, 'validator': -1, 'fft_shape_lookup': -1}, @@ -714,17 +714,17 @@ def scheme_functions(scheme): # Set the cleanup routine cdef void _cleanup() noexcept nogil: - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: fftw_cleanup() - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: fftwf_cleanup() - if HAVE_LONG: + if PYFFTW_HAVE_LONG: fftwl_cleanup() - if HAVE_DOUBLE_MULTITHREADING: + if PYFFTW_HAVE_DOUBLE_MULTITHREADING: fftw_cleanup_threads() - if HAVE_SINGLE_MULTITHREADING: + if PYFFTW_HAVE_SINGLE_MULTITHREADING: fftwf_cleanup_threads() - if HAVE_LONG_MULTITHREADING: + if PYFFTW_HAVE_LONG_MULTITHREADING: fftwl_cleanup_threads() # Initialize the module @@ -737,11 +737,11 @@ _build_nthreads_plan_setters_list() _build_validators_list() _build_set_timelimit_funcs_list() -if HAVE_DOUBLE_MULTITHREADING: +if PYFFTW_HAVE_DOUBLE_MULTITHREADING: fftw_init_threads() -if HAVE_SINGLE_MULTITHREADING: +if PYFFTW_HAVE_SINGLE_MULTITHREADING: fftwf_init_threads() -if HAVE_LONG_MULTITHREADING: +if PYFFTW_HAVE_LONG_MULTITHREADING: fftwl_init_threads() Py_AtExit(_cleanup) @@ -2044,7 +2044,7 @@ def export_wisdom(): # count the length of the string and extract it manually rather than using # `fftw_export_wisdom_to_string` to avoid calling `free` on the string # potentially allocated by a different C library; see #3 - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: fftw_export_wisdom(&count_char, &counter) c_wisdom = malloc(sizeof(char)*(counter + 1)) if c_wisdom == NULL: @@ -2058,7 +2058,7 @@ def export_wisdom(): py_wisdom = c_wisdom finally: free(c_wisdom) - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: fftwf_export_wisdom(&count_char, &counterf) c_wisdomf = malloc(sizeof(char)*(counterf + 1)) if c_wisdomf == NULL: @@ -2070,7 +2070,7 @@ def export_wisdom(): py_wisdomf = c_wisdomf finally: free(c_wisdomf) - if HAVE_LONG: + if PYFFTW_HAVE_LONG: fftwl_export_wisdom(&count_char, &counterl) c_wisdoml = malloc(sizeof(char)*(counterl + 1)) if c_wisdoml == NULL: @@ -2113,11 +2113,11 @@ def import_wisdom(wisdom): bint successf = False bint successl = False - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: success = fftw_import_wisdom_from_string(c_wisdom) - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: successf = fftwf_import_wisdom_from_string(c_wisdomf) - if HAVE_LONG: + if PYFFTW_HAVE_LONG: successl = fftwl_import_wisdom_from_string(c_wisdoml) return (success, successf, successl) @@ -2213,9 +2213,9 @@ def forget_wisdom(): Forget all the accumulated wisdom. ''' - if HAVE_DOUBLE: + if PYFFTW_HAVE_DOUBLE: fftw_forget_wisdom() - if HAVE_SINGLE: + if PYFFTW_HAVE_SINGLE: fftwf_forget_wisdom() - if HAVE_LONG: + if PYFFTW_HAVE_LONG: fftwl_forget_wisdom() diff --git a/setup.py b/setup.py index 30b7d9a4..dc319c63 100755 --- a/setup.py +++ b/setup.py @@ -616,7 +616,7 @@ def build_extensions(self): # define macros, that is which part of wrapper is built self._pyfftw_define_macros = [ - (k, int(v)) for k, v in sniffer.compile_time_env.items() + (f"PYFFTW_{k}", int(v)) for k, v in sniffer.compile_time_env.items() ] # call `extend()` to keep argument set neither by sniffer nor by From 38b4f0fd66ac0d105c70dbc368096039467879c8 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Mon, 6 Nov 2023 14:57:47 -0500 Subject: [PATCH 11/12] Add additional noexcept declarations to FFTW wrapping functions. This silences some performance warnings from Cython mentioning that the GIL will be reaquired to check for Python exceptions that will not be set by FFTW. --- pyfftw/pyfftw.pyx | 54 +++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index ace06cac..0ed3402c 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -155,7 +155,7 @@ cdef void* _fftw_plan_guru_dft( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftw_plan_guru_dft(rank, dims, howmany_rank, howmany_dims, @@ -167,7 +167,7 @@ cdef void* _fftw_plan_guru_dft_r2c( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftw_plan_guru_dft_r2c(rank, dims, howmany_rank, howmany_dims, @@ -179,7 +179,7 @@ cdef void* _fftw_plan_guru_dft_c2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftw_plan_guru_dft_c2r(rank, dims, howmany_rank, howmany_dims, @@ -191,7 +191,7 @@ cdef void* _fftw_plan_guru_r2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags) nogil: + int *direction, int flags) noexcept nogil: return fftw_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -203,7 +203,7 @@ cdef void* _fftwf_plan_guru_dft( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwf_plan_guru_dft(rank, dims, howmany_rank, howmany_dims, @@ -215,7 +215,7 @@ cdef void* _fftwf_plan_guru_dft_r2c( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwf_plan_guru_dft_r2c(rank, dims, howmany_rank, howmany_dims, @@ -227,7 +227,7 @@ cdef void* _fftwf_plan_guru_dft_c2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwf_plan_guru_dft_c2r(rank, dims, howmany_rank, howmany_dims, @@ -239,7 +239,7 @@ cdef void* _fftwf_plan_guru_r2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags) nogil: + int *direction, int flags) noexcept nogil: return fftwf_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -251,7 +251,7 @@ cdef void* _fftwl_plan_guru_dft( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwl_plan_guru_dft(rank, dims, howmany_rank, howmany_dims, @@ -263,7 +263,7 @@ cdef void* _fftwl_plan_guru_dft_r2c( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwl_plan_guru_dft_r2c(rank, dims, howmany_rank, howmany_dims, @@ -275,7 +275,7 @@ cdef void* _fftwl_plan_guru_dft_c2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, unsigned flags) nogil: + int *direction, unsigned flags) noexcept nogil: return fftwl_plan_guru_dft_c2r(rank, dims, howmany_rank, howmany_dims, @@ -287,7 +287,7 @@ cdef void* _fftwl_plan_guru_r2r( int rank, fftw_iodim *dims, int howmany_rank, fftw_iodim *howmany_dims, void *_in, void *_out, - int *direction, int flags) nogil: + int *direction, int flags) noexcept nogil: return fftwl_plan_guru_r2r(rank, dims, howmany_rank, howmany_dims, @@ -303,71 +303,71 @@ cdef void _fftw_execute_null(void *_plan, void *_in, void *_out) with gil: raise RuntimeError("Undefined executor. This is a bug") # Complex double precision -cdef void _fftw_execute_dft(void *_plan, void *_in, void *_out) nogil: +cdef void _fftw_execute_dft(void *_plan, void *_in, void *_out) noexcept nogil: fftw_execute_dft(_plan, _in, _out) # real to complex double precision -cdef void _fftw_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +cdef void _fftw_execute_dft_r2c(void *_plan, void *_in, void *_out) noexcept nogil: fftw_execute_dft_r2c(_plan, _in, _out) # complex to real double precision -cdef void _fftw_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftw_execute_dft_c2r(void *_plan, void *_in, void *_out) noexcept nogil: fftw_execute_dft_c2r(_plan, _in, _out) # Complex single precision -cdef void _fftwf_execute_dft(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwf_execute_dft(void *_plan, void *_in, void *_out) noexcept nogil: fftwf_execute_dft(_plan, _in, _out) # real to complex single precision -cdef void _fftwf_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwf_execute_dft_r2c(void *_plan, void *_in, void *_out) noexcept nogil: fftwf_execute_dft_r2c(_plan, _in, _out) # complex to real single precision -cdef void _fftwf_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwf_execute_dft_c2r(void *_plan, void *_in, void *_out) noexcept nogil: fftwf_execute_dft_c2r(_plan, _in, _out) # Complex long double precision -cdef void _fftwl_execute_dft(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwl_execute_dft(void *_plan, void *_in, void *_out) noexcept nogil: fftwl_execute_dft(_plan, _in, _out) # real to complex long double precision -cdef void _fftwl_execute_dft_r2c(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwl_execute_dft_r2c(void *_plan, void *_in, void *_out) noexcept nogil: fftwl_execute_dft_r2c(_plan, _in, _out) # complex to real long double precision -cdef void _fftwl_execute_dft_c2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwl_execute_dft_c2r(void *_plan, void *_in, void *_out) noexcept nogil: fftwl_execute_dft_c2r(_plan, _in, _out) # real to real double precision -cdef void _fftw_execute_r2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftw_execute_r2r(void *_plan, void *_in, void *_out) noexcept nogil: fftw_execute_r2r(_plan, _in, _out) # real to real single precision -cdef void _fftwf_execute_r2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwf_execute_r2r(void *_plan, void *_in, void *_out) noexcept nogil: fftwf_execute_r2r(_plan, _in, _out) # real to real long double precision -cdef void _fftwl_execute_r2r(void *_plan, void *_in, void *_out) nogil: +cdef void _fftwl_execute_r2r(void *_plan, void *_in, void *_out) noexcept nogil: fftwl_execute_r2r(_plan, _in, _out) @@ -379,17 +379,17 @@ cdef void _fftw_destroy_null(void *plan): raise RuntimeError("Undefined destroy. This is a bug") # Double precision -cdef void _fftw_destroy_plan(void *_plan): +cdef void _fftw_destroy_plan(void *_plan) noexcept: fftw_destroy_plan(_plan) # Single precision -cdef void _fftwf_destroy_plan(void *_plan): +cdef void _fftwf_destroy_plan(void *_plan) noexcept: fftwf_destroy_plan(_plan) # Long double precision -cdef void _fftwl_destroy_plan(void *_plan): +cdef void _fftwl_destroy_plan(void *_plan) noexcept: fftwl_destroy_plan(_plan) From 2494ad5f6354ed577fca1985cb6ed6a75c615f19 Mon Sep 17 00:00:00 2001 From: Karl Otness Date: Mon, 6 Nov 2023 15:02:13 -0500 Subject: [PATCH 12/12] Handle conditional use of set_timelimit and plan_with_nthreads. These were missing some additional Cython cdef wrappers for use in cases where the symbols might be missing. --- pyfftw/pyfftw.pxd | 6 ++++++ pyfftw/pyfftw.pyx | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/pyfftw/pyfftw.pxd b/pyfftw/pyfftw.pxd index 59af0f9a..2abc2ad4 100644 --- a/pyfftw/pyfftw.pxd +++ b/pyfftw/pyfftw.pxd @@ -78,6 +78,7 @@ cdef extern from 'fftw3.h': #define fftw_export_wisdom(...) ((void)0) #define fftw_import_wisdom_from_string(wisdom) (0) #define fftw_forget_wisdom() ((void)0) + #define fftw_set_timelimit(...) ((void)0) #endif #if !PYFFTW_HAVE_SINGLE @@ -94,6 +95,7 @@ cdef extern from 'fftw3.h': #define fftwf_export_wisdom(...) ((void)0) #define fftwf_import_wisdom_from_string(wisdom) (0) #define fftwf_forget_wisdom() ((void)0) + #define fftwf_set_timelimit(...) ((void)0) #endif #if !PYFFTW_HAVE_LONG @@ -110,21 +112,25 @@ cdef extern from 'fftw3.h': #define fftwl_export_wisdom(...) ((void)0) #define fftwl_import_wisdom_from_string(wisdom) (0) #define fftwl_forget_wisdom() ((void)0) + #define fftwl_set_timelimit(...) ((void)0) #endif #if !PYFFTW_HAVE_DOUBLE_MULTITHREADING #define fftw_cleanup_threads() ((void)0) #define fftw_init_threads() ((void)0) + #define fftw_plan_with_nthreads(...) ((void)0) #endif #if !PYFFTW_HAVE_SINGLE_MULTITHREADING #define fftwf_cleanup_threads() ((void)0) #define fftwf_init_threads() ((void)0) + #define fftwf_plan_with_nthreads(...) ((void)0) #endif #if !PYFFTW_HAVE_LONG_MULTITHREADING #define fftwl_cleanup_threads() ((void)0) #define fftwl_init_threads() ((void)0) + #define fftwl_plan_with_nthreads(...) ((void)0) #endif """ diff --git a/pyfftw/pyfftw.pyx b/pyfftw/pyfftw.pyx index 0ed3402c..3d0a2d5e 100644 --- a/pyfftw/pyfftw.pyx +++ b/pyfftw/pyfftw.pyx @@ -464,27 +464,51 @@ cdef void _fftw_plan_with_nthreads_null(int n): raise RuntimeError("Undefined plan with nthreads. This is a bug") +cdef void _fftw_plan_with_nthreads(int n) noexcept: + + fftw_plan_with_nthreads(n) + +cdef void _fftwf_plan_with_nthreads(int n) noexcept: + + fftwf_plan_with_nthreads(n) + +cdef void _fftwl_plan_with_nthreads(int n) noexcept: + + fftwl_plan_with_nthreads(n) + cdef fftw_generic_plan_with_nthreads * _build_nthreads_plan_setters_list(): for i in range(3): nthreads_plan_setters[i] = ( &_fftw_plan_with_nthreads_null) if PYFFTW_HAVE_DOUBLE_MULTITHREADING: nthreads_plan_setters[0] = ( - &fftw_plan_with_nthreads) + &_fftw_plan_with_nthreads) if PYFFTW_HAVE_SINGLE_MULTITHREADING: nthreads_plan_setters[1] = ( - &fftwf_plan_with_nthreads) + &_fftwf_plan_with_nthreads) if PYFFTW_HAVE_LONG_MULTITHREADING: nthreads_plan_setters[2] = ( - &fftwl_plan_with_nthreads) + &_fftwl_plan_with_nthreads) # Set planner timelimits cdef fftw_generic_set_timelimit set_timelimit_funcs[3] -cdef void _fftw_generic_set_timelimit_null(void *plan): +cdef void _fftw_generic_set_timelimit_null(double seconds): raise RuntimeError("Undefined set timelimit. This is a bug") +cdef void _fftw_set_timelimit(double seconds) noexcept: + + fftw_set_timelimit(seconds) + +cdef void _fftwf_set_timelimit(double seconds) noexcept: + + fftwf_set_timelimit(seconds) + +cdef void _fftwl_set_timelimit(double seconds) noexcept: + + fftwl_set_timelimit(seconds) + cdef fftw_generic_set_timelimit * _build_set_timelimit_funcs_list(): for i in range(3): set_timelimit_funcs[i] = ( @@ -492,13 +516,13 @@ cdef fftw_generic_set_timelimit * _build_set_timelimit_funcs_list(): if PYFFTW_HAVE_DOUBLE: set_timelimit_funcs[0] = ( - &fftw_set_timelimit) + &_fftw_set_timelimit) if PYFFTW_HAVE_SINGLE: set_timelimit_funcs[1] = ( - &fftwf_set_timelimit) + &_fftwf_set_timelimit) if PYFFTW_HAVE_LONG: set_timelimit_funcs[2] = ( - &fftwl_set_timelimit) + &_fftwl_set_timelimit) # Data validators table cdef validator validators[2]