I'm trying to call cython (cdef) function in C program. When the cdef function contains python statements, e.g. print(0.5), or python (def) functions, calling the (cdef) function raises a segmentation fault.
The .pyx file:
# cython: language_level=3
cdef public double PI = 3.1415926
cdef public double get_e():
print("calling get_e()")
return 2.718281828
The .c file:
#include "Python.h"
#include "transcendentals.h"
#include <math.h>
#include <stdio.h>
int main(int argc, char **argv) {
Py_Initialize();
PyInit_transcendentals();
printf("pi**e: %f\n", pow(PI, get_e()));
Py_Finalize();
return 0;
}
The compiling commands:
cython transcendentals.pyx
gcc -I. -I/usr/include/python3.5m -I/usr/include/python3.5m \
-Wno-unused-result -Wsign-compare \
-g -fstack-protector-strong -Wformat \
-Werror=format-security -DNDEBUG -g \
-fwrapv -O3 -Wall -Wstrict-prototypes \
-L/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu \
-L/usr/lib transcendentals.c main.c \
-lpython3.5m -lpthread -ldl -lutil -lm -Xlinker \
-export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions
When I remove the print statement of get_e function, no segmentation fault would be raised. But the value of PI will be 0.
I guess you are using Cython 0.29. Since 0.29, PEP-489 multi-phase module initialisation has been enabled for Python versions >=3.5. This means, using
PyInit_XXX
is no longer sufficient, as you are experiencing.Cython's documentation suggest to use inittab mechanism, i.e. your
main
-function should look something like:Another possibility to restore the old behavior would be to define macro
CYTHON_PEP489_MULTI_PHASE_INIT=0
and thus overriding the default by e.g. passing-DCYTHON_PEP489_MULTI_PHASE_INIT=0
to gcc on the command line.This seems like a bug (or at least an issue with Python3.7).
I tested your example on my Arch Linux with Python3.7.
First thing which made me curious was how long the compilation took on this step:
I have a not so bad computer but it took it a couple of minutes to get this compilation done. Strange.
And upon running
./a.out
, I also got a segmentation error, like you.So, then I decided to test (with one minor modification: change
PyInit_transcendentals
toinittranscendentals
inmain
) with Python2.7, as shown below:The compilation was instant.
I ran
./a.out
and the output was:Then just to be sure, that this had nothing to do with any flags that you might be using, nor that the math library nor something else would be having an effect here, I repeated the test with a very simple "hello world" example as shown below.
Then,
The output was,
On the other hand, recompling with Python3.7 (after changing
inithello
toPyInit_hello
) gave the following output: