C++轻量级脚本:lua

C++轻量级脚本:lua

1) Lua

轻量级脚本语言,源代码也及其轻量,能很方便得嵌入到C/C++。

Lua最著名的的莫过于游戏脚本,但这次过程中新发现的Nginx+Lua,着实让我长见识了(难道只是自己孤陋寡闻TT)。

2) 准备

curl -R -O http://www.lua.org/ftp/lua-5.2.3.tar.gz
tar zxf lua-5.2.3.tar.gz

解压后,“doc/readme.html"详细介绍了Lua的编译与安装。

2.1) 编译Lua

这里,如果选择自行配置编译的话,就是如下生成一个lib,两个exe:

library:
    lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c lstrlib.c ltablib.c loadlib.c linit.c
interpreter(解释器,可交互,运行Lua文本或预编译字节码):
    library, lua.c
compiler(编译器,生成预编译二进制文件):
    library, luac.c

但需要注意以下几点:

  1. “src/luaconf.h"内可自定义特性,并能查看到其对一些宏定义的说明。
  2. 编译"compiler"时,链接"library"动态库有问题的话,就直接链接lib所有的object文件吧。

编译时,一般要定义如下些宏:

# Window
_WIN32
LUA_BUILD_AS_DLL
LUA_COMPAT_ALL

# Linux
LUA_USE_LINUX
LUA_COMPAT_ALL

另外,Linux上需要安装readline:

yum install readline readline-devel -y

并且链接时,需要添加:

-lm -Wl,-E -ldl -lreadline

然后,就可以愉快得玩耍了。

2.2) 学习Lua

推荐官方书籍:Programming in Lua, Third Edition,书本示例可见附1。

或者这些资料:

  1. Learn Lua in 15 Minutes
  2. Lua简明教程
  3. Lua游戏开发实践指南

如果对Lua源码感兴趣的话:

  1. Lua源码欣赏
  2. Lua代码分析

3) Luabind

PiL第四部分介绍了Lua原生的C API,而Luabind则是Lua的C++封装了,其受Boost.Python所启发。

官方文档里只介绍了bjam来编译,自行配置编译的话,步骤如下:

  1. 下载Luabind与Boost。注意:如果是Lua5.2的话,那么下这个Luabind。不然,会遇到Issue 1。
  2. 添加Luabind/src下所有文件,包含Luabind、Boost根目录及Lua/src目录,链接Lua库,添加宏"LUABIND_DYNAMIC_LINK”,然后编译即可。
  3. Linux下可能会遇到luabind与boost不兼容,在宏"BOOST_PP_ITERATION_FLAGS"位置。问题及补丁见Issue 2。

Issue 1: compile luabind with errors

error C3861: 'lua_strlen': identifier not found
error C2065: 'LUA_GLOBALSINDEX' : undeclared identifier

Issue 2: incompatibility of luabind and boost on linux, here is the patch

.../luabind/detail/call_member.hpp:319:7: note: in expansion of macro 'BOOST_PP_ITERATION_FLAGS'
 #elif BOOST_PP_ITERATION_FLAGS() == 1

.../luabind/detail/call_function.hpp:326:7: ...
.../luabind/wrapper_base.hpp:92:7: ...

3.1) 使用Luabind

内容其实挺多,最好阅读下官方文档。

以下是官方的Hello world,更多文档示例代码也请见附1。

lb_hello.cc

#include <iostream>
#include "luabind/luabind.hpp"

void greet() {
    std::cout << "hello world!" << std::endl;
}

extern "C" SHARED_EXPORT
int luaopen_lbhello(lua_State *L) {
    using namespace luabind;

    // register the functions to create classes from Lua, and initialize
    // some state-global structures used by luabind.
    open(L);

    // register all declared functions or classes in the global namespace
    // in Lua.
    module(L)
    [
        def("greet", &greet)
    ];

    return 0;
}

编译动态库时,SHARED_EXPORT在Windows下得是__declspec(dllexport),Linux则不需要。

lb_hello.lua

require "lbhello"
-- package.loadlib('lbhello.dll', "luaopen_lbhello")()
greet()

写Luabind示例时,遇到的以下情况值得留意:

  1. Window与Linux绑定Class时成员变量默认值不一致。可见附1"src/Luabind/lb_bind.*“。
    • 基础类型成员变量默认值:Linux正常原值;Window上却是function。
    • 非基础类型成员变量默认值:Linux正常引用,直接print()时tostring会出错,应该设个__tostring方法就好;Window上仍是function。
    • Window上用property()也一样,初次get也是function。仅当设了值后,再使用才正常。

另外,官方文档到17节才提到了Build options。18节是Implementation notes,简单规避方式为:不以__luabind为变量前缀,不覆盖全局super。

4) LuaJIT

Lua即时编译器,将Lua脚本编译成本地机器码来运行,提升效率。

4.1) 编译LuaJIT

官方Installation里已有详细说明。不过目前版本仅完全兼容5.1。5.2的话,Extensions from Lua 5.2内有描述,定义宏DLUAJIT_ENABLE_LUA52COMPAT能开启更多些特性。

cd LuaJIT-2.0.3

# Linux
make PREFIX=/usr/local/lj-2.0.3
sudo make install PREFIX=/usr/local/lj-2.0.3
ln -s /usr/local/lj-2.0.3/bin/luajit /usr/bin/luajit
# luajit,确认可运行

# Windows
# "Visual Studio Command Prompt"
cd src
msvcbuild
# 拷贝src目录下的luajit.exe,lua51.dll以及jit目录即可使用
# 忘记jit目录的话,会遇到Issue 1
# luajit.exe,确认可运行

Issue 1: luajit.exe: unknown luaJIT command or jit.* modules not installed

如果自行配置编译的话,可以参考这个:

  1. 使用VS IDE编译Luajit脚本引擎

4.2) 使用LuaJIT

同样看官方Running LuaJIT的说明,用如下代码试用比较了下:

test.lua

local os = require "os"
local string = require "string"
local debug = require "debug"

function timeit(func, ...)
    fname = debug.getinfo(1, "n").name
    begstamp = os.time()
    result = func(...)
    endstamp = os.time()
    elapsed = os.difftime(endstamp, begstamp)
    print(string.format("%s cost time: %.2f", fname, elapsed))
    return result
end

function hanoi(n, a, b, c)
    if n == 1 then
        print("Move "..n.." from "..a.." to "..c)
    else
        hanoi(n-1, a, c, b)
        print("Move "..n.." from "..a.." to "..c)
        hanoi(n-1, b, a, c)
    end
end

timeit(hanoi, 15, "A", "B", "C")

然后:

# 字节码
luac -o test.out test.lua
lua test.out
# 机器码
luajit -b test.lua test.out
luajit test.out

结果:15的话,1.00;改到20的话,也差不多都38.00。PC上上述代码测不出什么差距啊==。

5) 其他

5.1) LDoc

  1. 使用LDoc给Lua生成文档

5.2) ngx_lua

Nginx嵌入Lua作脚本。

  1. Nginx与Lua
  2. Ngx_lua使用技巧和应用的范例

5.3) cloudwu@github

  1. ejoy2d:2D图形引擎
  2. skynet:游戏服务器

6) 总结

本文主要介绍了Lua的一些环境。针对学习的话,仅给出了参考资料以及整理的示例(见附1)。

对于Lua的话,个人感受很不错。可能是因为自己以前没做过类似的实践,譬如把V8或Python嵌入C++作为脚本。也充分体现了Lua良好的可嵌入性。

总之,感兴趣的话,还不赶紧动起手来。

附1:样例工程lua_start

下载:lua_start.zip。

C::B工程,目录树如下:

lua_start/
├─build/
│  ├─lua_start-gcc.cbp   # for gnu gcc
│  └─lua_start-msvc.cbp  # for msvc 2010
├─src/
│  ├─Luabind/  # Luabind文档示例
│  └─PiL3/     # PiL3书籍示例
├─third_party/
│  ├─boost_1_55_0/
│  ├─lua-5.2.3/
│  ├─luabind-0.9/
│  └─luasocket-3.0-rc1/
└─tools/

third_party/下都是空目录,前文已提及下载。目录名不能变,版本最好一致。

其中LuaSocket在PiL3第9章协程会用到,请下载这个LuaSocket 3.0-rc1。

另外,Linux下也将lua编译成了动态库,并会在post build时拷贝到/usr/local/lib/目录。所以,最好以root用户打开C::B,以确保有操作权限。

ll /usr/local/lib/liblua*

PiL3/下可以在当前目录,通过lua.bat,lua.sh或lua.py来运行书籍示例脚本。

而Luabind/下只有lb_run.py,编译工程all_lua,all_luabind两个target后,直接"python lb_run.py"就会运行所有例子了。

你可能感兴趣的:(C++,lua,luajit,luabind)