luajit是什么
简单说,是lua语言的另一个实现版本,唯一区别的是,加入了jit功能。
JIT是just in time的缩写,也就是即时编译。
编译luajit
前置说明
luac文件是加密后的代码,并不是luac的代码才会在luajit模式下运行,加密和luajit是2个任何不相关的东西,不要混淆,这是一个理解的误区。
如果使用了luajit的库,那么lua代码才会在luajit模式下运行,因为luajit编译出来的是lua51.dll,和lua官方编译出来的文件名是一致的。
代码是在luajit的情况下崩溃的,所以必须让项目的lua代码运行在luajit模式下,为了方便测试,我选择了使用win32进行编译测试。
win32编译
luajit的win32编译非常简单,作者已经帮我们写好了bat编译脚本,切换到Visual Studio Command Prompt
输入msvcbuild.bat很顺利就在当前目录下生成了lua51.lib
msvcbuild.bat的解读
不使用msvcbuid.bat,自己搭建luajit的vs项目,这篇文章可以参考,编译脚本我们还是需要好好理解下,有助于我们了解更多的细节。
- 先编译了minilua.c,链接生成了minilua.exe
cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline host\minilua.c link /nologo /out:minilua.exe minilua.obj
- 生成src/host/
buildvm_arch.h
,host/.gitignore里面忽略了这个文件,也印证了这个文件是需要动态生成的 - 复制代码
minilua ..\dynasm\dynasm.lua -LN -D WIN -D JIT -D FFI -o host\buildvm_arch.h vm_x86.dasc
- 编译buildVM相关的源码,生成buildVM.exe,这里用到了上一步生成的buildvm_arch.h文件,不过对于cmake来说,它只关心c文件,不会影响cmake的编写
cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline /arch:SSE2 /I "." /I ..\dynasm host\buildvm*.c link /nologo /out:buildvm.exe buildvm*.obj
- 使用buldVM.exe,生成了一些中间文件有
obj
、.h
、.lua
,也就是-o
参数后边的文件
buildvm -m peobj -o lj_vm.obj buildvm -m bcdef -o lj_bcdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c buildvm -m ffdef -o lj_ffdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c buildvm -m libdef -o lj_libdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c buildvm -m recdef -o lj_recdef.h lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c buildvm -m vmdef -o jit\vmdef.lua lib_base.c lib_math.c lib_bit.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c lib_debug.c lib_jit.c lib_ffi.c lib_buffer.c buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
- 编译
lj_\*.c
、lib_\*.c
,链接生成lua51.dll
,最关键的一步之前的所有准备都是为这一步准备的
cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline /arch:SSE2 /MD /DLUA_BUILD_AS_DLL lj_*.c lib_*.c link /nologo /release /DLL /out:lua51.dll lj_*.obj lib_*.obj 1. 编译luajit.c,链接生成luajit.exe 2. bash 3. 复制代码 cl /nologo /c /O2 /W3 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_STDIO_INLINE=__declspec(dllexport)__inline /arch:SSE2 luajit.c link /nologo /release /out:luajit.exe luajit.obj lua51.lib
- 最后就是一些清理工作了,至此生成的文件为lua51.lib lua51.dll luajit.exe
编译luajit可能遇到的报错
手动搭建vs项目编译luajit时,你一定会遇到这个问题:
2>lib_jit.obj : error LNK2019: 无法解析的外部符号 _lj_vm_cpuid,函数 _jit_cpudetect 中引用了该符号 2>lib_math.obj : error LNK2019: 无法解析的外部符号 _lj_vm_floor,函数 _random_seed 中引用了该符号 2>lj_vmmath.obj : error LNK2001: 无法解析的外部符号 _lj_vm_floor
lj_vm_xx
好多函数都是在lj_vm.h
中定义的,发现的确是没有lj_vm_cpuid
的实现,luajit快的一个原因就是lj_vm_xx
之类的函数都是用反汇编实现的,这也导致你就没有办法通过vs进行完整的编译luajit,只能通过官方提供的msvcbuild.bat
进行编译。
调试luajit的解决办法
通过msvcbuild.bat编译出来debug版本,然后将lua51.dll
、lua51.lib
、lua51.pdb
(这个非常重要,能够调试跳转到源码全部靠他)文件提供给exe使用,最后是勉强跑起来了
命令参数debug无法通过cmake设置,只能自己手动设置了
现在也能跳转到lua_cpcall
了,但是像lj_vm_cpcall
这个就无法跳转了,只能从堆栈中查看反汇编看到的结果:
不过经过这番折腾,勉强可以跑起来了luajit,并且在对应的源码位置打断点,是可以进行调试的
尝试触发lj_meta_chach
简单测试了下,目前发现调用该函数是在lua_close的时候,游戏关闭或者被强行退出,也会有可能触发该函数,但是崩溃就有点无法理解了
也有可能是lua gc触发的,也有可能是我的lua脚本太简单,看来还是需要放到项目中进行验证。
至此,我们已经大致了解编译调试luajit的办法了,下一步就是放到cocos2dx中实际跑起来。