tolua++が生成したグルーコードを見てみる
以前(http://d.hatena.ne.jp/kitfactory/20100511/1273583585)に作った、tolua++が生成したCとLuaの連携を実現するグルーコード。
LuaのC言語との連携で大事なのは、Lua側にCの関数や型を登録してCとの関係を作り上げることと、実際の関数呼び出しの処理(Luaで関数が呼ばれたら、関係づいているCの関数に引数を渡して処理させ、その返値をLuaに戻す)だと思う。グルーコードはどうやって実現しているのだろうか。ちょっくら見てみよう。
以前の例ではrequire文でDLLがロードされるときはrequire("cfunc")とした。これはcfuncというDLLのtolua_cfunc_open関数を呼ぶことを意味する。そこで、tolua_cfunc_open()の中身を見ると、型を登録したり、関数を登録したりという関数が見える。でもhello()関数を直接登録しているのではなく、hello()関数をラップしているtolua_cfunc_hello00()関数をhelloという名前で登録している。Luaでhello()だと思って呼び出しているのは、実はtolua_cfunc_hello00()関数ということか。
で、hello()をラップしているtolua_cfunc_hello00()関数ではLuaの中でhello()を呼び出した時の引数をLuaのVMが持っているスタックから引数を取り出して(スタックから数を取り出す tolua_tonumber)、実際のhello()関数を呼び出し、その返り値をLuaのスタックへ積んでいる。(tolua_pushnumber)
なるほど、よく出来てるなぁ。
/* ** Lua binding: cfunc ** Generated automatically by tolua++-1.0.92 on 05/11/10 21:34:46. */ #ifndef __cplusplus #include "stdlib.h" #endif #include "string.h" #include "tolua++.h" #include "cfunc.h" /* Exported function */ TOLUA_API int tolua_cfunc_open (lua_State* tolua_S); /* function to register type */ static void tolua_reg_types (lua_State* tolua_S) { } /* function: hello */ #ifndef TOLUA_DISABLE_tolua_cfunc_hello00 static int tolua_cfunc_hello00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isnumber(tolua_S,1,0,&tolua_err) || !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { int i = ((int) tolua_tonumber(tolua_S,1,0)); { int tolua_ret = (int) hello(i); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'hello'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE /* Open function */ TOLUA_API int tolua_cfunc_open (lua_State* tolua_S) { tolua_open(tolua_S); tolua_reg_types(tolua_S); tolua_module(tolua_S,NULL,0); tolua_beginmodule(tolua_S,NULL); tolua_function(tolua_S,"hello",tolua_cfunc_hello00); tolua_endmodule(tolua_S); return 1; } #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 501 TOLUA_API int luaopen_cfunc (lua_State* tolua_S) { return tolua_cfunc_open(tolua_S); }; #endif