Quantcast

[C++-sig] How to implement a cross-module C-API

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[C++-sig] How to implement a cross-module C-API

Thomas Schipolowski
Hello,

I have a working C++ extension module for python that has been exported
with boost::python. Now I am trying to embed the python interpreter in a
plain C program and make it execute a script which will import my C++
module and do some calculations with it. The results will end up in a
C++ object created by the extension module. In the enveloping C program,
I would be able to retrieve a PyObject* reference to the Python wrapper
of this result object from the interpreter global namespace after the
script finished. But is there a way to get fast C-level access to the
underlying C++ object?

I read the extending/embedding part of the standard python docu and
tried to think up a possible solution. As it seems to be a bit involved,
can please somebody tell me if I am on the right way, or what I could do
better?

 

My idea so far:

I would add some free functions to my C++ module that offer a minimal
C-API for some of the classes defined there. These functions would
accept a PyObject* reference as argument. Internally, they would
construct a boost::python::object from the PyObject* and try to extract
the expected C++ object type from it. Once I have the C++ object back, I
could call its methods to perform the desired operations. All results
would be returned as plain C structs or arrays.

In order to get access to the API functions in my C program, I would
package them in a static table of function pointers, place a void* ptr
to the table in a Python CObject, and make the CObject visible to my C
program by exporting a function (to python) that delivers the CObject on
request.

Can this work? The fact that there is a "extern C" declaration for using
C functions in C++ makes me wonder if it is possible/safe to access a
function compiled with C++ from a program compiled with a C compiler?

 

Thanks in advance,

Thomas.


_______________________________________________
C++-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/c++-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [C++-sig] How to implement a cross-module C-API

Stefan Seefeld
Thomas Schipolowski wrote:

> I would add some free functions to my C++ module that offer a minimal
> C-API for some of the classes defined there. These functions would
> accept a PyObject* reference as argument. Internally, they would
> construct a boost::python::object from the PyObject* and try to extract
> the expected C++ object type from it. Once I have the C++ object back, I
> could call its methods to perform the desired operations. All results
> would be returned as plain C structs or arrays.
>
> In order to get access to the API functions in my C program, I would
> package them in a static table of function pointers, place a void* ptr
> to the table in a Python CObject, and make the CObject visible to my C
> program by exporting a function (to python) that delivers the CObject on
> request.

That sounds plausible. You are essentially generating your own vtbls
in C that act as C wrappers around the C++ core. I'm not quite
sure I would embedd these vtbls into the objects you are wrapping, as that
is a bit invasive. Instead, you may create a dictionary that maps python
type objects to the structures holding your vtbl and provide a simple
lookup mechanism that queries the PyTypeObject pointer from a given python
object and look up the C vtbl with that.

> Can this work? The fact that there is a "extern C" declaration for using
> C functions in C++ makes me wonder if it is possible/safe to access a
> function compiled with C++ from a program compiled with a C compiler?

Yes, this should work.

Regards,
                Stefan

_______________________________________________
C++-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/c++-sig
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [C++-sig] How to implement a cross-module C-API

Thomas Schipolowski
Hello Stefan,

thank you for the quick response.

I'm not quite
sure I would embedd these vtbls into the objects you are wrapping, as that
is a bit invasive. 
Uhm, I am not sure if this is what I meant to do. I intended to take the route suggested by the std. Python extending tutorial: http://docs.python.org/ext/using-cobjects.html So I want to put the whole table of API function ptrs in just one of these Python-API CObjects, to get the addresses across the C++/Python/C borders. This would leave the C++ objects which I intend to access with my API untouched. They would even be oblivious to the existence of the C-API, as the functions will only access the objects using their normal public interface.

But, yes, the CObject itself would be wrapped in order to get it out to python. I thought of something like:

static void* call_table[MY_API_PTRS];
.... put function pointers in table ...

object get_c_api() {
    return object(handle<>(PyCObject_FromVoidPtr((void*)call_table, NULL)));
}

Then I would export 'get_c_api' with the normal boost::python facilities. In the plain C part, I would call get_c_api via python, extract the void* ptr from the PyCObject* and cast it into the array of function pointers, whose prototypes are known thanks to a header file that describes the fixed layout of call_table.

Instead, you may create a dictionary that maps python
type objects to the structures holding your vtbl and provide a simple
lookup mechanism that queries the PyTypeObject pointer from a given python
object and look up the C vtbl with that.
  
Ok, this would be a nice way to associate the functions with the corresponding objects. But still I need to use PyCObject_FromVoidPtr or something equivalent to be able to put the opaque C pointers, or the ptr to the vtable, into a python dict, do I? But don't worry, I will need only one vtable with a static structure for my few API functions. So it boils down to the problem of getting a single address safely from the C++ part to the C part. Each function will check with extract<expected_class>(...).check()  to make sure it is called with the C++ object type it is intended for.

Hope it still makes sense.
Regards,
Thomas.



_______________________________________________
C++-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/c++-sig
Loading...