SWIG: Lua - passing a C ++ instance as a parameter to the lua function

I am exporting some C ++ classes to Lua using SWIG. I declared boost :: fileystem :: path in the SWIG interface file as follows:

namespace boost { namespace filesystem { class path {}; } } 

Now I want to call the function declared in the lua script, which should take boost :: filesystem :: path & as a parameter to pass it to another object. I only need to go through the path to the object. I do not need to use any functions from the path object.

 function on_path_selected(the_path) another_object:set_path(the_path) end 

I will call the Lua function from C ++ using this index.

 lua_rawgeti(L, LUA_REGISTRYINDEX, m_function_index); lua_push[SOMETHING](L, path_object); // <-- HOW TO ? lua_pcall(L,1,0,0) 

QUESTION: How to push boost :: filesystem :: path as a parameter to a Lua function?

+2
source share
1 answer

It is actually quite complicated. The expected use of SWIG is to create modules for Lua. Lua script should be the only one deciding what is called and what is not. This is actually not intended to be built-in use when you use SWIG to display some C ++ objects, and then call the Lua code directly from your application.

This does not mean that it is impossible, just difficult.

All SWIG-based C ++ objects are passed through Lua as pointers. Thus, the question of ownership is a question; you cannot just drag a pointer to a stack object in Lua.

The safest way to do this is to transfer a new copy of the object to Lua. Thus, Lua owns a pointer. SWIG will know that Lua owns the pointer and will attach the proper garbage collection mechanism to it to clear it. So everything should be fine, the memory is reasonable.

But this requires a proper “boxing" (due to the lack of a better term), which object as SWIG does. This requires the use of certain SWIG macros.

Given how you bound the path type to SWIG, you would do something similar to push it onto the 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, outputType, 1); 

SWIG_TypeQuery selects the type of any object that has been linked by SWIG to Lua. This type information object is required for SWIG_NewPointerObj , which takes a pointer to this type. Both of these are macros. SWIG_NewPointerObj gives Lua ownership of the pointer; The Lua garbage collector will delete it thanks to the SWIG metadata. Also, SWIG_NewPointerObj pushes the object lua_State stack.

Once it is on the stack, you can do whatever you want. Return it from a function in Lua, pass it to the Lua function as an argument, insert it into a global variable, etc. This is the value of Lua.

Now, if you inject this code into your project, the chances that you will get a compilation error when the compiler sees swig_type_info are good. This type is defined inside the source file generated by the SWIG command.

You have two options:

  • Put this source code in the .swig file itself. Yes indeed. You can define regular C ++ functions there in the help topics ( %{ %} blocks). These functions will be copied directly to the generated SWIG code. You can access them by putting prototypes in the headers. This is the easiest and easiest way to work. This is often used to create custom interfaces where a pre-existing C ++ function is not suitable for the Lua API (or simply does not exist).

  • You can create an appropriate header containing these definitions with the -external-runtime argument. This should be another SWIG run step from the step that generates the .cpp file. See, it does not actually process the SWIG file or anything else. All he needs is the target language ( -lua ) and whether you use C ++ ( -c++ ). So just run the command swig -c++ -lua -external-runtime someheader.h and all you need to get types and macros.

    Include this header in any source that you want to connect to SWIG related objects in Lua in.

+5
source

All Articles