Im toying around with the idea to use python as an embedded scripting language for a project im working on and have got most things working. However i cant seem to be able to convert a python extended object back into a native c++ pointer.
So this is my class:
class CGEGameModeBase
{
public:
virtual void FunctionCall()=0;
virtual const char* StringReturn()=0;
};
class CGEPYGameMode : public CGEGameModeBase, public boost::python::wrapper<CGEPYGameMode>
{
public:
virtual void FunctionCall()
{
if (override f = this->get_override("FunctionCall"))
f();
}
virtual const char* StringReturn()
{
if (override f = this->get_override("StringReturn"))
return f();
return "FAILED TO CALL";
}
};
Boost wrapping:
BOOST_PYTHON_MODULE(GEGameMode)
{
class_<CGEGameModeBase, boost::noncopyable>("CGEGameModeBase", no_init);
class_<CGEPYGameMode, bases<CGEGameModeBase> >("CGEPYGameMode", no_init)
.def("FunctionCall", &CGEPYGameMode::FunctionCall)
.def("StringReturn", &CGEPYGameMode::StringReturn);
}
and the python code:
import GEGameMode
def Ident():
return "Alpha"
def NewGamePlay():
return "NewAlpha"
def NewAlpha():
import GEGameMode
import GEUtil
class Alpha(GEGameMode.CGEPYGameMode):
def __init__(self):
print "Made new Alpha!"
def FunctionCall(self):
GEUtil.Msg("This is function test Alpha!")
def StringReturn(self):
return "This is return test Alpha!"
return Alpha()
Now i can call the first to functions fine by doing this:
const char* ident = extract< const char* >( GetLocalDict()["Ident"]() );
const char* newgameplay = extract< const char* >( GetLocalDict()["NewGamePlay"]() );
printf("Loading Script: %s\n", ident);
CGEPYGameMode* m_pGameMode = extract< CGEPYGameMode* >( GetLocalDict()[newgameplay]() );
However when i try and convert the Alpha class back to its base class (last line above) i get an boost error:
TypeError: No registered converter was able to extract a C++ pointer to type class CGEPYGameMode from this Python object of type Alpha
I have done alot of searching on the net but cant work out how to convert the Alpha object into its base class pointer. I could leave it as an object but rather have it as a pointer so some non python aware code can use it. Any ideas?
Thanks to Stefan from the python c++ mailling list, i was missing
super(Alpha, self).__init__()
from the constructor call meaning it never made the parent class. Thought this would of been automatic :D
Only other issue i had was saving the new class instance as a global var otherwise it got cleaned up as it went out of scope.
So happy now
May not be the answer you are looking for, but take a look at ChaiScript for embedding in your C++ application.
According to their website,
ChaiScript is the first and only
scripting language designed from the
ground up with C++ compatibility in
mind. It is an ECMAScript-inspired,
embedded functional-like language.
ChaiScript has no meta-compiler, no
library dependencies, no build system
requirements and no legacy baggage of
any kind. At can work seamlessly with
any C++ functions you expose to it. It
does not have to be told explicitly
about any type, it is function
centric.
With ChaiScript you can literally
begin scripting your application by
adding three lines of code to your
program and not modifying your build
steps at all.
Well, I am not sure whether it will help you, but I had the same problem with scripts in Lua. We created objects from Lua and wanted some c++ code to handle the objects via pointers. We did the following:
all object stuff was written in c++, including constructors, destructors and factory method;
lua code was calling a factory method to create an object. this factory method 1) gave the object a unique ID number and 2) registered it in the c++ map, that mapped ID numbers to native pointers;
so, whenever lua was going to pass a pointer to c++ code, it gave an object ID instead, and the c++ code looked up the map for finding the actual pointer by ID.
Related
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;
}
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.
I'm using Boost.Python to wrap a C++ library.
How do I ensure that the same Python instance (by object identity) is always returned for a particular C++ instance (by pointer identity)? I can't extend the C++ classes, but I can add a member variable (such as a PyObject * or a boost::python::handle<>) if that helps. I'm thinking that I should be able to cache the Python instance in the C++ instance, and return the cached instance instead of creating a new one. However, I can't figure out what wrapping code is required.
Example class to be wrapped:
class C {
public:
boost::python::handle<> wrapper_;
private:
C();
C(const C &);
~C();
};
Can anyone offer advice?
After investing some time into this very problem I came to the conclusion that it's more trouble than it's worth. I have resigned myself that id() will identify the (potentially short-lived) wrapper object and not the actual C++ object.
Instead I identify my C++ objects in some other way, e.g. by looking at the contents.
Currently I know how to have C++ objects instantiated and passed around in Lua using SWIG bindings, what I need is the reverse.
I am using Lua & C++ & SWIG.
I have interfaces in C++ and objects in lua, that implement methods which do the same job and have the same structure. I would like to be able to instantiate these objects in lua yet pass them around in C++ using pointers to that interface which they resemble.
As such I can imagine creating a c++ implementation of the interface which would act as a handler for said lua object, yet I don't know how to do this. The class would act as the lua objects representative or proxy in the C++ world.
To clarify I shall start with the following example code used in an answer to a similar question I asked:
C++ code:
// Represents a generic bank account
class Account {
virtual void deposit(double amount) = 0;
};
Lua code:
SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
SavingsAccount.balance = SavingsAccount.balance + amount
end
-- Usage
a = SavingsAccount
a.balance = 100
a.deposit(1000)
Now say that I have a class in C++ called Bank:
class Bank {
void AddAccount(Account* a);
};
What I would like here is a mechanism for doing the following in lua:
SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
SavingsAccount.balance = SavingsAccount.balance + amount
end
-- Usage
a = SavingsAccount
bank:AddAccount(a)
If I need to take an extra step such as instantiating a C++ class to act as a proxy and pass it the lua table with all my lua functions etc, I can imagine it looking like this:
C++ code:
// Represents a generic bank account
class ProxyAccount : public Account {
virtual void deposit(double amount);
};
Lua code:
SavingsAccount = { balance = 0 }
SavingsAccount.deposit = function(amount)
SavingsAccount.balance = SavingsAccount.balance + amount
end
-- Usage
a = SavingsAccount
a.balance = 100
a.deposit(1000)
proxy = program.ProxyAccount()
proxy.settable(a)
bank:AddAccount(p)
The problem here being I have no idea how I would implement the ProxyAccount class, or even what the function signature of settable would look like...
I'm not familiar with SWIG (I know what it is but have never used it) so this may not be the answer you are looking for.
I've been working on a C++ project and have had success using luabind. It allows you to subclass C++ objects with Lua objects. You might want to give it a try and see if it works for you.
What I seem to gather from your examples and the discussions is that 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.
Now, the important question is: why don't you want to have a C representation of the object, and prefer to have it in Lua? Since C++ is a much lower level language, and object definitions must be static, and Lua dynamically defines its "objects" it is much easier to have Lua adapt to C++ objects.
Another issue I see is that you seem to be designing your Lua code in a very Object Oriented manner. Remember that even though Lua can fake Object Oriented concepts, it is not built as an Object Oriented language, and should not be used primarily as one. If you want a fully OO scripting language, use python instead.
Now if you Really want to do it the other way, and considered that the other alternatives do not work for you, then what I would recommend, is that you keep the Lua object as a coroutine, this will allow you to:
Keep a representation of the object
in C++ (the lua_State *)
Have multiple individual instances of the same "object type"
Lua takes care of the cleanup
However, the downsides are:
All functions that act on an "object"
need to do so through the lua API
There is no easy/fast way to recognize different lua types (you
could use a metatable)
Implementation is quite cumbersome, and hard to decypher.
EDIT:
Here is how you could expose the interface to an object in a script, Each object instance would be running a new lua_State, and run its script individually, thus allowing for your "Object member data" to just be globals inside the script instance. Implementing the API for the object's methods would go like this:
int move(lua_State * L)
{
int idx = lua_getglobal(L, "this");
assert(!lua_isnull(-1));
AIObject * obj = static_cast<AIObject *>(lua_touserdata(L, -1));
lua_pop(1);
//Pop the other parameters
obj->move(/*params*/);
}
You can bind any C function you want to Lua and call it from there. You can define in this function what you expect the contract is between your script and your C++ code. For example, the following would kind of do what you want. You'll need to add meta table information to your Lua tables so you can distinguish different Lua object types.
int lua_AddBankAccount(lua_State* L, int pos)
{
// Assume you've created metadata for your Lua objects.
if (IsAccount(L, pos))
{
// process your 'Account' Lua instance.
}
else
{
// error - tried to add a non-Account.
}
}
You can take this further with SWIG to bind any arbitrary C method, but it's basically the same.