1. liblua的 编译
lua脚本中的C module必须采用动态链接库的形式.
如果lua脚本再被c程序调用,c程序和CModule都必须动态链接lua库,
(如果采用静态链接的方式,会报multiple Lua VMs detected错误,认为启动了两个lua虚拟机)。
这样,就需要把lua编译成动态链接库。
2.特殊函数
lua5.1 之中有一个luaL_register,用于把luaL_Reg 数组中的所有函数注册到lua中。但在lua5.2中已经不支持这一函数了,
lua5.2的手册中建议使用luaL_setfuncs来替代luaL_register.
在5.1中经常会把一些C函数注册在LUA_GLOBALINDEX 全局table中。
e.g.
lua_pushstring(L, name)
lua_pushcfunction(L, func)
lua_settable(L, LUA_GLOBALSINDEX);
在5.2中已经移除了LUA_GLOBALSINDEX,去而带之的是注册表。
在5.1中lua_setglobal() 和 lua_getgloba() 都用是LUA_GLOBALINDEX 伪索引。
在5.2中上面两个函数都是使用的注册标中的LUA_RIDX_GLOBAS伪索引(索引注册表的全局环境)
LUA_RIDX_GLOBAS是LUA state 注册表中与定义的两个值之一。另一个是
LUA_RIDX_MAINTHREAD 索引的是lua state的主线程状态。
【lua_toXXX,luaL_checkXXX】都不会改变stack中的值,但是lua_tolstring会改变stack中的值(例如index对应的是number,这个函数调用会改变stack中的实际值)
所以在使用lua_next来遍历table表时,不能将luaL_tolstring应用在table key上,否则会引起table遍历的混乱
3.lua文件编译
可以预编译成bytecode,加快lua脚本的加载.
luac -o [编译后脚本名] [脚本名]
4.其它补足
a) table.x ,table["x"] 访问table变量的2种方式,效果一样。例如
M.print(1,2)
M["print"](1,2)
如何定义个table中的方法,可以如下:
sample1:
local t={}
function t.print(a,b)
print(a,b)
end
sample2:
t.print = function (a,b)
print(a,b)
end
b) lua脚本中可以使用tostring(v),来将各种类型的变量转换成string,如果v对应的metatable中有__string方法,会将这个方法的结果返回
c) lua语言中的for语句 可以解释成如下模型
for var_1,...,var_n in <explist> do <block> end
is equivalent to the following code:
do
local _f,_s,_var = <explist>
while true do
local var_1,...,var_n = _f(_s,_var)
_var = var_1
if _var == nil then break end
<block>
end
end
for语法会帮助存储一些变量,所以尽量应该使用stateless iterator,这样可以减少内存消耗。for提供的机制无法满足iterator时,尽量使用closure来封装更多的数据(状态),
实在不行的情况下,用上面的_s(非变量),来存储更多的状态信息.因为closure的存取被table.field快。
d)lua脚本中的require可以保证module只被load一次。已经被loaded的module,它的返回值被存在package.loaded.<modname> require "modname" 被调用,并且找到对应的库文件时,lua会将 modname和找到的库文件的位置传给对应的库文件。
关于require的执行流程
- 首先判断是否已经在package.loaded的表中
- 不在的情况下,依次遍历package.searchers list,如果整个search list中都没有找到合适的,会raise error
- searcher list中包含preload,lua searcher,c searcher,c supper searcher
- 例如lua searcher,就会利用传入的modname,以及lua path template,来查找对应的lua文件
关于这里的path template做简单说明:
编译的时候,lua runtime中会有个default path(?; ?.lua; /usr/local/lua/?/?.lua),这个可以作为运行时的path template
查找的时候,会用modname替换上面的?,依次查找各个路径是否有该文件。
对应lua ,c path template,会在启动时候查找环境变量LUA_PATH_5_2 ,LUA_PATH,LUA_CPATH_5_2,LUA_CPATH中的以双分号(;;)
标志的变量作为path template的开头搜索部分。
submodules,package
如果require的modname中包含点号,lua会将它变更成路径分割符,来查找该文件。
例如 path template:
./?.luar;/usr/local/lua/?.lua
当我们 require "a.b"时,实际查找的是
./a/b.lua
/usr/local/lua/a/b.lua
/usr/local/lua/a/b/init.lua
我们在写一般的lua module时,可以按照下面的格式
--import section
--导入库中要使用的全局函数或者外部函数,
--使用local变量还有一个好处是速度比较快
local sqrt = math.sqrt
local io = io
---将_env编为nil,好处是即使错误编写也不会玷污全局空间
_ENV = nil
<定义库部分>
--将导出函数归纳到一个表中
return {
new = new
add = add
}
补足:
在有些情况下,我们不能直接修改c binary so文件,但是它和其它c binary so重名了,怎么办?
有个小技巧
正常情况下,我们 require "mod"时,查找到该c library后会调用它的导出函数luaopen_mod,
但是可以通过短横线(-),来修饰c library name,但是调用的导出函数,却是忽略(-)之前的字符,例如
require "v-mod",同样查找的也是luaopen_mod
e) debug机能
lua提供的debug机能分为2类,一为检查类function,二为hooks function
可以通过 debug.getinfo(n),来获取当前活动栈中的信息,需要注意的是,调用debug.getinfo的函数A stack level 为 1(n=1),调用函数A的函数,level =2.
debug.getinfo:可以查找当前栈或者函数的相关信息
debug.getupvalue:可以查找closure的相关信息
coroutine抛出error的时候,并不会释放它的调用stack,所以这个时候你还是可以使用debug函数来检查一些变量
hooks可以监视function call,line code excuting,return call,count
一些对性能有要求的测试,有可能的情况下,尽可能使用c interface
f) lua eclipse插件
Eclipse Update: http://download.eclipse.org/koneki/updates-nightly/ldt
如何安装:http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.platform.doc.user/tasks/tasks-127.htm
h) 如何在editor中表达一个长字符串,可以分行
char lua_code[] = " \
function lprofT_mesure_function() \
local i \
\
local t = function() \
end \
\
i = 1 \
while (i < 100000) do \
t() \
i = i + 1 \
end \
end \
\
lprofT_mesure_function() \
lprofT_mesure_function = nil \
";
资源