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

来源:互联网 发布:python字符串转字典 编辑:程序博客网 时间:2024/04/27 22:35

前段时间公司让我寻找一个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 argint b = lua_getinteger(L, 2);// 2nd arglua_pushinteger(L, a+b); //return sum to luareturn 1; // return result num}


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

int myAdd(lua_State *L){//根据类型推导库(boost::any等)获得参数个数和类型,略int arg1 = lua_getinteger(L, 1);// 1st argint arg2 = lua_getinteger(L, 2);// 2nd argint result1 = trueAdd(arg1, arg2); //the wrapped func!lua_pushinteger(L, result1); //return sum to luareturn 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 fileint 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 -lluaclean:        rm -f *.o *.so test

注意:若运行报找不到libtest.so,一般是LD_LIBRARY_PATH没有加入当前目录,加入即可。


1 0
原创粉丝点击