lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]




On Sun, Jul 17, 2011 at 2:22 AM, Steven Berry <steven@berry.asn.au> wrote:
I have just started working on a new project using C++ and LuaJIT (and also
just started using Lua/LuaJIT) and I wanted to confirm some questions about
the best way of setting up the bindings between the two.

I'm currently not using any existing binding libraries/tools as I couldn't
find one I liked and that used the FFI. If I've missed one please let me
know.
My current approach is to run my binding generator before compilation and
generate a cpp + lua binding file.
I use clang to visit each method and output the corresponding wrapper
function.

For example, for the input:

  class Test1 {
  public:
     void Method1(const char *text);
  };

  class Test2 {
  public:
     void Method1(Test1 *a, int b);
  };

  class Test3 : public Test2 {
  public:
     void Method2();
  };


I would generate a wrapper file for the C++:

  Test1 * Test1_new() {
     return new Test1();
  }
  void Test1_delete(Test1 *__this) {
     delete __this;
  }
  void Test1_Method1(Test1 *__this, const char *text) {
     __this->Method1(text);
  }
  void Test2_Method1(Test2 *__this, Test1 *a, int b) {
     __this->Method1(a, b);
  }
  void Test3_Method2(Test3 *__this) {
     __this->Method2();
  }

and then a Lua file:

  ffi = require('ffi')
  ffi.cdef[[
     typedef struct { void *__this; } Test1;
     typedef struct { void *__this; } Test2;
     typedef struct { void *__this; } Test3;

     Test1 *Test1_new();
     void Test1_Method1(void *__this, const char *text);
     void Test2_Method1(void *__this, void *a, int b);
     void Test3_Method2(void *__this);
  ]]
  C = ffi.C

  local Test1_index = {Method1 = function(__this, text)
C.Test1_Method1(__this, text) end }
  local Test1_mt = ffi.metatype("Test1", { __index = Test1_index})
  Test1 = function() return Test1_mt(C.Test1_new()) end

  local Test2_index = {Method1 = function(__this, a, b)
C.Test2_Method1(__this, a, b) end }
  local Test2_mt = ffi.metatype("Test2", { __index = Test2_index})
  Test2 = function() return Test2_mt(C.Test2_new()) end

  local Test3_index = CopyTable({Method2 = function(__this)
C.Test3_Method2(__this) end }, Test2_index)
  local Test3_mt = ffi.metatype("Test3", { __index = Test3_index})
  Test3 = function() return Test3_mt(C.Test3_new()) end


(In my case I delete/free the objects in C++ so I don't have to worry about
gc for most of the classes)
I'm also making sure that none of the C++ classes I expose use multiple
inheritance to simplify things, and I currently use void * in the ffi cdef
so I don't have casting issues.
I can also generate non ffi bindings in a similar fashion.

I know the above works as I have it working, but I'm not sure if I've missed
something or if there is a faster/easier/better way of doing things?

Thanks,
Steven



I am experimenting with a similar approach:

simple.cpp:     gist: 1087380
simple_jit.lua : gist: 1087382

The interesting part in these two files is this:

simple = ffi.load('simple')
-- wrap into class like behavior
local mt = {}
mt.__index = mt
function mt.id(self, ...)
  return simple.Simple_id(self.super, ...)
end

function Simple(...)
  local self = {super = simple.Simple_Simple(...)}
  ffi.gc(self.super, simple.Simple__gc)
  return setmetatable(self, mt)
end

s = Simple(6)
print(s:id())
=====

I do not know if this is better then classical bindings.


                                                               Gaspard