SLua 中使用 Lua 5.3 的编译工程

2016-03-05 更新:

之前编译的库,在 Android 下 Lua_Number 和 Lua_Integer 被编译为了32位,导致从 C# 到 Lua 过程中有64位到32位整型转换会出现溢出出错,出现异常大的负整数。

以下修改或是之前遗漏的部分均使用红色表示。


2016-11-21 更新:

之前编译的库都是用的是 32位的 NDK(当时vs2015还不支持最新的64位ndk),如果你是用64位的 NDK 编译请注意兼容性问题;其二请注意安卓打包的库目录问题,安卓库 "libs"目录下对应于不同的cpu目录:

ARM 32: "armeabi-v7a"

ARM 64: "arm64-v8a"

x86 32: "x86"

x86 64: "x86_64"


  我们项目将 SLua 中的 Lua 核心升级为了 5.3.2,添加了 LPeg 和 sproto(和服务器兼容)。

整个工程直接分别创建了 Mac 和 IOS 的 XCode 工程,以及 Windows 和 Android 的 VS2015工程,vs 支持 clang 和 gcc 后,可以直接创建 Android NDK 工程。

  安装 vs2015 的过程中,可以选择安装 Android 的支持,但是 NDK 以及其他工具的安装需要从谷歌下载,会导致这些组件安装失败,所以只能安装完成后,手动安装 NDK。

  vs2015 只支持 NDK r10e 32位,使用更高版本将无法使用 clang,因为 vs2015默认且只支持 clang 3.6,具体请阅读这里。各个 Android 需求工具的安装默认路径,请参考这里

  一个简单的办法是:将下载好的 NDK 放置在:“C:\ProgramData\Microsoft\AndroidNDK”,或其他地方,然后修改注册表:“HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\Setup\VS\SecondaryInstaller\AndroidNDK”(没有则新建),然后新建项:“NDK_HOME”,设置值为 NDK 的安装路径即可完成。再次编译 NDK 工程则不会出现 "NDK_ROOT" 未定义的情况。

  最简单的办法是:在安装时不勾选 Android SDK,NDK,自己单独下载,安装 vs2015 完毕后,在 工具 -> 选项 -> Cross Platform -> C++ -> Android 一栏修改路径即可。

  使用 vs2015 编译 Android 版本 slua 需要注意的几个地方:

  • 目前主流的 ARM 处理器都是带浮点处理单元的,即:“armeabi-v7a”,需要在 ARM 架构的配置中加入宏定义:“__ARM_ARCH_7A__”(实际在 vs2015 中编译的最低版本也是 armv7,不显式指定此宏也可以);
  • 目前 支持 c99 的 NDK 至少为:“Jelly Bean 4.3.x,(android-18)”(属性页中的目标 API 级别),如果想兼容更低版本的 api,需要添加宏定义:“LUA_USE_C89”,否则会出现 error : undefined reference to 'log2' 错误,(属性页-> C/C++ -> 语言 -> C语言标准,不需要设置成 -std=c89,保持默认值:“默认”,可能依然导致编译错误。);(此处注意:一旦使用 LUA_USE_C89,那么 Lua_Number 和 Lua_Integer 就会被编译为32位,具体请参考 luaconf.h 中的代码,slua 中 lua_pushinteger 导出接口的定义默认使用的是 Int64,所以存在一个类型转换和溢出问题,你会发现无论你怎么调用 lua_pushinteger 到了 lua 端,数据都是错的,很可能是一个大的负整数,这就是我找了好几天才发现的错误,一个大坑。当然,你也可以在 slua 的 luadll.cs 中将 lua_pushinteger 导出接口的定义改为 Int32 应该也能修复,不过我没有试验并强烈建议使用 64 位整形的 Lua。)(2017-07-09更新:后来查看了 XLua 的工程编译并知道了,其实 log2 是 c99 的新函数,在 c98 中 lua 是通过两步运算模拟的,c99 中直接使用 log2 运算效率更高,所以如果为了支持 Android api 更低级别,只需要删除 math_log 中
    #if !defined(LUA_USE_C89)
        if (base == 2.0) res = l_mathop(log2)(x); else
    #endif

    这一小段代码即可,影响就是在 log2 的运算中,效率稍低,但是兼容性更好了。)

  • 可能编译 Lua 会出现错误:error : no member named 'decimal_point' in 'struct lconv',你可以修改 luaconf.h 中将
    #define lua_getlocaledecpoint()        (localeconv()->decimal_point[0])

    修改为:

    #define lua_getlocaledecpoint()        ('.')

    但是这样修改了源文件会影响其他平台,所以更好的方式是,在工程属性页 -> C/C++ -> 命令行 -> 其他选项 中加入:-D "lua_getlocaledecpoint()=('.')" ,(引号也是内容一部分),这样修改仅限于 Android 平台编译;

  • 如果出现各种连接错误:error : undefined reference to 'xxx',xxx 为各种数学函数 sin, cos 等等,需要给连接器增加 -lm 选项,动态查找链接接口:工程属性页 -> 链接器 -> 命令行 -> 其它选项 中加入:-lm 即可。
  • 同时需要在工程 Debug 配置中加入宏定义:"LPEG_DEBUG"
  • Mac 版本编译 Debug 版本,由于代码的一些书写(函数定义和使用)不符合 c99 书写标准,需要修改才能编译通过;
  • Mac 版本编译的额外链接选项 Other Linker Flags 需要加入:“-undefined dynamic_lookup”;
  • 默认 Lua 的异常使用 longjmp,如果编译为 c++ 会自动转换为 try-catch,如果在c++工程中编译 c 代码,由于已经定义 _cplusplus,LUAI_THROW 会被展开为 try,出现编译错误的话可以考虑添加宏:LUA_USE_LONGJMP。

  编译工程 SLua + Lua 5.3.2 + LPeg 1.0.0 + sproto 的 GitHub 地址:https://github.com/yaukeywang/slua-503-build

  后续:由于 premake5 目前对 vs2015 的支持还不完整,打算利用业余时间扩展 premake5,同时将改工程修改为 premake5 工程并提交到 github。