I found here and here that one can use Cython to convert Python to C, but I cannot find any step-by-step example. Let's say I have a simple function:
foo.pyx
cdef void foo(double* x):
x[0] = 0.0
setup.py
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("foo.pyx")
)
then I run: python setup.py build_ext --inplace to get foo.c and foo.so files (and build directory). Well, I would like to use translated (I hope) foo function in main.c. What should I put into main.c file and how to compile it in order to be able to use foo function? I am using gcc.
Far from a c expert but for me using ubuntu, the following works:
main.c:
#include "foo_api.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
Py_Initialize();
initfoo();
import_foo();
double arr[5] = {1,2,3,4,5};
int i = 0;
foo(arr);
for(i = 0; i < 5; i++)
{
printf("%f\n", arr[i]);
}
Py_Finalize();
return 0;
}
foo.pyx:
cdef public api foo(double* x):
x[0] = 0.0
From the same directory:
$ cython foo.pyx
Then:
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -o foo *.c -lpython2.7
Then just run.
$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000
I used pkg-config --cflags python
to get the flags:
$ pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7
Without calling Py_Initialize (Initialize the Python interpreter. In an application embedding Python, this should be called before using any other Python/C API functions;), you will get:
Fatal Python error: PyThreadState_Get: no current thread
Aborted (core dumped)
Without initfoo()
or import_foo()
you get a:
Segmentation fault (core dumped)
If you don't call Py_Finalize:
Py_Initialize
a no-op when called for a second time (without calling Py_Finalize() first).
To get the delorean example from the docs to run:
main.py:
#include "delorean_api.h"
#include <stdio.h>
Vehicle car;
int main(int argc, char *argv[]) {
Py_Initialize();
initdelorean();
import_delorean();
car.speed = atoi(argv[1]);
car.power = atof(argv[2]);
activate(&car);
Py_Finalize();
return 0;
}
delorean.pyx:
ctypedef public struct Vehicle:
int speed
float power
cdef api void activate(Vehicle *v):
if v.speed >= 88 and v.power >= 1.21:
print "Time travel achieved"
else:
print("Sorry Marty")
The procedure is the same, the only change was I had to use ctypedef
with the Vehicle struct or else in main or use I had t use struct Vehicle car;
in main:
$ cython delorean.pyx
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -o delorean *.c -lpython2.7
$ ./delorean 1 1
Sorry Marty
$ ./delorean 100 2
Time travel achieved
You can also get it to work without using Py_Initialize
etc...
In foo.pyx
you just need to make the function public:
cdef public foo(double* x):
x[0] = 0.0
I added #include <python2.7/Python.h>
just imported foo.h
in main.c and removed Py_Initialize();
etc. Just importing python.h
would not work for me but that may not be the case for everyone.
#include <python2.7/Python.h>
#include "foo.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
double arr[5] = {1,2,3,4,5};
int i = 0;
foo(arr);
for(i = 0; i < 5; i++)
{
printf("%f\n", arr[i]);
}
return 0;
}
Compiling was the same:
$ cython foo.pyx
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 -o foo *.c -lpython2.7
$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000
If you are using the api version then just include the api header or vice versa as per the docs However, note that you should include either modulename.h or modulename_api.h in a given C file, not both, otherwise you may get conflicting dual definitions.
To do the same with the delorean example I had to use libc.stdio
to print the strings to avoid a segmentation fault:
from libc.stdio cimport printf
ctypedef public struct Vehicle:
int speed
float power
cdef public void activate(Vehicle *v):
if v.speed >= 88 and v.power >= 1.21:
printf("Time travel achieved\n")
else:
printf("Sorry Marty\n")
main:
#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"
Vehicle car;
int main(int argc, char *argv[]) {
car.speed = atoi(argv[1]);
car.power = atof(argv[2]);
activate(&car);
return 0;
}
It might make more sense to return the values:
ctypedef public struct Vehicle:
int speed
float power
cdef public char* activate(Vehicle *v):
if v.speed >= 88 and v.power >= 1.21:
return "Time travel achieved"
return "Sorry Marty"
main:
#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"
Vehicle car;
int main(int argc, char *argv[]) {
car.speed = atoi(argv[1]);
car.power = atof(argv[2]);
printf("%s\n",activate(&car));
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With