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

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.

Related

SWIG-Python: How to garbage collect int pointer

I have a big C project and I want to expose it's API to python by using SWIG.
For that, I have a script for generating automatically the interface file for swig (.i file).
For each type defined in the project, the script adds to the interface file %pointer_functions and %array_functions for that type.
Those directives create set of functions including a "new" function which in turn allocates memory.
Is there a way to automatically deallocate that memory when the object is garbage collected instead of calling explicitly the "delete" function?
I have a solution for structs, using the %newobject directive and %extend with destructor definition which free the allocated memory - similar to the solution in this post SWIG - Garbage Collection using %newobject .
But it doesn't work on primitive types like int, enum, etc...
Any ideas how to solve it for such types?

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.

Per-entity Lua scripts in games?

I'm using Lua for scripts in my C++ game. I want to be able to attach scripts to entities, and based on which functions are defined in the script, register for callbacks which will run the script functions at the appropriate time.
I believe that I can encapsulate different scripts from each other, by making the "script" into a table. Basically, ... lua source code ... would become ScriptName = { ... lua source code ... }. Then instead of calling func(), I'd call ScriptName.func(), and thus two scripts defining the same function (aka registering for the same event) wouldn't trample over each other.
My problem now is in encapsulating different entities sharing the same script. Obviously I don't want them to be sharing variables, but with what I'm doing now, any variable defined by a script would be shared by every instance of that script, which is just really bad. I could maybe try something similar to my above solution on the source level, by wrapping every script with EntityID.ScriptName = { ... } before compiling it. Something tells me there's a better way, though, I just don't know it.
Another factor is that scripts need to be able to reference entities and scripts/components relative to a specific entity. If I use the above method the best solution to this would be passing entity IDs around as strings which could reference the table specific to that entity, I think? At this point I really have no idea what I'm doing.
In order for a script to interact with a C++ object, the typical approach is to have the C++ code expose the object to Lua as a userdata (a wrapper for a pointer) and provide C++ functions that the script can call, passing the userdata as parameter. In the C++ code, that userdata gives you the object that the function should to operate on. It's equivalent to a "this" pointer.
You usually do this by putting the C++ functions into a metatable associated with the userdata, so they can be called like methods in the Lua code (i.e. objectIGotFromCpp:someMethod('foo').
ScriptName.func(), and thus two scripts defining the same function (aka registering for the same event) wouldn't trample over each other.
Rather than relying on accessing globals or naming conventions, ect. it's much cleaner to simply provide a callback that Lua scripts can use to register for events.
If I use the above method the best solution to this would be passing entity IDs around as strings
No reason. An entity in your C++ code is a pointer to an object on the heap. You can pass that pointer directly to Lua as userdata. Lua can pass that back to your C++ code and give you direct access to the object, rather than going through some object-to-ID mapping.

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.

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

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.