您的位置:首页 > 编程语言 > Lua

Lua调用只有头文件的C++动态库函数

2014-10-15 22:16 585 查看
前段时间公司让我寻找一个for C++的Lua Binder库,要求C++ 和 Lua能够双向调用(所以SWIG/tolua排除),最后选择了LuaBind的一个fork,名叫LuaPonte,选择的原因是既有LuaBind的广泛使用比较可靠,又支持LuaJIT(我们要用)的5.1语法。

昨天做summary presentation时我用这个例子展示Lua调C++的效果

void print_hello(int number) {
  std::cout << "hello world " << number << std::endl;
}

int main() {
  // Create a new lua state
  lua_State *myLuaState = luaL_newstate();

  // Connect LuaBind to this lua state
  luabind::open(myLuaState);

  // Add our function to the state's global scope
  luabind::module(myLuaState) [
    luabind::def("print_hello", print_hello)
  ];

  // Now call our function in a lua script
  luaL_dostring(
    myLuaState,
    "print_hello(123)\n"
  );

  lua_close(myLuaState);
}


没想到被人challenge了,说print_hello函数是自己定义的,实际项目中很可能不知道函数的定义,这时你怎么保证还能调用?

当时没反应过来,我选的LuaPonte也被architect枪毙掉了。。。。。。

今天仔细了解了下Lua调C的方法,总结起来就是

1,假设你的库里有n个函数,库名libxxx.so,则必须提供一个函数

2,在luaopen_xxx里调用luaL_Register注册你的所有n个函数

3,其中每个函数都必须是lua_CFunction类型

4,每个lua_CFunction获取Lua通过栈传入的参数,计算后将结果通过栈传回Lua

网上给的很多lua_CFunction示例,基本都是这样

int myAdd(lua_State *L)
{
int a = lua_getinteger(L, 1);// 1st arg
int b = lua_getinteger(L, 2);// 2nd arg
lua_pushinteger(L, a+b); //return sum to lua
return 1; // return result num
}



但是这样很难自动化,如果只能这样则SWIG就不可能存在了,所以,我猜测上面的代码如果要自动生成的话,应该是这样的

int myAdd(lua_State *L)
{
//根据类型推导库(boost::any等)获得参数个数和类型,略
int arg1 = lua_getinteger(L, 1);// 1st arg
int arg2 = lua_getinteger(L, 2);// 2nd arg
int result1 = trueAdd(arg1, arg2); //the wrapped func!
lua_pushinteger(L, result1); //return sum to lua
return 1; // return result num
}


这样就将负责bind的myAdd和负责运算的trueAdd分离开来。

其实这个trueAdd完全可以放在第三方库里,由LuaPonte(或其他Binder库)根据trueAdd的签名(头文件)生成myAdd,然后主程序链接myAdd,myAdd又链接trueAdd。

估计SWIG也是这么个路子,只是SWIG要额外产生一个so,相比之下该方法更好。

最后上一个自己写的例子

test.cpp

#include <luaponte/luaponte.hpp>

extern int myAdd(int a, int b);//all from third party lib's header file

int main()
{
        // Create a new lua state
        lua_State *myLuaState = lua_open();

        // Connect LuaBind to this lua state
        luaponte::open(myLuaState);

        luaponte::module(myLuaState)[
                luaponte::def("myAdd", myAdd)
        ];

        std::cout << "Result: "
        << luaponte::call_function<int>(myLuaState, "myAdd", 2, 3)
        << std::endl;

        lua_close(myLuaState);
        return 0;
}


libtest.cpp

int myAdd(int a, int b)
{
        return a+b;
}


Makefile

all:
        g++ -fPIC -c libtest.cpp -o libtest.o
        g++ -shared -o libtest.so libtest.o -ldl
        g++ -std=c++11 -c test.cpp -o test.o -I/root/pkgs/luaponte-master/
        g++ -o test -L/usr/local/lib -L/root/pkgs/luaponte-master/build/src/ -L. test.o -ltest -lluaponte -llua

clean:
        rm -f *.o *.so test


注意:若运行报找不到libtest.so,一般是LD_LIBRARY_PATH没有加入当前目录,加入即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: