tolua框架有两部分组成,一个是c#部分,一个是c部分,整个框架在游戏代码中的位置如下图所示:
可以看到tolua c起到承上启下的作用,是c#和lua之间进行堆栈交互的中间层。所以如果我们要为tolua c扩展功能的话,就必须把tolua c进行重新编译成对应平台的tolua库,供c#和lua进行调用。其中tolua地址为https://github.com/topameng/tolua,对应的tolua运行时地址为https://github.com/topameng/tolua_runtime。
一.编译win32和win64平台的tolua.dll库:
1.配置mingw:可以参考https://github.com/topameng/tolua_runtime/wiki进行配置,其中配置好的mingw地址为https://pan.baidu.com/s/1c2JzvDQ。
2.编辑build_win32.sh或者build_win64.sh文件,在里面添加或者移除第三方c库。以默认的build_win64.sh中添加sproto为例,配置如下:
#!/bin/bash
# 64 Bit Version
mkdir -p window/x86_64
cd luajit-2.1
mingw32-make clean
mingw32-make BUILDMODE=static CC="gcc -m64 -O2" XCFLAGS=-DLUAJIT_ENABLE_GC64
cp src/libluajit.a ../window/x86_64/libluajit.a
mingw32-make clean
cd ..
gcc -m64 -O2 -std=gnu99 -shared \
tolua.c \
int64.c \
uint64.c \
pb.c \
lpeg.c \
sproto.c \
lsproto.c \
struct.c \
cjson/strbuf.c \
cjson/lua_cjson.c \
cjson/fpconv.c \
luasocket/auxiliar.c \
luasocket/buffer.c \
luasocket/except.c \
luasocket/inet.c \
luasocket/io.c \
luasocket/luasocket.c \
luasocket/mime.c \
luasocket/options.c \
luasocket/select.c \
luasocket/tcp.c \
luasocket/timeout.c \
luasocket/udp.c \
luasocket/wsocket.c \
-o Plugins/x86_64/tolua.dll \
-I./ \
-Iluajit-2.1/src \
-Iluasocket \
-lws2_32 \
-Wl,--whole-archive window/x86_64/libluajit.a -Wl,--no-whole-archive -static-libgcc -static-libstdc++
3.打开ming32.exe或者ming64.exe的终端,并选择编辑好的build_win32.sh或者build_win64.sh文件进行编译,最终会生成一个tolua.dll文件到Plugins/x86或者Plugins/x86_64目录下。将编译好的tolua.dll拷贝到unity的Plugins下对应平台目录下进行替换。
二.编译android平台下arm和x86架构的libtolua.so库:由于android机器用的cpu架构最多的是acorn公司的arm架构,所以intel公司的x86架构也做了一个arm架构转换程序。所以我们一般只需要导出arm架构的libtolua.so库就行,但是有时有可能因为转换程序的问题,在x86架构机器上会出现闪退,所以最好也导出x86架构的libtolua.so库,但这样就会增加包体大小。编译android的libtolua.so库步骤如下:
1.安装ndk,下载地址为https://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip,下载安装完毕后配置ndk环境变量,如图所示:
2.编辑build_arm.sh或者build_x86.sh文件,修改ndk路径为自己ndk所在的路径,如上面环境变量地址:D:\Program\android-ndk-r10e。
3.修改android/jni目录下面的Android.mk文件,在里面添加或者移除第三方c库。以默认的Android.mk中添加sproto为例,配置如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libluajit
LOCAL_SRC_FILES := libluajit.a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE := tolua
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../luajit-2.1/src
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../
LOCAL_CPPFLAGS := -O2
LOCAL_CFLAGS := -O2 -std=gnu99
LOCAL_SRC_FILES := ../../tolua.c \
../../int64.c \
../../uint64.c \
../../pb.c \
../../lpeg.c \
../../sproto.c\
../../lsproto.c\
../../struct.c \
../../cjson/strbuf.c \
../../cjson/lua_cjson.c \
../../cjson/fpconv.c \
../../luasocket/auxiliar.c \
../../luasocket/buffer.c \
../../luasocket/except.c \
../../luasocket/inet.c \
../../luasocket/io.c \
../../luasocket/luasocket.c \
../../luasocket/mime.c \
../../luasocket/options.c \
../../luasocket/select.c \
../../luasocket/tcp.c \
../../luasocket/timeout.c \
../../luasocket/udp.c \
../../luasocket/usocket.c \
LOCAL_WHOLE_STATIC_LIBRARIES += libluajit
include $(BUILD_SHARED_LIBRARY)
4.打开ming32.exe终端,并选择build_arm.sh或者build_x86.sh文件进行编译,此时ndk会将luajit目录生成luajit.a文件放在android/jni目录下,并和Android.mk文件一起通过gcc编译,最终会生成一个libtolua.so文件到Plugins/Android/libs/armeabi-v7a或者Plugins/Android/libs/x86目录下。将编译好的libtolua.so拷贝到unity的Plugins下对应平台目录下进行替换。
tolua中更改第三方c库:tolua库中添加或者移除第三方c库后,需要在tolua的LuaDLL.cs文件中添加或者移除第三方c库的导出函数。还是以加上sproto为例,对应的lsproto.c库入口函数如下:
int luaopen_sproto_core(lua_State *L) {
#ifdef luaL_checkversion
luaL_checkversion(L);
#endif
luaL_Reg l[] = {
{ "newproto", lnewproto },
{ "deleteproto", ldeleteproto },
{ "dumpproto", ldumpproto },
{ "querytype", lquerytype },
{ "decode", ldecode },
{ "protocol", lprotocol },
{ "loadproto", lloadproto },
{ "saveproto", lsaveproto },
{ "default", ldefault },
{ NULL, NULL },
};
//luaL_newlib(L,l);
luaL_register(L, "sproto.core", l);
pushfunction_withbuffer(L, "encode", lencode);
pushfunction_withbuffer(L, "pack", lpack);
pushfunction_withbuffer(L, "unpack", lunpack);
return 1;
}
此时LuaDLL.cs中关联的导出函数为:
[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
public static extern int luaopen_sproto_core(IntPtr L);