I'm having an issue with a rather intricate interaction of C++ and Python that I'm hoping the community can help me with. If my explanation doesn't make sense, let me know in the comments and I'll try to clarify.
Our C++ code base contains a parent classes called "IODevice" which is a parent to other classes such as "File" and "Socket" and so forth. We've done this so that in much of our code we can work generically with "IODevice" objects that might actually be files or sockets or whatever we originally constructed. This all works fine within the C++ code.
We've started to build Python bindings for some of our objects. We didn't want to modify the original "File" or "Socket" classes; we created "FilePy" and "SocketPy" subclasses of the "File" and "Socket" classes. These *Py classes contain the necessary Python binding code.
Here's where the problem starts. Let's say I have a "InputProcessorPy" C++ class that has the appropriate Python bindings. I would want to be able to construct it in my Python code and pass it a "FilePy" or "SocketPy" object that the "InputProcessorPy" is going to pull data from. The Python binding code from "InputProcessorPy" looks like this:
PyObject* InputProcessor::PyMake(PyObject* ignored, PyObject *args)
{
PyObject* cD_py;
IODevice* inputFile;
if (!PyArg_ParseTuple(args, "O", &cD_py))
return NULL;
inputFile = (IODevice*) cD_py;
inputFile->isReadable();
printf("------>>>> Done\n");
return (PyObject *) new CL_InputRenderer(*inputFile, InputProcessor::Type);
}
If I run this code, I get a segmentation error when I call the isReadable() method of inputFile, which is actually a method of the IODevice base class.
If instead I do this:
...
FilePy* inputFile;
...
inputFile = (FilePy*) cD_py;
inputFile->isReadable();
...
The code works fine in this case. This, however, is undesirable, as it assumes we are passing in a "FilePy" object, which will not be the case; it might be a "SocketPy" or "BufferPy" or "StringPy" or any other sort of "IODevice" subclass.
It seems as if the Python binding process is somehow not compatible with the C++ class inheritance structure that we're trying to use. Has anyone tried to solve an issue like this before? Are we doing our C++ inheritance wrong, or should we be doing something different in our Python bindings to make this work?
Are your types FilePy and IODevice derived from PyObject? Otherwise, the C++ compiler will interpret:
inputFile = (IODevice*) cD_py;
as:
inputFile = reinterpret_cast<IODevice*> (cD_py);
rather than what you expected:
inputFile = dynamic_cast<IODevice*> (cD_py);
If the actual type passed is not PyObject, or IODevice is not related to PyObject via inheritance, there is no way for the C++ compiler or runtime to know how to find the proper vtable.
Related
---Context---
I want to have a class called "fileProcessor". This class is completely static and merely serves as a convinient namespace (within my normal library namespace) for some global function. This is a basic blueprint of the class with only the relevant stuff
class fileProcessor{
private:
lua_State* LUA_state;
public:
static std::variant<type1,type2> processFile(const char* filePath,const char* processorScript);
}
Please note again that I ommitted most of the stuff from the class so if anything seems odd ignore it.
What process file is supposed to do is:
Read the filePath file, storing all directives including it (this is my own filetype or style of syntax. This is already handeled correctly). The directives are stored with strings, one for the command and one for everything after it.
Read the script file and check if it has a commented out fileProcessor line at the top. This is to make sure that the lua script loaded is relevant and not some random behaviour script
Load and compile the lua script.
Make all read directives available (they are saved in a struct of 2 strings as mentioned before)
Run the file and recieve a object back. The object should only be of types that I listed in the return type (variant)
I am having problems with step 4 and one vital part of the scripting.
---Question---
How can I make the creation of a full new object of type1 or type2 possible within lua, write to it from within lua and then get it back from the lua stack into c++ and still know if its type1 or type2?
---No example provided since this question is more general and the only reason I provided my class is for context.---
It seems like you are trying to do it the other way around. I quote a part of this answer:
...you are expecting Lua to be the primary language, and C++ to be the client. The problem is, that the Lua C interface is not designed to work like that, Lua is meant to be the client, and all the hard work is meant to be written in C so that Lua can call it effortlessly.
If you are convinced there is no other way that doing it other way around you can follow the workaround that answer has given. Otherwise I think you can achieve what you need by using LUA as it meant to be.
LUA has 8 basic types (nil, boolean, number, string, userdata, function, thread, and table). But you can add new types as you require by creating a class as the new type in native C++ and registering it with LUA.
You can register by either:
Using some LUA helper for C++ like luna.h (as shown in this tutorial).
Pushing a new lua table with the C++ class (check this answer).
Class object instance is created in your native C++ code and passed to LUA. LUA then makes use of the methods given by the class interface.
I have a C++ project that use a lot of classes. The main one is 'sso::Object' (every classes are in the 'sso' namespace) and this class is derived into some other classes but one which is abstract: 'sso::Drawable'.
This class has two pure virtual methods 'sso::Drawable::set_opacity' and 'sso::Drawable::raw_draw' and it is derived into other classes like 'sso::View' which implement these two methods.
The whole project works fine when it is used in C++, but I would like to use it in Python too, so I created a Boost.Python module like that:
class DrawableWrapper : public sso::Drawable , public wrapper<sso::Drawable> {
public:
void set_opacity(byte opacity) { this->get_override("set_opacity")(opacity); }
void raw_draw(const sso::Rect &rect,sso::Target &target,const sso::Position &position) const {
this->get_override("raw_draw")(rect,target,position);
}
};
BOOST_PYTHON_MODULE(sso) {
class_<DrawableWrapper,boost::noncopyable> ("Drawable",init<>())
.add_property ("opacity",&sso::Drawable::get_opacity)
// python_sso_getter & python_sso_setter_* are only used for an easier access to accessors
.add_property ("position",python_sso_getter<sso::Drawable,sso::Position,&sso::Drawable::get_position>,python_sso_setter_1_const<sso::Drawable,sso::Position,&sso::Drawable::set_position>)
.def("raw_draw",pure_virtual(&sso::Drawable::raw_draw))
;
class_<sso::View,bases<sso::Drawable> > ("View",init<>())
.def("insert",python_sso_setter_1<sso::View,sso::Drawable*,&sso::View::insert>)
.def("remove",&sso::View::erase)
;
}
This code compile without errors but when I execute these lines in Python:
myview = sso.View()
print myview
I get this output:
<sso.View object at 0x7f9d2681a4b0>
But my C++ debugger tell me that the variable 'v' (the python 'myview') is a 'sso::Object' instance, not a 'sso::View' one. sso::View::View() is called but the variable type is not a view and I don't know why. Do you have any idea about that ? Did you do something like that and found a way to make it work ?
I use Python2.7 and Boost.Python1.49 and gcc version 4.6.1
EDIT: I've made a mistake: sso::Drawable does not inherit from sso::Object, but sso::View does (=multiple inheritance).
The output <sso.View object at 0x7f9d2681a4b0> from python is just python telling you what it thinks the object type is called, it has nothing to do with the actual type of object created at the C++ level.
As you've told boost python to expose the object as sso.View then that is what python will see it as. If you were to change your code to expose std::string as sso.View then python would still report <sso.View object at 0x7f9d2681a4b0> after you've created it.
Similarly, if you were to change "View" in your C++ to "BlahDeBlah" then python would report the object as <sso.BlahDeBlah object at 0x7f9d2681a4b0> (of course you'd also have to create it via sso.BlahDeBlah()
That aside, I can't see anything wrong with the code you have posted. Does sso::View inherit from sso::Object? If that's the case, and you've witnessed sso::view::View() being called, then I think you might just be misinterpreting the debugger when it tells you the object is of type sso::Object. Perhaps it has a pointer to the base class or something similar at the point you are debugging?
What happens when you call myview.insert or myview.remove from python?
EDIT: I suspect (though I could be wrong) that you might not have RTTI turned on in your compiler, so typeid() is just returning the type that implemented the function you are in when you called typeid(). That would certainly explain why you get sso::View when in insert but a different answer in other functions.
Anyway, I've been looking into the documentation a little bit more and I think your problem is actually that you've provided the ability to override the raw_draw method but you haven't actually overridden it with anything.
If you have a look at the decleration of the pure_virtual boost::python function at the bottom of this file you'll see a comment:
//
// Passed a pointer to member function, generates a def_visitor which
// creates a method that only dispatches to Python if the function has
// been overridden, either in C++ or in Python, raising a "pure
// virtual called" exception otherwise.
//
So what you're seeing is just expected behaviour. If you provide an override for raw_draw in sso::View or a python class that inherits from it then you should no longer get this error.
So, I want to be able to modify already instanced C++ objects in a scripting language. I have been looking at Lua with LuaBind and Python with SWIG or Boost::Python, but all I see is how to make new instances of the objects, but I want to modify already existing ones.
Example:
C++:
Player playerOne = new Player();
Scripting Language :
playerOne.Transform.x += 5;
Is this possible, and if so, wat would you suggest as a good Language/library to achieve this with?
In my main project we use LuaBind, and it works pretty well. We do basically what you're asking to do. We have existing C++ objects where we want behavior extended in various ways, but it would be a lot of work and risky to do those changes in behavior in the C++ code for the object itself.
So in your example, you'd want at least 2 C++ wrapper classes - one that represents the 'Game' that allows you to write an API function to return players, and a wrapper class that wraps the C++ player class that you can return to lua. Each wrapper function would have api functions/properties that would fiddle with the individual object it's wrapped internally that lua could call and pass values to. Here is a link to an article giving you pretty straightforward examples of using LuaBind and what it looks like:
http://blog.nuclex-games.com/tutorials/cxx/luabind-introduction/
I recently needed to do the same thing. I also considered (and used) Boost.Python but personally (as much as I love Boost) I felt it was a little overkill to drag in half the Boost library to get one feature.
So, if you're interested, I recently implemented a very light-weight Python wrapper library called ECS:Python. ECS:Python (Embedded C++ Scripting with Python) is designed specifically for C++ developers that wish to expose objects FROM a C++ application TO an embedded Python interpreter for interactive scripting.
Its free (BSD) and open source: http://sourceforge.net/projects/ecspython
There is no mechanism that can magic values into a scripting language from the host language. If you want a particular object instances to be accessible in the scripting language, it must be given to the scripting language via some function.
This is no different from any other properly encapsulated C++ type. If object A creates and stores some instance T, then the only way object B can get it is if it calls a function on A that returns T.
I was having the problems in my project. Have a look at my post in the Ogre3d forums:
http://www.ogre3d.org/forums/viewtopic.php?f=5&t=41631&p=332200&hilit=mrmclovin#p405204
Code example:
int main (int argc, char * const argv[])
{
try
{
// Initialize the python interpreter
Py_Initialize();
// Create a module dynamically
object module((handle<>(borrowed(PyImport_AddModule("NameOfMyModule")))));
// Retrieve the module's namespace
object main_namespace(module.attr("__dict__"));
// Put a c++ class named "Car" exported using boost.python into our module
main_namespace["Car"] = class_<Car>("Car")
.def("drive", &Car::drive)......;
// The class car now exists in a dynamic module
// and that module is accessable everywhere as longs as the python interpreter exists
// Create a instance of Car here
Car* myCar = new Car(...);
// Now simply add it to the module. Make sure you have exposed class Car before adding instances
main_namespace["car_instance"] = object(ptr(myCar)); // the boost python ptr() class make sure not to copy the pointee but only copy pointer adress
}
catch( error_already_set )
{
PyErr_Print();
}
return 0;
}
first I must say that as a Python programmer, I might be seeing this problem from a wrong perspective, many years had passed since I wrote my last c++ code back in college.
I'm having a bit of a problem, trying to create a hybrid python/c++ plugin using firebreath. I've been succesfull so far integrating all the parts using boost/python.h, but a problem arose when I tried to fire an event from within python. I stumbled with the problem of having to bind together a python function with a c++ function (using the BOOST_PYTHON_MODULE). First I tried to bind directly python with my JSAPI derived class fbtestconpythonAPI, the problem with this approach seems to be the lack of reference to the JSAPI object instantiated by the browser, giving me all kinds of signature mismatch problems between python function and c++ equivalent at execution time.
The only thing that ocurred to me to fix this( I agree, is an ugly dirty solution), is to use a global pointer which I initialize by hand with set_pluginPointer. This actually works pretty well so far, but I know it is not the right way to do it. I read that I should not be using a "raw" pointer with a JSAPI object, but I'm not sure how to replace it with a shared_ptr for this particular implementation. Another problem is the global variable, wich is shared accross all instances, causing for example, that all events are fired on the last tab/window opened. One way to solve the latter would be creating some sort of array with an index being the current window/thread id, wich is something I should be able to access from both my JSAPI object and python/c++ function.
Of course I'm open, and will apreciate very much, any suggestions, on how to improve/fix either this particular workaround or, better, the correct way to communicate boost::python and firebreath without hacking.
Below is the relevant part of the plugin code
// Global pointer to plugin instance
fbtestconpythonAPI *fbtestPtr;
void fbtestconpythonAPI::set_pluginPointer(const std::string& val){
m_testString = val;
fbtestPtr = this; //Global pointer initialization
}
void echo(std::string x){
// Firing the echo event on the plugin instance using the global raw pointer
fbtestPtr->fire_echo(x, 1);
}
BOOST_PYTHON_MODULE(Pointless) {
def("echo", echo);
}
FB::variant fbtestconpythonAPI::echo(const FB::variant& msg){
int result_value;
Py_Initialize();
try {
initPointless(); // initialize Pointless
PyRun_SimpleString("import Pointless");
PyRun_SimpleString("Pointless.echo('hello world')");
object module(handle<>(borrowed(PyImport_AddModule("__main__"))));
object dictionary = module.attr("__dict__");
} catch (error_already_set) {
PyErr_Print();
}
Py_Finalize();
return 0;
}
From a quick look you'd setup your class for export like this:
class_<YourAPI, boost::noncopyable>("YourAPI", no_init)
.def("function", &YourAPI::function);
Then you can pass a reference to your C++ instance to Python, allowing you to call functions on it which in turn can fire events.
I have a little problem with the WOsclib. Not particularly with the library, it's more the callback function. The listen to specific osc commands i have to put up some callback method like
void TheOscStartMethod::Method(
const WOscMessage *message,
const WOscTimeTag& when,
const TheNetReturnAddress* networkReturnAddress)
{
std::cout << "Got the start signal";
start.alpha = 1.0;
}
start is IBOutlet UIImageView.
But the compiler says me, that start is out of scope. If I try to access start in obj-c code, it works like it should.
How can i get my Objective C Objects into the c code or at least call a objective-c function.
Thank you
Make the file an objective C++ file with extension .mm Then you can call object C and C++ objects in the same code.
XCode will call the correct compiler from the file extension (ie adding -x objective-c++ to the compile command)
Not that C++ and objective C are different languages and do not understand each others objects so to move data between them you will need to convert the data to a C type e.g. void, char int and pointers to them.
It sounds like start is an instance variable belonging to some Objective-C object and you're trying to access it just by writing its name from a C++ object. If this is the case, it should be pretty obvious why it won't work: The C++ object doesn't know anything about start. The solution is to somehow give the C++ object a reference to the Objective-C object that owns start.
You'll have to make the start object available to your other code.
You can pass it, you can pass the portions you'll be using, you can create an API for the two code bases to use. There are other options as well, all depending on precisely how you wish to use the various objects
The Solution:
I don't know if this is the best way to do it, but it works.
There must be an empty c object, which later will become our objective c object that holds all the stuff we want to access.
static gsSearchForIp* delegate = NULL;
We must define a function to set the objective c object
void setCallbackDelegate(gsSearchForIp* del)
{
delegate = del;
}
And then call it. ( I called it in the initWithFrame method)
setCallbackDelegate(self);
Now i can call a method with [delegate methodName:firstPara] in my c++ method. In this function i have access to all my stuff that I need from the gsSearchForIp class.