Passing values from C++ to embedded python.
Justin Dubs
jtdubs at eos.ncsu.edu
Sat Aug 17 21:40:10 EDT 2002
"Justin Dubs" <jtdubs at eos.ncsu.edu> wrote in message
news:HWzJ8.43861$6v2.1791415 at twister.southeast.rr.com...
> "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
>
>
Nevermind, that was easy. dlopen(), dlsym(), dlclose(), dlerror(), -ldl.
No problem.
Thanks again,
Justin
More information about the Python-list
mailing list