How do I push An instance of a c++ class wrapped with swig onto a lua stack? - c++

I have a class that is wrapped with swig, and registered with lua. I can create an instance of this class in a lua script, and it all works fine.
But say I have an instance of a class made in my c++ code with a call to new X, and I have la lua_state L with a function in it that I want to call, which accepts one argument, an instance of X... How do I call that function. Here is (some) of the code in question (I've omitted the error handling stuff):
main.cpp
class GuiInst;
extern "C"
{
int luaopen_engine (lua_State *L);
}
int main()
{
GuiInst gui=new GuiInst;
lua_State *L=luaL_newstate();
luaopen_engine(L); //this is swigs module
int error=luaL_loadfile(L,"mainmenu.lua")||
lua_pcall(L, 0, 0, 0);
lua_getglobal(L,"Init");
//Somehow push gui onto lua stack...
lua_pcall(L, 1, 0, 0));
lua_close(L);
}
mainmenu.lua
function Init(gui)
vregion=gui:CreateComponent("GuiRegionVertical");
end
At the moment all I have found that can work is to expose some functionality from the swig generated cpp file, and call that. This is bad for a few reasons... It won't work if I have multiple modulles and I had to change the default linkage specification in the swig file (using -DSWIGRUNTIME=).
I add the following to main.cpp
extern "C"
{
struct swig_module_info;
struct swig_type_info;
int luaopen_engine (lua_State *L);
swig_module_info *SWIG_Lua_GetModule(lua_State* L);
void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);
That gets a pointer to the module, then a pointer to the type, then calls swigs function to register it. It was an unreasonable thing to have to dig into a file that's not supposed to be human readable (so it says at the top of the file) and is just MESSY! (but it does work!)
Surely theres a better way to accomplish what I'm trying to do.
PS from a high level pov what I want is to have lua not refcount the Gui components which are created by the Object Factory in GuiInst, in case I'm going about this wrong. This is my first time exposing functionality to a scripting language apart from some very simple (and non-swig) python modules, so I'm prepared to take advice.
Thanks for any advice!
Response to comment by RBerteig
GuiInst's contructor is #defined to private when swig runs to prevent lua constructing instances of it, so that won't work for me. What I was trying to prevent was the following (in lua):
r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())
which would call "g=new GuiButton" then register it with the GuiRegionVertical (which needs to store a pointer for various reasons), then call "delete g", and the GuiRegionVertical is left with a dangling pointer to g.
I suspect what really needs to happen is that GuiRegionVertical::Add(GuiButton*) should increment the ref count of the GuiButton*, and then GuiRegionVertical's destructor should decrement the refcounts of all of its contents, though i'm not sure how this should be done with swig.
That would remove the need for the private constructors, the Gui Object Factory and the nasty externs.
Am I going about this Wrong?
Thanks.

Better late then never, and this solution will help other people.
void handle_web_request(WebRequest *request, WebResponse *response)
{
lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
lua_call(rackam->lua_state, 2, 0);
}
this code must be inside %{}% blocks in your .i file, because SWIGTYPE_p_WebRequest is
#define SWIGTYPE_p_WebResponse swig_types[6]
and swig_types[6] is
static swig_type_info *swig_types[12];
which means that swig_types is only accessable from the C++ file from which it is defined.
this particular snippet is sending in two of my wrappered pointers, so calling handle_web_request(request, response) from the C++ side of things will run the global lua function "handle_web_request" and pass it my two pointers, with the SWIG magic applied.

There is a simple and direct answer, that may not be the most efficient answer. SWIG produces wrappers for manipulating objects from the scripting language side. For objects, it also synthesizes a wrapped constructor. So, the direct solution is to just let the Lua interpreter call SWIG's constructor to create the new object.
For the wrapped engine.GuiInst class, you almost certainly can do something like:
int main()
{
lua_State *L=lua_open();
luaopen_engine(L); //this is swigs module
int error=luaL_loadfile(L,"mainmenu.lua")||
lua_pcall(L, 0, 0, 0);
luaL_dostring(L, "Init(engine.new_GuiInst())");
lua_close(L);
}
For a one-shot case like script startup, the penalty of running a string constant through luaL_dostring() is not bad at all. I'd look harder to avoid it in an event callback or an inner loop, however.
It does seem like there ought to be a way to convert a pointer directly into a wrapped object, I'm not spotting it in my own handful of SWIG generated wrappers.
Edit: Of course, the Lua fragment can be decomposed to API calls that get the engine table global on the stack, extract from it the new_GuiInst member, call it, then call the global Init, but the little bit of efficiency comes at the cost of some clarity.
As for dealing with objects that shouldn't be constructed by accident in user code, as the clarified question indicates, my first impulse would be to let SWIG generate the constructor function, keep a private reference if needed later, and remove it from the table. Even a C module is (usually) just a table whose members contain function values. Being implemented in C doesn't make them read-only unless extra effort is taken.
So, you could always retrieve the value of engine.new_GuiInst and park it in the registry (see luaL_ref() and the discussion in section 3.5 of the Lua Reference Manual of the pseudo-index LUA_REGISTRYINDEX for the details) for later use. Then, before letting any user code run, simply do the equivalent of engine.new_GuiInst = nil. I should note that for the C data types I've been playing with most recently, SWIG created two constructors for each type, named new_TYPE and TYPE. Both were visible in the module's table, and you would want to set both names to nil. If have much less experience with SWIG wrapping C++ classes, and the result may differ...
You might want to check and review the whole content of the engine table returned by SWIG, and create a proxy object that contains only the methods you want available to your users. You can also change the environment seen by the user script so that it only has the proxy available, and names the proxy engine as well. There has been a fair amount of discussion of sandboxing user scripts on the Lua list and at the lua-users wiki.

Related

Creating a new c++ object from within a lua script?

---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.

Call C++ Functions in an active program from Lua

I'm not sure if my question makes any sense, but I certainly know it is near impossible to get the results from Google. Firstly, what I do not want. I don't want to call some function that prints "hello world" or adds two numbers together, I want to load a Lua script from a C++ program, but allow the script to modify variables of the C++ program, using functions. For example, imagine I have a C++ program like this:
class Foo
{
private:
int number = 0;
public:
void setNumber(const int& newNumber) {number = newNumber;}
}
int main()
{
Foo foo;
//Load and execute Lua script, with foo object
return 0;
}
How could I allow the Lua script to do foo.setNumber() (preferably without foo.)? This may be a very simple question, but as mentioned above, almost all information on Google when searching "Call C++ Function from Lua" assume there is no program, but just a .cpp/hpp file with some functions that you want to call.
I'm on Linux (Ubuntu), but the program needs to compile on all platforms (Windows and Mac)
This is asked here fairly regularly.
To roll your own binding you should:
Master Lua metatables completely.
Read the Programming in Lua stuff on the C API, particularly the part on classes. Alternatively you can read the manual, read the source (API headers especially), and do some googling, but the book will probably save you some time.
Broadly, you expose a C++ class instance to Lua by creating a Lua "userdata" containing a pointer to the class instance and passing this to the Lua script. A userdata is an opaque type; the Lua script can't actually do anything with it (other than pass it around) unless you give it a metatable. At the very least you must implement the __index metamethod on the userdata, which allows your C++ code to intercept attempts to index the userdata and return something meaningful, and the __gc metamethod, which allows your C++ code to delete the exposed C++ object when the corresponding Lua userdata is garbage collected.
For instance, you create a function called createFoo which creates a Foo instance, wraps the pointer as a userdata, applies a metatable implementing __index to it, and returns it to the Lua script.
When the user runs foo.setNumber, your C++ __index metamethod is called with the userdata and the string "setNumber". It's up to you what you return and this determines what foo.setNumber evaluates to in the Lua script. You want foo.setNumber to evaluate to a lua_CFunction which expects a Foo userdata as its first parameter, so that your class methods can be called idiomatically from Lua (i.e. foo:setNumber(12), which is syntax sugar for foo.setNumber(foo, 12)).
It's a very low level and manual process, and once you get the hang of it you're going to end up create a library/templates/macros whatever to do the boilerplate for you. At that point you may want to evaluate the myriad C++ binding libraries that exist. However, thanks to the Law of Leaky Abstractions it's a very good idea to learn to do this manually first.

SWIG:Lua - Passing a c++ instance as a lua function parameter

I'm exporting some c++ classes to Lua with SWIG. I have declared boost::filesystem::path in the SWIG interface file like this:
namespace boost
{
namespace filesystem
{
class path {};
}
}
Now I want to call a function declared in a lua script which should take a boost::filesystem::path& as parameter to pass it to another object. I only need to be able to pass the path to the object. I don't need to use any functionality from the path object.
function on_path_selected(the_path)
another_object:set_path(the_path)
end
I am going to call the Lua function from c++ using it's index.
lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_index);
lua_push[SOMETHING](L, path_object); // <-- HOW TO ?
lua_pcall(L,1,0,0)
THE QUESTION: How to push a boost::filesystem::path as a parameter to the Lua function?
This is actually fairly complicated. The expected use of SWIG is to create modules for Lua. The Lua script should be the one deciding what gets called and what doesn't. It isn't really meant for embedded use, where you use SWIG to expose some C++ objects and then call Lua code directly from your application.
That's not to say that it's impossible, just complicated.
All SWIG-based C++ objects are passed through Lua as pointers. Thus ownership is a question; you can't just shove a pointer to a stack object into Lua.
The safest way to do this is to pass a new copy of the object to Lua. That way, Lua owns the pointer. SWIG will know that Lua owns the pointer, and will attach a proper garbage collection mechanism to it to clean it up. So everything should be fine, memory wise.
But doing this requires properly "boxing" (for want of a better term) that object the way that SWIG wants it done. This requires using certain SWIG macros.
Given how you have bound the path type to SWIG, you would do something like this to stick it onto a Lua stack:
swig_type_info *pathType = SWIG_TypeQuery("boost::filesystem::path *");
boost::filesystem::path *pArg = new boost::filesystem::path(the_path);
SWIG_NewPointerObj(L, pArg, pathType, 1);
SWIG_TypeQuery fetches the type of any object that has been bound by SWIG to Lua. This type info object is needed for SWIG_NewPointerObj, which takes a pointer to that type. Both of these are macros. SWIG_NewPointerObj gives Lua ownership of the pointer; Lua's garbage collector will delete it thanks to SWIG's metatables. Also SWIG_NewPointerObj pushes the object onto the lua_State stack.
Once it's on the stack, you can pretty much do whatever you want with it. Return it from a function to Lua, pass it to a Lua function as an argument, stick it in a global variable, etc. It's a Lua value.
Now, if you type this code into your project, odds are good that you'll get a compile error when the compiler sees swig_type_info. This type is defined internally within the source file generated by SWIG's command-line.
You have two options:
Put this source code into the .swig file itself. Yes, really. You can define regular C++ functions there, within verbatum sections (the %{ %} delimited blocks). These functions will be copied directly into SWIG's generated code. You can access them by putting prototypes in headers. This is the simplest and easiest way to work. This is often used for creating special interfaces, where a pre-existing C++ function isn't appropriate for a Lua API (or simply doesn't exist).
You can generate an appropriate header that contains these definitions with the -external-runtime argument. This has to be a different SWIG execution step from the step that generates the .cpp file. See, it doesn't actually process the SWIG file or anything. All it needs is the target language (-lua) and whether you're using C++ (-c++).So just have a command that does swig -c++ -lua -external-runtime someheader.h, and that's all you need to get the types and macros.
Include that header in whatever source you want to attach SWIG-bound objects to Lua in.

Passing C++ object to C++ code through Python?

I have written some physics simulation code in C++ and parsing the input text files is a bottleneck of it. As one of the input parameters, the user has to specify a math function which will be evaluated many times at run-time. The C++ code has some pre-defined function classes for this (they are actually quite complex on the math side) and some limited parsing capability but I am not satisfied with this construction at all.
What I need is that both the algorithm and the function evaluation remain speedy, so it is advantageous to keep them both as compiled code (and preferrably, the math functions as C++ function objects). However I thought of glueing the whole simulation together with Python: the user could specify the input parameters in a Python script, while also implementing storage, visualization of the results (matplotlib) and GUI, too, in Python.
I know that most of the time, exposing C++ classes can be done, e.g. with SWIG but I still have a question concerning the parsing of the user defined math function in Python:
Is it possible to somehow to construct a C++ function object in Python and pass it to the C++ algorithm?
E.g. when I call
f = WrappedCPPGaussianFunctionClass(sigma=0.5)
WrappedCPPAlgorithm(f)
in Python, it would return a pointer to a C++ object which would then be passed to a C++ routine requiring such a pointer, or something similar... (don't ask me about memory management in this case, though :S)
The point is that no callback should be made to Python code in the algorithm. Later I would like to extend this example to also do some simple expression parsing on the Python side, such as sum or product of functions, and return some compound, parse-tree like C++ object but let's stay at the basics for now.
Sorry for the long post and thx for the suggestions in advance.
I do things similar to this all the time. The simplest solution, and the one I usually pick because, if nothing else, I'm lazy, is to flatten your API to a C-like API and then just pass pointers to and from Python (or your other language of choice).
First create your classes
class MyFunctionClass
{
public:
MyFunctionClass(int Param)
...
};
class MyAlgorithmClass
{
public:
MyAlgorithmClass(myfunctionclass& Func)
...
};
Then create a C-style api of functions that creates and destroys those classes. I usually flatted in out to pass void* around becuase the languages I use don't keep type safety anyway. It's just easier that way. Just make sure to cast back to the right type before you actually use the void*
void* CreateFunction(int Param)
{
return new MyFunctionClass(Param);
}
void DeleteFunction(void* pFunc)
{
if (pFunc)
delete (MyFunctionClass*)pFunc;
}
void* CreateAlgorithm(void* pFunc)
{
return new MyAlgorithmClass(*(MyFunctionClass*)pFunc)
}
void DelteAlgorithm(void* pAlg)
{
if (pAlg)
delete (MyAlgorithmClass*)pAlg;
}
No all you need to do is make python call those C-style function. In fact, they can (and probably should) be extern "c" functions to make the linking that much easier.

Pass C++ object to Lua function

I have a C++ project, where 1 method of a 1 class changes very often. So I want to take that code from C++ to Lua. Note, I'm novice to Lua.
The whole task:
Bind some class methods to Lua state machine;
Pass reference to class object to a function, written in Lua;
Operate with passed C++ object in Lua function.
I've found how to make first step with Lunar, and can't cope with second and third.
I can't use SWIG and boost.
//This has a large number of steps, but I'm gonna post them all. This is all using native Lua 5 and the lua CAPI.
int CreateInstanceOfT(lua_State* L) {
new (lua_newuserdata(L, sizeof(T))) T(constructor args);
return 1;
}
int CallSomeFuncOnT(lua_State* L) {
if (lua_istable(L, 1)) { // If we're passed a table, get CData
lua_getfield(L, 1, "CData");
lua_replace(L, 1);
}
if (!lua_touserdata(L, 1))
lua_error(L); // longjmp out.
T& ref = *(T*)lua_touserdata(L, 1);
ref.SomeFunc(); // If you want args, I'll assume that you can pass them yourself
return 0;
}
int main() {
lua_State* L = luaL_newstate();
lua_pushcfunction(L, CreateInstanceOfT);
lua_setglobal(L, "CreateInstanceOfT");
lua_pushcfunction(L, CallSomeFuncOnT);
lua_setglobal(L, "CallSomeFuncOnT");
luaL_dofile(L, "something.lua");
lua_close(L);
}
-- Accompanying Lua code: semicolons are optional but I do out of habit. In something.lua
function CreateCInstance()
local Instance = {
CData = CreateInstanceOfT();
SomeFunc = CallSomeFuncOnT;
}
return Instance;
end
local object = CreateCInstance();
object:SomeFunc(); // Calls somefunc.
I could post a great quantity of detail about how to make exposure easier, and how to make inheritance, and suchlike - and it'll need altering if you want to expose more than one T (I think the most common solution is a simple struct { std::auto_ptr<void>, int type } deal). But, it should be a starting point if you don't understand anything about this process.
Bascally, first, we ask Lua to allocate some space (the userdata), then put T in it. When CallSomeFuncOnT comes up, first we ask it if we have a table (many Lua classes are based around tables, as they support object orientation, metatables, and such), and get the userdata out, which we then convert into a pointer to our object, and then convert into a reference. Remember that lua_touserdata gives you a void*, so you'd better be damn sure about what's on the other end. Then we call somefunc and return.
In Main, we just register the functions as globals.
Now, in Lua, when you call CreateInstanceOfT, it effectively just calls the T constructor, transparently to the Lua user. Then we ditch it in a table, which is simpler for Lua novices, and call SomeFunc by passing it this table.
Have you taken a look at luabind? It makes it fairly easy to expose C++ objects and functions to LUA.
Like John, I've used luabind and recommend it. However, since using boost isn't an option for you, you may find the list of libraries on this page helpful. You may also want to check out the DoItYourselfCppBinding page on the lua-users wiki.
One library mentioned on the page is oolua, which has no dependencies (so it says).