Example program of Cython as Python to C Converter

前端 未结 1 1891
南旧
南旧 2020-12-31 07:40

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.py

相关标签:
1条回答
  • 2020-12-31 08:20

    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.hin 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;
    }
    
    0 讨论(0)
提交回复
热议问题