Complex number support using msvc
chris-hld opened this issue · 11 comments
In API mode, compiling on github actions, using _Complex
works perfectly for Linux and macOS latest.
However, on windows-latest, I am not sure how to use the interface type complex.
I am aware that msvc doesn't support float _Complex
, but defines its own _Fcomplex
.
https://learn.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support?view=msvc-170
This is, however, not supported by cffi as it seems, since trying
if sys.platform != "win32":
ffibuilder.cdef("""
typedef float _Complex float_complex;
typedef double _Complex double_complex;
""")
else:
ffibuilder.cdef("""
typedef _Fcomplex float_complex;
typedef _Dcomplex double_complex;
""")
fails with
cffi.CDefError: cannot parse "typedef _Fcomplex float_complex;"
<cdef source string>:3:23: before: float_complex
Error: Process completed with exit code 1.
If I don't use _Fcomplex
, only using float _Complex
throughout the project, then msvc fails with the typical
build\temp.win-amd64-cpython-310\Release\_safpy.c(727): error C2143: syntax error: missing ')' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(727): error C2143: syntax error: missing '{' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(727): error C2059: syntax error: 'type'
build\temp.win-amd64-cpython-310\Release\_safpy.c(727): error C2059: syntax error: ')'
build\temp.win-amd64-cpython-310\Release\_safpy.c(736): error C2143: syntax error: missing ';' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(761): error C2146: syntax error: missing ')' before identifier '_Complex'
build\temp.win-amd64-cpython-310\Release\_safpy.c(761): error C2059: syntax error: ')'
build\temp.win-amd64-cpython-310\Release\_safpy.c(761): error C2100: illegal indirection
build\temp.win-amd64-cpython-310\Release\_safpy.c(761): error C2100: illegal indirection
build\temp.win-amd64-cpython-310\Release\_safpy.c(761): error C2297: '*': not valid as right operand has type 'void *'
build\temp.win-amd64-cpython-310\Release\_safpy.c(782): warning C4133: 'function': incompatible types - from 'int ***' to 'float_complex ***'
build\temp.win-amd64-cpython-310\Release\_safpy.c(795): error C2143: syntax error: missing ')' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(795): error C2143: syntax error: missing '{' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(795): error C2040: 'x1': 'int *' differs in levels of indirection from 'int ***'
build\temp.win-amd64-cpython-310\Release\_safpy.c(795): error C2059: syntax error: 'type'
build\temp.win-amd64-cpython-310\Release\_safpy.c(795): error C2059: syntax error: ')'
build\temp.win-amd64-cpython-310\Release\_safpy.c(804): error C2143: syntax error: missing ';' before '*'
build\temp.win-amd64-cpython-310\Release\_safpy.c(829): error C2146: syntax error: missing ')' before identifier '_Complex'
build\temp.win-amd64-cpython-310\Release\_safpy.c(829): error C2059: syntax error: ')'
build\temp.win-amd64-cpython-310\Release\_safpy.c(829): error C2297: '*': not valid as right operand has type 'void *'
build\temp.win-amd64-cpython-310\Release\_safpy.c(850): warning C4047: 'function': 'float_complex *' differs in levels of indirection from 'int ***'
build\temp.win-amd64-cpython-310\Release\_safpy.c(850): warning C4024: 'afSTFT_backward_flat': different types for formal and actual parameter 2
and so on.
Since the documentation mentions complex number support, is there any advice on how to use them with msvc/ cffi on windows?
Thanks!
Possibly related:
cython/cython#5512
Can we see a complete example for the 2nd case? I think it should work (or at least not fail like that) if you use typedef float _Complex float_complex;
in the cdef(), but not in the C sources, where you'd presumably include typedef _Fcomplex float_complex;
instead. Not saying it's the cleanest and most well-designed approach...
...ah no, I managed to write a failing example. Yes, indeed the C code generated by cffi uses float _Complex
directly and that doesn't compile on MSVC.
This workaround might work for you:
import cffi
ffibuilder = cffi.FFI()
ffibuilder.cdef("""
typedef struct { ...; } _Fcomplex;
typedef struct { ...; } _Dcomplex;
typedef _Fcomplex float_complex;
typedef _Dcomplex double_complex;
int my_function(float_complex);
""")
ffibuilder.set_source("_wincomplex_cffi", """
#include <complex.h>
typedef _Fcomplex float_complex;
typedef _Dcomplex double_complex;
int my_function(float_complex x) { return 42; }
""")
ffibuilder.compile()
Please tell me if it fully works for you. If it does, I could make the first two lines of the cdef() be automatically added on Windows.
...but you can't pass Python complex numbers as arguments to my_function()
in this version. CFFI doesn't know that _Fcomplex
is supposed to be a complex number. So it's likely not enough.
I've made pull request #57 that should implement the necessary bits and pieces. If you can test it for your use case, it would be appreciated!
Great!
I ended up with a somewhat similar workaround:
if sys.platform != "win32":
ffibuilder.cdef("""
typedef float _Complex float_complex;
typedef double _Complex double_complex;
""")
else:
ffibuilder.cdef("""
typedef struct
{
float _Val[2];
} float_complex;
""")
I found this was how (at least the current) msvc implementation looked.
I'll give the PR a test, thanks!
With #57, no further workarounds required, this works as expected:
if sys.platform != "win32":
ffibuilder.cdef("""
typedef float _Complex float_complex;
typedef double _Complex double_complex;
""")
else:
ffibuilder.cdef("""
typedef _Fcomplex float_complex;
typedef _Dcomplex double_complex;
""")
While looking at the PR I just realized that
ffibuilder.cdef("""
typedef float _Complex float_complex;
typedef double _Complex double_complex;
""")
Works on MSVC now too! (I am assuming it comes from src/cffi/commontypes.py?)
Yes: float _Complex
works everywhere in the cdef() or the usages of the type at runtime, like in ffi.new("float _Complex[]", array_length)
. It always did; the PR mostly just adds the type _Fcomplex
as a synonym, and when CFFI generates C code it writes _cffi_float_complex_t
instead, and there are some #define
s. It would be more work to prevent float _Complex
from working there, and there is little point.
I still need to update the docs in the PR.
Great, thanks!
(Closing as solved with PR, workarounds shown here.)