Passing values from C++ to embedded python.

Justin Dubs jtdubs at eos.ncsu.edu
Thu May 30 21:00:23 EDT 2002


"Mark Rowe" <bdash at gmx.net> wrote in message
news:mailman.1022734969.31865.python-list at python.org...
> Justin Dubs wrote:
>
> >Hey everyone,
> >
> >I have a C++ app in which I have embedded the python interpreter.  I have
a
> >thread which does the simple Py_Initialize(), PyRun_InteractiveLoop(),
> >Py_Finalize() business using stdin and stdout.  Meanwhile the main thread
> >does all the regular functionality of the app in another window.  I have
> >several classes, written in C++, which I have wrapped with SWIG and
compiled
> >into a shared library.  C++ can instantiate the original classes,
obviously,
> >as they are written in C++.  Python can instantiate the wrapped classes
from
> >the shared library and that also works perfectly.
> >
> >So, my problem is thus:
> >
> >If I have a pointer to an instance of one of these classes in C++, how
can I
> >create a python variable that points to the same instance?
> >
> >In other words, in pseudocode:
> >
> >In C++:
> >    MyClass *foo = new MyClass();
> >    foo->SetAnswer(42);
> >    // insert unknown code to communicate foo to python
> >
> >In Python, from my interactive interpreter running on stdin and stdout
> >within the C++ app:
> >    # insert unknown code to receive foo from c++
> >    >>> foo.getAnswer();
> >    42
> >
> >I hope you can understand what I am trying to accomplish.  I need to make
> >python aware of an instance of a variable that exists in C++.  I tried
doing
> >this some simple ways from C++ using PyCObject_* and PyInstance_* and
> >PyNew_* and other things.  But, alas, I am but a beginner with the
Python/C
> >API and I could really use some help.
> >
> >Thanks a lot everyone,
> >
> >Justin Dubs
> >
> >
> >
> >
> Hello,
>
> I had a similar problem recently.  I'm unsure if the method that I used
> to solve it is the simplest way to do so, but so far it has worked for me.
>
> The SWIG function SWIG_NewPointerObj can be used to return a PyObject *
> for your wrapped class.  If you are using SWIG shadow classes, you then
> have to create a wrapper class instance that shadows the newly created
> PyObject *.  You can then insert the PyObject * into the appropriate
> Python namespace.
>
> eg (Edited and untested):
>
> PyObject *ToConsole(Console *c);
>
>  // Insert console object to into Python namespace
> void InsertObject(Console *m_console)
> {
>         PyObject * console_s = NULL, * a3d_m = NULL, * a3d_md = NULL, *
> console_class = NULL;
>         PyObject * console = NULL, * main = NULL, * main_d = NULL, *
> arg_tuple = NULL;
>         console_s = ToConsole(m_console);
>
>         // Create Python shadow class from Python Object
>         // A3D.py is the shadow class file generated by SWIG
>         a3d_m = PyImport_ImportModule("A3D");
>         a3d_md = PyModule_GetDict(a3d_m);
>         console_class = PyDict_GetItemString(a3d_md, "ConsolePtr");
>         arg_tuple = PyTuple_New(1);
>         PyTuple_SetItem(arg_tuple, 0, console_s) ;
>         console = PyObject_CallObject(console_class, arg_tuple);
>         Py_XDECREF(arg_tuple);
>         arg_tuple = NULL;
>
>         // Insert Python shadow class into global namespace
>         main = PyImport_AddModule("__main__");
>         main_d = PyModule_GetDict(main);
>
>         PyDict_SetItemString(main_d, "console", console);
>
>         Py_XDECREF(console);
>         Py_XDECREF(a3d_m);
>         console = NULL;
>         a3d_m = NULL;
> }
>
> and in your SWIG file, create a small section like the following:
>
> %{
> extern swig_type_info _swigt__p_Console[];
> PyObject *ToConsole(Console *c)
> {
>   // _swigt__p_Console is a generated structure(?) that represents the
> C++ class
>   extern swig_type_info _swigt__p_Console[];
>   return SWIG_NewPointerObj(c, _swigt__p_Console, 0);
> }
> %}
>
> The C++ instance that you pass to InsertObject is then available in
> Python as console in the __main__ namespace.  I hope that this makes
> sense, and helps you :D
>
> Mark
>

Thanks a lot Mark,

I have a new problem now though.  :-).  our idea makes sense, I wrote the
code, I put the stuff in the SWIG interface file, and it compiled perfectly.
Woohoo.  However, I can't figure out how to link it now.

Here's what I have, simplified:

classtowrap.cpp            # the class i'm trying to wrap
classtowrap.h                # it's header file
classtowrap.i                # swig interface file
classtowrap_wrap.cxx    # generated c++ wrapper class from SWIG
classtowrap.py                # python shadow class from SWIG
classtowrapc.so                # the compiled, shared library from the
classtowrap.cpp and the classtowrap_wrap.cxx that python can import

main.cpp                        # the main driver program

So, the main.cpp is what gets the python interpreter running and needs to
send the instance into the python namespace.  It, therefore, needs to use
that method we defined in our classtowrap.i file, which was put in the
classtowrap_wrap.cxx file, which is now in the shared library
classtowrapc.so.

I can't, of course, just do a -lclasstowrapc because libraries need to start
with "lib", so I made a link from libclasstowrapc.so -> classtowrapc.so.
Now I did the compilation of main.cpp with a -lclasstowrapc at the end of
it.  Here's the error I got:

ld: libclasstowrapc.dylib is input for the dynamic link editor, is not
relocatable by the static link editor again

Mac OS X was nice enough to copy my symbolic link, this time with a .dylib
extension, as is the default for dynamically linked libraries on this OS.
However, being a dynamic library, you can't statically link it.  So, how DO
you dynamically link a library?  I've never dealt with this kind of thing
before.

Thanks again for your help,

Justin Dubs





More information about the Python-list mailing list