I am working on creating a Lua binding to another C++ project. After some investigation, LuaJIT FFI seems to be the best choice to achieve that goal. I really benefit from the lua-user mail list archive [1] and another related slide [2]. Actually a Hello World sample is done here [3] and any suggestions for improvements are welcome.
Currently I am trying to introduce shared_ptr
to this sample so that I won't need to care about garbage collection issue. But due to my poor experience on both Lua and LuaJIT, the Lua script always return Segmentation fault
and I even do not know how to debug that. The code snippets are listed as following and wish you talented guys can give me some practical advice.
This is hello.cpp
and the command I use to create the library is g++ -std=c++11 -shared -fPIC -o libhello.so hello.cpp
.
#include<memory>
using namespace std;
class Hello {
public:
const char* World()
{
return "Hello World!\n";
}
};
typedef shared_ptr<Hello> pHello;
extern "C" {
pHello Hello_new(){
return pHello();
}
const char* Hello_World(pHello self){
return self->World();
}
}
This is the hello.lua
with running command luajit hello.lua
.
ffi = require('ffi')
ffi.cdef[[
typedef struct pHello pHello;
pHello Hello_new();
const char* Hello_World(pHello);
]]
hello = ffi.load('hello')
hello_index = {
World = hello.Hello_World
}
hello_mt = ffi.metatype('pHello', {
__index = hello_index
})
Hello = hello.Hello_new
hello = Hello()
io.write(ffi.string(hello:World()))
Things don't work like you expect them to do.
First of all, your C++ code is flawed: The call return pHello()
returns an empty shared_ptr
with no managed object (say: null pointer). If you want to create a new object, call return std::make_shared< Hello >()
.
Apart from that, using a shared_ptr
does not help you regarding garbage collection. The reference counting done by the smart pointer relies on the destructor being called, a C++ mechanism. As the FFI library interfaces with C code this won't happen no matter how you wrap it up to pass it to LuaJIT (your compiler should have warned you about the use of `extern "C" together with a class-typed return type).
The standard way (if you want to rely on garbage collection) is to let the __gc
metamethod call a function doing the delete
on the C++ side. This is the C way: You allocated a resource in your function call, you are responsible to free it afterwards.
I'd recommend to write a simple wrapper around your class, perhaps using pure Lua API first to learn the basics. Move onto wrapping shared_ptr
later, when you have shared objects and don't want to do the reference counting yourself.