Exposing a C++ class via CFFI

513 views
Skip to first unread message

san...@nyu.edu

unread,
Mar 14, 2018, 5:11:49 PM3/14/18
to python-cffi
Hey everyone, I know this might sound odd but I'm trying to expose certain functionality from a source code which has mixed C and C++ (unfortunately). I need to initialize a class and I'm planning to do that via a void function call which takes in certain parameters. Here is roughly what I am expecting to send into the "set_sources" command


// source.cpp
ComplexClass myclass;

void init(args) {
  ...init myclass here
}

void operate(args) {
  ...operate on class
}

// source.h
void init(args);
void operate(args);

And these two functions will be exposed into the lib object in Python. Currently, my setup without the class works and I really need this class to be a global variable so that I can reuse the C/C++ code to initialize and operate on this class.

Is this the right way to go? Could somebody suggest other ways possible to wrap C++ code in C so that I can somehow proxy and expose via CFFI? 

If this is impossible, are there other options I have?

Armin Rigo

unread,
Mar 15, 2018, 1:23:18 AM3/15/18
to pytho...@googlegroups.com
Hi,

On 14 March 2018 at 22:11, <san...@nyu.edu> wrote:
> And these two functions will be exposed into the lib object in Python.
> Currently, my setup without the class works and I really need this class to
> be a global variable so that I can reuse the C/C++ code to initialize and
> operate on this class.
>
> Is this the right way to go? Could somebody suggest other ways possible to
> wrap C++ code in C so that I can somehow proxy and expose via CFFI?

Yes, that's the way to do it: by exposing a C API from set_source().
Something like:

ffibuilder.set_source("mymodule", r'''
extern "C" {
int somefunc(int somearg) { return real_cpp_func(somearg); }
}
''', source_extension='.cpp')

The ``source_extension`` keyword makes sure the C compiler treats it
as C++. The ``extern "C"`` bit in the C++ code makes sure that the
function name is not mangled in the compiled module.

If storing things as globals works fine in your use case, then that's
it, but if you need really to be able to pass around pointers to C++
instances to Python, you can cast them to ``void *``. Or, write
``struct my_class_in_c;`` in the ``.h`` part, i.e. declare a
completely opaque struct type, and cast back and forth to ``struct
my_class_in_c *``.


A bientôt,

Armin.

Armin Rigo

unread,
Mar 15, 2018, 1:26:12 AM3/15/18
to pytho...@googlegroups.com
On 15 March 2018 at 06:22, Armin Rigo <armin...@gmail.com> wrote:
> ``struct my_class_in_c;`` in the ``.h`` part, i.e. declare a
> completely opaque struct type, and cast back and forth to ``struct
> my_class_in_c *``.

...in fact you may not need any cast in C, just manipulate ``Class *``
values. On the Python side you would then say

ffibuilder.cdef("""typedef struct _Class Class;""")

to declare the type as an opaque structure.


A bientôt,

Armin.
Reply all
Reply to author
Forward
0 new messages