gh-61103: Support double complex (_Complex) type in ctypes (#120894)

Example:

```pycon
>>> import ctypes
>>> ctypes.__STDC_IEC_559_COMPLEX__
1
>>> libm = ctypes.CDLL('libm.so.6')
>>> libm.clog.argtypes = [ctypes.c_double_complex]
>>> libm.clog.restype = ctypes.c_double_complex
>>> libm.clog(1+1j)
(0.34657359027997264+0.7853981633974483j)
```

Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
Sergey B Kirpichev 2024-07-01 11:54:33 +03:00 committed by GitHub
parent a0b8b342c5
commit 6988ff02a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 316 additions and 17 deletions

View File

@ -266,6 +266,16 @@ Fundamental data types
(1) (1)
The constructor accepts any object with a truth value. The constructor accepts any object with a truth value.
Additionally, if IEC 60559 compatible complex arithmetic (Annex G) is supported, the following
complex types are available:
+----------------------------------+---------------------------------+-----------------+
| ctypes type | C type | Python type |
+==================================+=================================+=================+
| :class:`c_double_complex` | :c:expr:`double complex` | complex |
+----------------------------------+---------------------------------+-----------------+
All these types can be created by calling them with an optional initializer of All these types can be created by calling them with an optional initializer of
the correct type and value:: the correct type and value::
@ -2284,6 +2294,14 @@ These are the fundamental ctypes data types:
optional float initializer. optional float initializer.
.. class:: c_double_complex
Represents the C :c:expr:`double complex` datatype, if available. The
constructor accepts an optional :class:`complex` initializer.
.. versionadded:: 3.14
.. class:: c_int .. class:: c_int
Represents the C :c:expr:`signed int` datatype. The constructor accepts an Represents the C :c:expr:`signed int` datatype. The constructor accepts an

View File

@ -205,6 +205,12 @@ class c_longdouble(_SimpleCData):
if sizeof(c_longdouble) == sizeof(c_double): if sizeof(c_longdouble) == sizeof(c_double):
c_longdouble = c_double c_longdouble = c_double
try:
class c_double_complex(_SimpleCData):
_type_ = "C"
except AttributeError:
pass
if _calcsize("l") == _calcsize("q"): if _calcsize("l") == _calcsize("q"):
# if long and long long have the same size, make c_longlong an alias for c_long # if long and long long have the same size, make c_longlong an alias for c_long
c_longlong = c_long c_longlong = c_long

View File

@ -1,3 +1,4 @@
import ctypes
import math import math
import unittest import unittest
from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof,
@ -21,6 +22,17 @@ class LibTest(unittest.TestCase):
self.assertEqual(lib.my_sqrt(4.0), 2.0) self.assertEqual(lib.my_sqrt(4.0), 2.0)
self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0))
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_csqrt(self):
lib.my_csqrt.argtypes = ctypes.c_double_complex,
lib.my_csqrt.restype = ctypes.c_double_complex
self.assertEqual(lib.my_csqrt(4), 2+0j)
self.assertAlmostEqual(lib.my_csqrt(-1+0.01j),
0.004999937502734214+1.0000124996093955j)
self.assertAlmostEqual(lib.my_csqrt(-1-0.01j),
0.004999937502734214-1.0000124996093955j)
def test_qsort(self): def test_qsort(self):
comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char))
lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc

View File

@ -1,7 +1,10 @@
import array import array
import ctypes
import struct import struct
import sys import sys
import unittest import unittest
from itertools import combinations
from math import copysign, isnan
from operator import truth from operator import truth
from ctypes import (byref, sizeof, alignment, from ctypes import (byref, sizeof, alignment,
c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint, c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint,
@ -38,8 +41,55 @@ unsigned_ranges = valid_ranges(*unsigned_types)
signed_ranges = valid_ranges(*signed_types) signed_ranges = valid_ranges(*signed_types)
bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]] bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]
class IntLike:
def __int__(self):
return 2
class IndexLike:
def __index__(self):
return 2
class FloatLike:
def __float__(self):
return 2.0
class ComplexLike:
def __complex__(self):
return 1+1j
INF = float("inf")
NAN = float("nan")
class NumberTestCase(unittest.TestCase): class NumberTestCase(unittest.TestCase):
# from Lib/test/test_complex.py
def assertFloatsAreIdentical(self, x, y):
"""assert that floats x and y are identical, in the sense that:
(1) both x and y are nans, or
(2) both x and y are infinities, with the same sign, or
(3) both x and y are zeros, with the same sign, or
(4) x and y are both finite and nonzero, and x == y
"""
msg = 'floats {!r} and {!r} are not identical'
if isnan(x) or isnan(y):
if isnan(x) and isnan(y):
return
elif x == y:
if x != 0.0:
return
# both zero; check that signs match
elif copysign(1.0, x) == copysign(1.0, y):
return
else:
msg += ': zeros have different signs'
self.fail(msg.format(x, y))
def assertComplexesAreIdentical(self, x, y):
self.assertFloatsAreIdentical(x.real, y.real)
self.assertFloatsAreIdentical(x.imag, y.imag)
def test_default_init(self): def test_default_init(self):
# default values are set to zero # default values are set to zero
@ -86,9 +136,6 @@ class NumberTestCase(unittest.TestCase):
def test_floats(self): def test_floats(self):
# c_float and c_double can be created from # c_float and c_double can be created from
# Python int and float # Python int and float
class FloatLike:
def __float__(self):
return 2.0
f = FloatLike() f = FloatLike()
for t in float_types: for t in float_types:
self.assertEqual(t(2.0).value, 2.0) self.assertEqual(t(2.0).value, 2.0)
@ -96,18 +143,32 @@ class NumberTestCase(unittest.TestCase):
self.assertEqual(t(2).value, 2.0) self.assertEqual(t(2).value, 2.0)
self.assertEqual(t(f).value, 2.0) self.assertEqual(t(f).value, 2.0)
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex(self):
for t in [ctypes.c_double_complex]:
self.assertEqual(t(1).value, 1+0j)
self.assertEqual(t(1.0).value, 1+0j)
self.assertEqual(t(1+0.125j).value, 1+0.125j)
self.assertEqual(t(IndexLike()).value, 2+0j)
self.assertEqual(t(FloatLike()).value, 2+0j)
self.assertEqual(t(ComplexLike()).value, 1+1j)
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex_round_trip(self):
# Ensure complexes transformed exactly. The CMPLX macro should
# preserve special components (like inf/nan or signed zero).
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
-3, INF, -INF, NAN], 2)]
for z in values:
with self.subTest(z=z):
z2 = ctypes.c_double_complex(z).value
self.assertComplexesAreIdentical(z, z2)
def test_integers(self): def test_integers(self):
class FloatLike:
def __float__(self):
return 2.0
f = FloatLike() f = FloatLike()
class IntLike:
def __int__(self):
return 2
d = IntLike() d = IntLike()
class IndexLike:
def __index__(self):
return 2
i = IndexLike() i = IndexLike()
# integers cannot be constructed from floats, # integers cannot be constructed from floats,
# but from integer-like objects # but from integer-like objects

View File

@ -3125,7 +3125,7 @@ MODULE_MATH_DEPS=$(srcdir)/Modules/_math.h
MODULE_PYEXPAT_DEPS=@LIBEXPAT_INTERNAL@ MODULE_PYEXPAT_DEPS=@LIBEXPAT_INTERNAL@
MODULE_UNICODEDATA_DEPS=$(srcdir)/Modules/unicodedata_db.h $(srcdir)/Modules/unicodename_db.h MODULE_UNICODEDATA_DEPS=$(srcdir)/Modules/unicodedata_db.h $(srcdir)/Modules/unicodename_db.h
MODULE__BLAKE2_DEPS=$(srcdir)/Modules/_blake2/impl/blake2-config.h $(srcdir)/Modules/_blake2/impl/blake2-impl.h $(srcdir)/Modules/_blake2/impl/blake2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2b-ref.c $(srcdir)/Modules/_blake2/impl/blake2b-round.h $(srcdir)/Modules/_blake2/impl/blake2b.c $(srcdir)/Modules/_blake2/impl/blake2s-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2s-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2s-load-xop.h $(srcdir)/Modules/_blake2/impl/blake2s-ref.c $(srcdir)/Modules/_blake2/impl/blake2s-round.h $(srcdir)/Modules/_blake2/impl/blake2s.c $(srcdir)/Modules/_blake2/blake2module.h $(srcdir)/Modules/hashlib.h MODULE__BLAKE2_DEPS=$(srcdir)/Modules/_blake2/impl/blake2-config.h $(srcdir)/Modules/_blake2/impl/blake2-impl.h $(srcdir)/Modules/_blake2/impl/blake2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2b-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2b-ref.c $(srcdir)/Modules/_blake2/impl/blake2b-round.h $(srcdir)/Modules/_blake2/impl/blake2b.c $(srcdir)/Modules/_blake2/impl/blake2s-load-sse2.h $(srcdir)/Modules/_blake2/impl/blake2s-load-sse41.h $(srcdir)/Modules/_blake2/impl/blake2s-load-xop.h $(srcdir)/Modules/_blake2/impl/blake2s-ref.c $(srcdir)/Modules/_blake2/impl/blake2s-round.h $(srcdir)/Modules/_blake2/impl/blake2s.c $(srcdir)/Modules/_blake2/blake2module.h $(srcdir)/Modules/hashlib.h
MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h MODULE__CTYPES_DEPS=$(srcdir)/Modules/_ctypes/ctypes.h $(srcdir)/Modules/_complex.h
MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h MODULE__CTYPES_TEST_DEPS=$(srcdir)/Modules/_ctypes/_ctypes_test_generated.c.h
MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@ MODULE__CTYPES_MALLOC_CLOSURE=@MODULE__CTYPES_MALLOC_CLOSURE@
MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@ MODULE__DECIMAL_DEPS=$(srcdir)/Modules/_decimal/docstrings.h @LIBMPDEC_INTERNAL@

View File

@ -0,0 +1,3 @@
Support :c:expr:`double complex` C type in :mod:`ctypes` via
:class:`~ctypes.c_double_complex` if compiler has C11 complex
arithmetic. Patch by Sergey B Kirpichev.

34
Modules/_complex.h Normal file
View File

@ -0,0 +1,34 @@
/* Workarounds for buggy complex number arithmetic implementations. */
#ifndef Py_HAVE_C_COMPLEX
# error "this header file should only be included if Py_HAVE_C_COMPLEX is defined"
#endif
#include <complex.h>
/* Other compilers (than clang), that claims to
implement C11 *and* define __STDC_IEC_559_COMPLEX__ - don't have
issue with CMPLX(). This is specific to glibc & clang combination:
https://sourceware.org/bugzilla/show_bug.cgi?id=26287
Here we fallback to using __builtin_complex(), available in clang
v12+. Else CMPLX implemented following C11 6.2.5p13: "Each complex type
has the same representation and alignment requirements as an array
type containing exactly two elements of the corresponding real type;
the first element is equal to the real part, and the second element
to the imaginary part, of the complex number.
*/
#if !defined(CMPLX)
# if defined(__clang__) && __has_builtin(__builtin_complex)
# define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y))
# else
static inline double complex
CMPLX(double real, double imag)
{
double complex z;
((double *)(&z))[0] = real;
((double *)(&z))[1] = imag;
return z;
}
# endif
#endif

View File

@ -1750,7 +1750,11 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
[clinic start generated code]*/ [clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g";
#else
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g"; static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";
#endif
/*[clinic input] /*[clinic input]
_ctypes.c_wchar_p.from_param as c_wchar_p_from_param _ctypes.c_wchar_p.from_param as c_wchar_p_from_param
@ -2226,7 +2230,17 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
goto error; goto error;
} }
stginfo->ffi_type_pointer = *fmt->pffi_type; if (!fmt->pffi_type->elements) {
stginfo->ffi_type_pointer = *fmt->pffi_type;
}
else {
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
stginfo->ffi_type_pointer.elements = PyMem_Malloc(2 * sizeof(ffi_type));
memcpy(stginfo->ffi_type_pointer.elements,
fmt->pffi_type->elements, 2 * sizeof(ffi_type));
}
stginfo->align = fmt->pffi_type->alignment; stginfo->align = fmt->pffi_type->alignment;
stginfo->length = 0; stginfo->length = 0;
stginfo->size = fmt->pffi_type->size; stginfo->size = fmt->pffi_type->size;

View File

@ -13,6 +13,12 @@
#include <Python.h> #include <Python.h>
#include <ffi.h> // FFI_TARGET_HAS_COMPLEX_TYPE
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
# include "../_complex.h" // csqrt()
# undef I // for _ctypes_test_generated.c.h
#endif
#include <stdio.h> // printf() #include <stdio.h> // printf()
#include <stdlib.h> // qsort() #include <stdlib.h> // qsort()
#include <string.h> // memset() #include <string.h> // memset()
@ -443,6 +449,13 @@ EXPORT(double) my_sqrt(double a)
return sqrt(a); return sqrt(a);
} }
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
EXPORT(double complex) my_csqrt(double complex a)
{
return csqrt(a);
}
#endif
EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*))
{ {
qsort(base, num, width, compare); qsort(base, num, width, compare);

View File

@ -105,6 +105,10 @@ module _ctypes
#include "pycore_global_objects.h"// _Py_ID() #include "pycore_global_objects.h"// _Py_ID()
#include "pycore_traceback.h" // _PyTraceback_Add() #include "pycore_traceback.h" // _PyTraceback_Add()
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
#include "../_complex.h" // complex
#endif
#include "clinic/callproc.c.h" #include "clinic/callproc.c.h"
#define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem" #define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem"
@ -651,6 +655,9 @@ union result {
double d; double d;
float f; float f;
void *p; void *p;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
double complex C;
#endif
}; };
struct argument { struct argument {

View File

@ -14,6 +14,9 @@
#include <ffi.h> #include <ffi.h>
#include "ctypes.h" #include "ctypes.h"
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
# include "../_complex.h" // complex
#endif
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem" #define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
@ -1087,6 +1090,30 @@ d_get(void *ptr, Py_ssize_t size)
return PyFloat_FromDouble(val); return PyFloat_FromDouble(val);
} }
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
static PyObject *
C_set(void *ptr, PyObject *value, Py_ssize_t size)
{
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
double complex x = CMPLX(c.real, c.imag);
memcpy(ptr, &x, sizeof(x));
_RET(value);
}
static PyObject *
C_get(void *ptr, Py_ssize_t size)
{
double complex x;
memcpy(&x, ptr, sizeof(x));
return PyComplex_FromDoubles(creal(x), cimag(x));
}
#endif
static PyObject * static PyObject *
d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) d_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{ {
@ -1592,6 +1619,9 @@ static struct fielddesc formattable[] = {
{ 'B', B_set, B_get, NULL}, { 'B', B_set, B_get, NULL},
{ 'c', c_set, c_get, NULL}, { 'c', c_set, c_get, NULL},
{ 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw},
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
{ 'C', C_set, C_get, NULL},
#endif
{ 'g', g_set, g_get, NULL}, { 'g', g_set, g_get, NULL},
{ 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw},
{ 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw},
@ -1642,6 +1672,9 @@ _ctypes_init_fielddesc(void)
case 'B': fd->pffi_type = &ffi_type_uchar; break; case 'B': fd->pffi_type = &ffi_type_uchar; break;
case 'c': fd->pffi_type = &ffi_type_schar; break; case 'c': fd->pffi_type = &ffi_type_schar; break;
case 'd': fd->pffi_type = &ffi_type_double; break; case 'd': fd->pffi_type = &ffi_type_double; break;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
case 'C': fd->pffi_type = &ffi_type_complex_double; break;
#endif
case 'g': fd->pffi_type = &ffi_type_longdouble; break; case 'g': fd->pffi_type = &ffi_type_longdouble; break;
case 'f': fd->pffi_type = &ffi_type_float; break; case 'f': fd->pffi_type = &ffi_type_float; break;
case 'h': fd->pffi_type = &ffi_type_sshort; break; case 'h': fd->pffi_type = &ffi_type_sshort; break;

View File

@ -2,9 +2,15 @@
# include <alloca.h> # include <alloca.h>
#endif #endif
#include <ffi.h> // FFI_TARGET_HAS_COMPLEX_TYPE
#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "pycore_typeobject.h" // _PyType_GetModuleState()
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
# include "../_complex.h" // complex
#endif
#ifndef MS_WIN32 #ifndef MS_WIN32
#define max(a, b) ((a) > (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
@ -393,6 +399,9 @@ struct tagPyCArgObject {
double d; double d;
float f; float f;
void *p; void *p;
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
double complex C;
#endif
} value; } value;
PyObject *obj; PyObject *obj;
Py_ssize_t size; /* for the 'V' tag */ Py_ssize_t size; /* for the 'V' tag */

View File

@ -87,6 +87,7 @@
<ImportGroup Label="PropertySheets"> <ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="pyproject.props" /> <Import Project="pyproject.props" />
<Import Project="libffi.props" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup> <PropertyGroup>

View File

@ -72,6 +72,7 @@ _KEYWORD = textwrap.dedent(r'''
long | long |
float | float |
double | double |
_Complex |
void | void |
struct | struct |
@ -121,6 +122,16 @@ SIMPLE_TYPE = textwrap.dedent(rf'''
| |
(?: signed | unsigned ) # implies int (?: signed | unsigned ) # implies int
| |
(?:
(?: (?: float | double | long\s+double ) \s+ )?
_Complex
)
|
(?:
_Complex
(?: \s+ (?: float | double | long\s+double ) )?
)
|
(?: (?:
(?: (?: signed | unsigned ) \s+ )? (?: (?: signed | unsigned ) \s+ )?
(?: (?: long | short ) \s+ )? (?: (?: long | short ) \s+ )?

49
configure generated vendored
View File

@ -13999,6 +13999,51 @@ printf "%s\n" "$AIX_BUILDDATE" >&6; }
*) ;; *) ;;
esac esac
# check for _Complex C type
#
# Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost
# none properly support C11+ Annex G (where pure imaginary types
# represented by _Imaginary are mandatory). This is a bug (see e.g.
# llvm/llvm-project#60269), so we don't rely on presence
# of __STDC_IEC_559_COMPLEX__.
if test "$cross_compiling" = yes
then :
ac_cv_c_complex_supported=no
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <complex.h>
#define test(type, out) \
{ \
type complex z = 1 + 2*I; z = z*z; \
(out) = (out) || creal(z) != -3 || cimag(z) != 4; \
}
int main(void)
{
int res = 0;
test(float, res);
test(double, res);
test(long double, res);
return res;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"
then :
ac_cv_c_complex_supported=yes
else $as_nop
ac_cv_c_complex_supported=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test "$ac_cv_c_complex_supported" = "yes"; then
printf "%s\n" "#define Py_HAVE_C_COMPLEX 1" >>confdefs.h
fi
# check for systems that require aligned memory access # check for systems that require aligned memory access
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking aligned memory access is required" >&5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking aligned memory access is required" >&5
printf %s "checking aligned memory access is required... " >&6; } printf %s "checking aligned memory access is required... " >&6; }
@ -31487,8 +31532,8 @@ fi
if test "x$py_cv_module__ctypes_test" = xyes if test "x$py_cv_module__ctypes_test" = xyes
then : then :
as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_CFLAGS=$LIBFFI_CFLAGS$as_nl"
as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBM$as_nl" as_fn_append MODULE_BLOCK "MODULE__CTYPES_TEST_LDFLAGS=$LIBFFI_LIBS $LIBM$as_nl"
fi fi
if test "$py_cv_module__ctypes_test" = yes; then if test "$py_cv_module__ctypes_test" = yes; then

View File

@ -3826,6 +3826,35 @@ dnl The AIX_BUILDDATE is obtained from the kernel fileset - bos.mp64
*) ;; *) ;;
esac esac
# check for _Complex C type
#
# Note that despite most compilers define __STDC_IEC_559_COMPLEX__ - almost
# none properly support C11+ Annex G (where pure imaginary types
# represented by _Imaginary are mandatory). This is a bug (see e.g.
# llvm/llvm-project#60269), so we don't rely on presence
# of __STDC_IEC_559_COMPLEX__.
AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <complex.h>
#define test(type, out) \
{ \
type complex z = 1 + 2*I; z = z*z; \
(out) = (out) || creal(z) != -3 || cimag(z) != 4; \
}
int main(void)
{
int res = 0;
test(float, res);
test(double, res);
test(long double, res);
return res;
}]])], [ac_cv_c_complex_supported=yes],
[ac_cv_c_complex_supported=no],
[ac_cv_c_complex_supported=no])
if test "$ac_cv_c_complex_supported" = "yes"; then
AC_DEFINE([Py_HAVE_C_COMPLEX], [1],
[Defined if _Complex C type is available.])
fi
# check for systems that require aligned memory access # check for systems that require aligned memory access
AC_CACHE_CHECK([aligned memory access is required], [ac_cv_aligned_required], AC_CACHE_CHECK([aligned memory access is required], [ac_cv_aligned_required],
[AC_RUN_IFELSE([AC_LANG_SOURCE([[ [AC_RUN_IFELSE([AC_LANG_SOURCE([[
@ -7811,7 +7840,7 @@ PY_STDLIB_MOD([xxsubtype], [test "$TEST_MODULES" = yes])
PY_STDLIB_MOD([_xxtestfuzz], [test "$TEST_MODULES" = yes]) PY_STDLIB_MOD([_xxtestfuzz], [test "$TEST_MODULES" = yes])
PY_STDLIB_MOD([_ctypes_test], PY_STDLIB_MOD([_ctypes_test],
[test "$TEST_MODULES" = yes], [test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes], [test "$TEST_MODULES" = yes], [test "$have_libffi" = yes -a "$ac_cv_func_dlopen" = yes],
[], [$LIBM]) [$LIBFFI_CFLAGS], [$LIBFFI_LIBS $LIBM])
dnl Limited API template modules. dnl Limited API template modules.
dnl Emscripten does not support shared libraries yet. dnl Emscripten does not support shared libraries yet.

View File

@ -1686,6 +1686,9 @@
SipHash13: 3, externally defined: 0 */ SipHash13: 3, externally defined: 0 */
#undef Py_HASH_ALGORITHM #undef Py_HASH_ALGORITHM
/* Defined if _Complex C type is available. */
#undef Py_HAVE_C_COMPLEX
/* Define if year with century should be normalized for strftime. */ /* Define if year with century should be normalized for strftime. */
#undef Py_NORMALIZE_CENTURY #undef Py_NORMALIZE_CENTURY