olua 导出工具的使用
olua 是一个基于代码生成的 lua 绑定库,能够生成 c++ 类、枚举、lambda 函数、运算符函数、实例化模版等的 lua 绑定代码,你可以对生成的细节做一些定制,比如在函数调用前后插入代码,生成带异常捕获的代码块,生成迭代器,生成 lua 注释等等。
如果想了解 olua 的设计细节,请参见:
1. 使用示例
1.1. 创建
新建一个目录存放配置和 olua 脚本,结构如下:
tree -L 2 . |
1.2. clang 参数配置
clang { |
1.3. 构建脚本
require "olua" |
1.4. 生成
当配置好所以需要导出的类之后,就可以执行以下命令导出绑定。
lua build.lua |
2. 可选配置
可以在 build.lua
文件中,设置变量以调整扫描行为:
olua.AUTO_BUILD
:默认true
,扫描完成后,自动导出绑定代码。olua.AUTO_GEN_PROP
:默认true
,是否自动为getName
、isVisible
生成name
、visible
属性。olua.AUTO_EXPORT_PARENT
:默认false
,当没有用typeconf
指定父类时,是否自动导出。olua.ENABLE_DEPRECATED
:默认false
,是否导出已丢弃方法或变量。olua.ENABLE_WITH_UNDERSCORE
:默认false
,是否导出以_
开头的变量或方法。olua.MAX_VARIADIC_ARGS
:默认 16,生成重载方法时,最多支持的参数个数。olua.ENABLE_EXCEPTION
:默认false
,是否生成异常捕获代码。olua.CAPTURE_MAINTHREAD
:默认false
,是否捕获L
线程。olua.PARSE_ALL_COMMENTS
:默认false
,是否解析所有注释。
3. 配置指令
3.1. module
模块名称是由 module
指定的,也是构建导出文件名称的一部分。
module "example" |
导出信息:
- 导出文件名称
lua_example.h
和lua_exmaple.cpp
- 模块函数是
luaopen_example
3.2. output_dir
导出文件的目录是由 output_dir
指定的,可以是绝对路径,也可以相当路径。
output_dir '../../src' |
3.3. headers
导出的头文件中的 include
部分是由 headers
指定的,这是保证编译成功的前置条件。
headers [[ |
3.4. codeblock
模块中,如果需要引入手写代码,可以由 codeblock
指定,此代码原封不动拷贝至导出的文件中。
codeblock [[ |
3.5. luaopen
在 luaopen
函数中,插入代码。
module 'example' |
static int luaopen_example(lua_State *L) |
3.6. api_dir
指定 lua annotation api
生成的目录。
api_dir '../../addons/example' |
3.7. entry
指定 luaopen
函数返回的类。
entry 'example::Hello' |
OLUA_LIB int luaopen_example(lua_State *L) |
3.8. exclude_type
指定不需要导出的类型,一旦排除了一个类型,那么包含此类型的方法和变量都将忽略。
-- exclude example::Command and example::Command * |
3.9. import
如果要包含一个配置文件,可以使用 import
指令,比如引入 lua-types.lua
。
import 'olua/lua-types.lua' |
3.10. luacls
lua
类名的定制是由 luacls
指令实现的。
luacls(function (cppname) |
3.11. macro
macro
一般用于条件编译。
macro '#ifdef CCLUA_BUILD_EXAMPLE' |
Object
所生成的代码都被 CCLUA_BUILD_EXAMPLE
包裹。
|
3.12. typedef
typedef
定义了一个类型,一般来说,你已经手动实现该类型的转换器,只是使用 typedef
将其关联。
3.12.1. 语法
typedef 'ClassName' |
3.12.2. 指令 .luacls
指定 lua 类名。
3.12.3. 指令 .conv
指定转换器,若未指定申明类型或未指定转换器,则默认是 olua_$$_ClassName
。
3.12.4. 指令 .packable
指定此类型支持 @pack
和 @unpack
。
3.12.5. 指令 .packvars
指定此类型由多少个成员变量组成。
3.12.6. 指令 .smartptr
指定类型是否为智能指针类型,如果是,会把 std::shared_ptr<Node *>
当作一个整体,而不是一个模版容器。
3.12.7. 指令 .override
替换已有的类型信息。
3.12.8. 指令 .default
指定默认值。
3.12.9. 指令 .luatype
指定 lua 类型。
3.12.10. 指令 .from_string
指定此类的构造函数是否支持字符串初始化,默认为 false
。
static int _olua_fun_std_filesystem_ls$1(lua_State *L) |
3.12.11. 指令 .from_table
指定此类的实例对象是否支持使用 table 来创建,默认为 false
。
OLUA_LIB void olua_check_table(lua_State *L, int idx, example::Point *value) |
3.12.12. 示例
typedef 'example::vector' |
3.13. typeconf
typeconf
用于指定类或枚举的导出,包括类的静态方法、静态变量、对象方法、对像变量,但不包括模版函数。
同时会根据已经扫描到的信息,生成 typedef
信息,相当于:
// c++ 对象 |
3.13.1. 语法
typeconf 'ClassName' |
3.13.2. 指令 .codeblock
导出手写代码。
typeconf 'Object' |
3.13.3. 指令 .luaname
自定义方法或变量的 lua
名称。
typeconf 'Object' |
static int luaopen_Object(lua_State *L) |
3.13.4. 指令 .supercls
指定此类的父类名称,默认为 nil
,由导出工具根据扫描信息而定。
typeconf 'Hello' |
3.13.5. 指令 .packable
指定此类支持 @pack
和 @unpack
标记,同时在导出时自动生成以下几个函数:
OLUA_LIB void olua_pack_object(lua_State *L, int idx, Object *value); |
3.13.6. 指令 .packvars
指定此类型由多少个成员变量组成,一旦设置此变量,将不会自动生成上面三个函数,必须由使用者自己提供这三个函数。
3.13.7. 指令 .luaopen
在 luaopen_Hello
函数中,插入代码。
typeconf 'Hello' |
static int luaopen_Hello(lua_State *L) |
3.13.8. 指令 .indexerror
指定类的可访问性
typeconf 'Object' |
r
访问不存的属性时抛出错误w
写入新的属性时抛出错误
3.13.9. 指令 .from_string
指定此类的构造函数是否支持字符串初始化,默认为 false
。
typeconf "std::filesystem::path" |
3.13.10. 指令 .from_table
指定此类的实例对象是否支持使用 table 来创建,默认为 false
。
3.13.11. 指令 .exclude
所有方法和变量默认导出,除了指定的。
typeconf 'Object' |
.exclude
还支持通配符形式:「.exclude '^m_.*'
」
3.13.12. 指令 .include
所有方法和变量默认不导出,除了指定的。
typeconf 'Object' |
3.13.13. 指令 .macro
指定哪些方法需要根据宏来决定要不要编译。
typeconf 'Object' |
|
3.13.14. 指令 .iterator
生成迭代器。
typeconf "std::filesystem::path" |
static int _olua_fun_std_filesystem_path___pairs(lua_State *L) |
3.13.15. 指令 .extend
扩展指定的类。
typeconf 'Object' |
把所有 ObjectExtend
的静态方法合并至 Object
中。
3.13.16. 指令 .var
定义一个变量。
.ret
和 .arg1...N
使用说明参见 参数标记
.insert_before
、.insert_after
、.insert_cbefore
、和 .insert_cafter
使用说明参见 插入代码
.tag_scope
、.tag_store
、.tag_maker
、.tag_mode
、.tag_usepool
使用说明参见 回调函数配置
3.13.17. 指令 .func
定义方法。
typeconf 'Object' |
... |
.ret
和 .arg1...N
使用说明参见 参数标记
.insert_before
、.insert_after
、.insert_cbefore
、和 .insert_cafter
使用说明参见 插入代码
.tag_scope
、.tag_store
、.tag_maker
、.tag_mode
、.tag_usepool
使用说明参见 回调函数配置
3.13.18. 指令 .prop
定义属性。
typeconf 'Object' |
... |
3.14. typeonly
只导出类型信息,不导出任何方法和变量,等价于:
typeconf 'Object' |
3.15. 插入代码
在导出插入代码,共有 4 个可以插入:
insert_before
函数调用前。insert_after
函数调用后。insert_cbefore
回调函数调用前。insert_cafter
回调函数调用后。
typeconf 'Object' |
static int _Object_pay(lua_State *L) |
3.16. 回调函数配置
定义 std::function
回调细节。回调函数实现参见:olua 回调函数设计
typeconf 'Object' |
回调函数存储细节:
callback functions |
tag_usepool
回调函数的参数是否使用对象池,默认值true
。tag_mode
标签匹配模式,如果回调函数作为参数,默认值为replace
;如果回调函数作为返回值,默认值为equal
。replace
如果存在指定tag
的回调函数,则替换,否则创建新tag
存储回调函数。new
始终创建新tag
存储回调函数。startwith
删除开头包含tag
的回调函数。equal
删除与tag
相同的回调函数。
tag_store
回调函数存储位置,默认值为0
,合法值有:0
如果是静态方法,存储在.classobj
中;如果对象方法,则存储在userdata
中。-1
存储在返回值中。1、2...N
从左到右数,存储在第N
个参数中。
tag_maker
指定存储回调函数的键值,有两种形式:string
纯字符串。makeTag(#N)
、makeTag(#-N)
,将第 N 个参数作为参数调用makeTag
生成键值。
tag_scope
回调函数的生命周期,默认为object
,合法值有:object
由对象管理。once
调用一次就移除。invoker
调用完底层函数后就移除.
static int _Object_onClick(lua_State *L) |
3.17. 参数标记
.ret
和 .arg1...N
都支持 @
关键字的标记,给参数添加更多的行为。
3.17.1. @postnew
标记返回值属于新创建,要使用 olua_postnew
。
typeconf 'Object' |
static int _Object_create(lua_State *L) |
3.17.2. @nullable
标记参数是否可以为 nil
。
-- void onClick(const ClickCallback &callback); |
static int _Object_onClick(lua_State *L) |
3.17.3. @addref
给参数添加使用引用标记:@addref(name mode [where])
name
引用名称。
mode
引用存储模式,有两种:
^
独立存在。-- void setScene(Object *scene);
typeconf 'Object'
.func 'setScene' .arg1 '@addref(scene ^) @nullable'static int _Object_setScene(lua_State *L)
{
...
self->setScene(arg1);
...
olua_addref(L, 1, "scene", -1, OLUA_REF_ALONE);
...
}|
共存。-- void addChild(Object *child);
typeconf 'Object'
.func 'addChild' .arg1 '@addref(children |)' .ret '@delref(children ~)'static int _Object_addChild(lua_State *L)
{
...
olua_startcmpref(L, 1, "children");
...
self->addChild(arg1);
...
olua_addref(L, 1, "children", -1, OLUA_REF_MULTI);
olua_endcmpref(L, 1, "children");
...
}
where
引用存储的位置,如果提供此值,同时得使用插入代码,用于获取此值。
-- void show(); |
static int _Object_show(lua_State *L) |
关于引用实现参见 olua 引用链
3.17.4. @delref
给参数添加移除引用标记:@delref(name mode [where])
name
引用名称。
mode
引用存储模式,有四种:
^
独立存在。-- void setScene(Object *scene);
typeconf 'Object'
.func 'setScene' .arg1 '@delref(scene ^) @nullable'static int _Object_setScene(lua_State *L)
{
...
self->setScene(arg1);
...
olua_delref(L, 1, "scene", -1, OLUA_REF_ALONE);
...
}|
共存。-- void removeChild(Object *child);
typeconf 'Object'
.func 'removeChild' .arg1 '@addref(children |)'static int _Object_removeChild(lua_State *L)
{
...
self->removeChild(arg1);
...
olua_delref(L, 1, "children", -1, OLUA_REF_MULTI);
...
}~
生成使用比较移除引用的代码。-- void removeChildByName(const std::string &name);
typeconf 'Object'
.func 'removeChildByName' .ret '@delref(children ~)'static int _Object_removeChildByName(lua_State *L)
{
...
olua_startcmpref(L, 1, "children");
...
self->removeChildByName(arg1);
...
olua_endcmpref(L, 1, "children");
...
}*
移除所有引用。-- void removeChildren();
typeconf 'Object'
.func 'removeChildren' .arg1 '@delref(children *)'static int _Object_removeChildren(lua_State *L)
{
...
self->removeChildren();
...
olua_delallrefs(L, 1, "children");
...
}
where
引用存储的位置,如果提供此值,同时得使用插入代码,用于获取此值。
-- void removeSelf(); |
static int _Object_removeSelf(lua_State *L) |
关于引用实现参见 olua 引用链
3.17.5. @optional
标记参数是否可选,一般情况下用于 .var
命令,函数参数的 @optional
标记由自动扫描添加。
用于
.var
命令:typeconv 'Object'
.var 'x' .optional 'true'void olua_check_Object(lua_State *L, int idx, Object *value)
{
...
int arg1 = 0; /** x */
...
olua_getfield(L, idx, "x");
if (!olua_isnoneornil(L, -1)) {
olua_check_integer(L, -1, &arg1);
value->x = arg1;
}
lua_pop(L, 1);
...
}用于
.func
命令:-- 原型
-- void play(bool loop = true);
-- 扫描得到
-- void play(@optional bool loop = true);
-- 导出时转换为两个函数
-- void play();
-- void play(bool loop);
typeconf 'Object'static _Object_play1(lua_State *L)
{
...
self->play();
...
}
static _Object_play2(lua_State *L)
{
...
self->play(arg1);
...
}
static _Object_play(lua_State *L)
{
if (num_args == 0) {
reutrn _Object_play1(L);
}
if (num_args == 1) {
reutrn _Object_play2(L);
}
luaL_error(L, "method 'Object::play' not support '%d' arguments", num_args);
return 0;
}
3.17.6. @pack
将多个参数打包一个值对象。
-- void setPosition(const Point &p); |
local obj = Object.new() |
3.17.7. @unpack
将值对象拆解为多个值。
-- const Point &getPosition(); |
local obj = Object.new() |
3.17.8. @readonly
只读变量标记,用于 .var
命令。使用此标记后,只生成 getter
函数。
typeconf 'Object' |
3.17.9. @type
类型替换,提供的类型必须是原类型的其它表现形式。
void read(char *buf, size_t *len); |
正常情况下,buf
会被解析为字符串,使用的转换器是 olua_$$_string
,但是这里可能是一个可写入的变量,这时就可以使用 @type
进行标记,以实现准确的意图。
-- typedef char olua_char_t; |
通过此配置,可以在生成代码时,使用 olua_char_t *
的转换器。
3.17.10. 头文件标注
可以直接使用宏命令对参数或方法进行标注,autoconf
脚本会在扫描阶段解析这些信息。
宏命令:
使用示例:
class Object { |