cocos2d-x中luajit的使用

新版本的cocos2d-x使用了luajit来替代原始的lua,好处一是可以极大的提高运行速度(android下可以开jit,运行速度提高10-60倍,ios下不可以开jit,运行速度也可以提高2~3倍)。 二是luajit编译的字节码增加了反编译的成本,可以同时使用xxtea。 这里对luajit进行详细的说明。

1、基本使用。这个很简单,不用修改任何代码,与lua5.1完全兼容。 对应的头文件和库要替换成luajit的(与lua命名相同)

2、发布时编译成字节码。

这个需要luajit.exe的执行文件。 编译方法(windows): 在(http://luajit.org/download.html)下载源代码,使用vs的命令行工具,执行msvc.bat进行编译。
编译完成后,要注意luajit.exe和源代码src/jit文件夹要同时并且匹配使用。否则运行时会出现 "unknown luaJIT command or jit.* modules not installed"的错误。

编译成字节码的命令如下: luajit -b 原始文件 输出文件

3、编译luajit的静态库文件(for android)

编译字节码所用的执行文件和我们开发程序时使用的静态库文件要保持版本一致。 windows版本所需要的文件在编译执行文件时就已经生成。

android编译需要使用NDK在windows下进行交叉编译。 这里我一开始使用cygwin没有成功。一大堆编译错误。后来换mingw就相对顺利了。 我使用的是msys+mingw的环境(在装msysgit时附带装好的…) 编译脚本参考了cocos2d-x本身的和luajit官网的。修改如下:

#!/bin/sh
SRCDIR=/c/msysgit/msysgit/LuaJit-2.0.2
DIR=/d/MyProj/develop/lib/cocos2d-x/scripting/lua/luajit
 
cd "$SRCDIR"
 
NDK=/d/adt-bundle-windows/android-ndk-r8e
NDKABI=8
NDKVER=$NDK/toolchains/arm-linux-androideabi-4.7
NDKP=$NDKVER/prebuilt/windows/bin/arm-linux-androideabi-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-arm"
 
#Android/ARM, armeabi (ARMv5TE soft-float), Android 2.2+ (Froyo)
DESTDIR=$DIR/android/armeabi
rm "$DESTDIR"/*.a
make clean
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_SYS=Linux TARGET_FLAGS="$NDKF"
 
if [ -f $SRCDIR/src/libluajit.a ]; then
    mv $SRCDIR/src/libluajit.a $DESTDIR/libluajit.a
fi;
 
# Android/ARM, armeabi-v7a (ARMv7 VFP), Android 4.0+ (ICS)
NDKARCH="-march=armv7-a -Wl,--fix-cortex-a8"
DESTDIR=$DIR/android/armeabi-v7a
rm "$DESTDIR"/*.a
make clean
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_SYS=Linux TARGET_FLAGS="$NDKF $NDKARCH"
 
if [ -f $SRCDIR/src/libluajit.a ]; then
    mv $SRCDIR/src/libluajit.a $DESTDIR/libluajit.a
fi;
 
# Android/x86, x86 (i686 SSE3), Android 4.0+ (ICS)
NDKABI=14
DESTDIR=$DIR/android/x86
NDKVER=$NDK/toolchains/x86-4.7
NDKP=$NDKVER/prebuilt/windows/bin/i686-linux-android-
NDKF="--sysroot $NDK/platforms/android-$NDKABI/arch-x86"
rm "$DESTDIR"/*.a
make clean
make HOST_CC="gcc -m32" CROSS=$NDKP TARGET_SYS=Linux TARGET_FLAGS="$NDKF"
 
if [ -f $SRCDIR/src/libluajit.a ]; then
    mv $SRCDIR/src/libluajit.a $DESTDIR/libluajit.a
fi;
 
make clean

最开始设置好SRCDIR和DIR这个是Luajit源代码的目录和编译好的库文件的安装目录。 NDK指定的是android ndk的安装目录。 原本cocos2d-x的脚本自动检测host(与这行代码相关 NDKP=$NDKVER/prebuilt/windows/bin/arm-linux-androideabi-),但是不太管用,所以统一修改为windows

这里还要注意下,我在编译armv7a的时候总是出现minilua.exe执行错误,无法编译成功,去掉-mfloat-abi=softfp后编译正常。

Android中编译和使用LuaJIT
1.把生成的libluajit.a库文件与一些头文件拷贝到jni目录下
本例子中使用的是ndk中的hello-jni工程

$ cp src/{libluajit.a,lua.h,lauxlib.h,lua.hpp,luaconf.h,luajit.h,lualib.h} > ../android/jni  # android工程jni目录
$ vim ../android/jni/Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDLIBS := $(LOCAL_PATH)/libluajit.a   #加上这句

include $(BUILD_SHARED_LIBRARY)

2.修改hello-jin.c

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"  // 引入头文件

lua_State* L;         // Lua指针

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    L = lua_open();   // 打开Lua指针
    luaL_openlibs(L);
    luaL_dostring(L, "return 'Hello from Lua !'");  // 执行Lua语句
    const char * str = lua_tostring(L, -1);         // 获取Lua语句的返回值
    lua_close(L);

    return (*env)->NewStringUTF(env, str);
}

下一篇
作者:知乎用户
链接:https://www.zhihu.com/question/49144449/answer/123116906
来源:知乎
我的建议是,如果使用luajit,就全部都使用,即使在不支持jit的IOS平台上,你也应该使用禁用掉jit功能的LuaJIT,而不是原版lua。
如果要将现有代码迁移至LuaJIT,我建议您看一下下面的内容。
LuaJIT和lua的兼容性是有的,而且问题非常之多,在我的DontStarveLuaJIT系列文章中有两篇提到了多处不同:饥荒游戏扫雷笔记(一)|脚本引擎篇——LuaJIT的救赎(合集) - paintsnow的文章 - 知乎专栏饥荒游戏扫雷笔记(二) | 脚本引擎篇——偷懒的高温陷阱 - paintsnow的文章 - 知乎专栏

如果不想看原文,我大概总结一下:
1.string HASH策略不一样,导致表的遍历顺序不一样。(你不应该让程序逻辑依赖于表的遍历顺序)
2.表的[0]索引的实现不一样,LuaJIT会放在array part,而lua则在hash part,导致遍历顺序不一样(使用pairs或者next。
3. string的转义符处理策略不一样,对于"\abcdef"这样的字符串,lua会把不能形成有效转义序列的字符串拆开,也就是这里的\和a都会出现在最终的字符串里。而LuaJIT会报错,因为没有\a这个转义符。
4. LuaJIT新增加了不少转义符,像\u{1234}来表示unicode字符。
5. LuaJIT新增加了自己的库函数,例如ffi等。使用它们后将不再会保持与原版lua的兼容性。
6. LuaJIT和lua5.2及以后的版本不支持arg这个语法糖来代表{…},因此旧代码迁移到luaJIT会有这样的问题。
7. LuaJIT会有一些限制,比如说一个函数内最多定义的常量个数,函数最多的参数个数之类的。这些上限一般都比lua的上限要小,所以有些过于复杂的代码能在lua中跑但是在LuaJIT中会引起编译错误。有的限制可以调整luaJIT代码中的常量来提高,但是像“函数内最多定义的常量个数”由于指令格式的限制,想到突破需要新增指令,需要对LuaJIT比较熟悉才能做到;否则就像我文章中提到的那样针对某些情况绕过去。(通常会发生在序列化数据表的地方)
8. @唐艺洋 提到的,luaJIT内存上限为4G
9. LuaJIT中使用table.unpack(table.pack(1, 2, 3, nil, 5))将得到1, 2, 3而不是1, 2, 3, nil, 5
10. 想到了再续

以上所有问题的兼容和解决方案(大部分是workaround)在上面两篇文章中有提到了,如果您有较多的旧代码,不方便作迁移的话,可以从github上clone我的DontStarveLuaJIT:GitHub - paintdream/DontStarveLuaJIT: Don’t Starve LuaJIT/OpenGL ES optimization patch (compatible with DS, RoG, SW, DST [only for test] ) ,以获取与lua兼容性较好的luajit!但是如果您的代码量不多或者精力比较充沛,建议您还是手工修改掉自己代码中这些奇怪的地方。因为这些lua和luajit的不同之处大部分都是不好或者罕见的编程习惯。

猜你喜欢

转载自blog.csdn.net/qq_35624156/article/details/86696923