原文地址: http://www.codenix.com/~tolua/tolua++.html
译者注:在网上貌似没有对应的tolua中文版文档,故心血来潮,翻译了第一部分:tolua使用。第一次翻译,出了很多错误。可能还潜在很多的错误,建议和原版一起阅读。如果有错误,希望各位看官指出,谢谢。
Tolua++是tolua的升级版,是把C/C++和lua代码结合使用的一种工具。tolua++包括一些来自C++的新功能,如:
- 支持std::string,并将其作为一种基本类型
- 支持class template
当然,还有一些新的特点和bug的修复。
Tolua的使用大大简化了C/C++和lua的代码一体化。基于干净的头文件(或者扩展的头文件),tolua会自动生成相关的代码供lua访问C/C++使用。
使用Lua的API和标记方法(tag method facilities),tolua可以把C/C++里的常数,变量,函数,类和方法映射到lua。
这本手册是tolua++ 1.0版本,针对Lua5.0以上,基于tolua5.0。如果使用旧版本,请查看兼容性的详细资料。
以下各节描述如何使用tolua 。如果你发现错误,或者有建议和意见,请与我们联系。
How tolua works
要使用tolua,我们需要创建package文件,C/C++干净的头文件(cleaned header file),只列出所有我们希望暴露给lua使用的常数,变量,函数,类和方法。然后tolua剖析这个文件,并自动创建C / C + +文件,该文件会自动把C/C++的代码绑定到Lua。当我们的程序链接到这个文件时,我们就能从Lua访问对应的C/C++代码。
Package文件可以包括常规头文件,其他Package文件,以及lua文件。
让我们先以一些例子。如果我们指定下列C头文件输入到tolua:
#define FALSE 0
#define TRUE 1
enum {
POINT = 100,
LINE,
POLYGON
}
Object* createObejct (int type);
void drawObject (Object* obj, double red, double green, double blue);
int isSelected (Object* obj);
这段代码绑定到Lua,会自动生成一个C文件。因此,在Lua代码里,我们能够访问对应的C代码,例如(writing, for instance:):
...
myLine = createObject(LINE)
...
if isSelected(myLine) == TRUE then
rawObject(myLine, 1.0, 0.0, 0.0);
else
rawObject(myLine, 1.0, 1.0, 1.0);
end
...
另外,考虑一个C++头文件:
#define FALSE 0
#define TRUE 1
class Shape
{
void draw (void);
void draw (double red, double green, double blue);
int isSelected (void);
};
class Line : public Shape
{
Line (double x1, double y1, double x2, double y2);
~Line (void);
};
如果这个文件是用来加载到tolua的,一个C++文件会自动生成,为Lua提供访问对应代码。因此,以下的Lua代码是有效的:
...
myLine = Line:new (0,0,1,1)
...
if myLine:isSelected() == TRUE then
myLine:draw(1.0,0.0,0.0)
else
myLine:draw()
end
...
myLine:delete()
...
Package文件传给tolua的不是真正的C/C++头文件,而是一种干净的版本(cleaned version)。Tolua并不执行一个完整的剖析解释的C/C++代码,只是解析一些声明,用来描述暴露给lua功能的声明(it understands a few declarations that are used to describe the features that are to be exported to Lua.)。
通常头文件可以包括进packages文件里,tolua会提取对应的代码用于解析对应的头文件(see Basic Concepts).。
How to use toLua
Tolua由两部分代码组成:可执行程序和静态库(an executable and a library)。可执行程序用于解析,从package文件读入,然后输出C/C++代码,该代码为lua提供访问C/C++的方法。如果package文件是与C++类似的代码(例如包括类的定义),就会生成一份C++代码。如果package文件是与C类似的代码(例如不包括类),就会生成一份C代码。Tolua接收一系列选择(tolua accepts a set of options)。运行“tolua -h”显示当前可接收的选择。例如,要解析一个名为myfile.pkg生成一个名为myfile.c的捆绑代码,我们需要输入:
tolua -o myfile.c myfile.pkg
产生的代码必须被应用程序生成和链接,才能提供给Lua进行访问。每个被解析的文件会生成一个package暴露给Lua。默认情况下,软件包的名称是根输入文件名称( myfile的例子),用户可以指定一个不同的名称给package:
tolua -n pkgname -o myfile.c myfile.pkg
package还应当明确初始化。我们需要声明和调用初始化函数,从化我们的C/C++代码初始化package。初始化函数被定义为:
int tolua_pkgname_open (lua_State*);
其中pkgname是被绑定package的名字。如果我们使用的是C++,我们可以选择自动初始化:
tolua -a -n pkgname -o myfile.c myfile.pkg
在这种情况下,初始化函数会自动调用。然而,如果我们计划使用多个Lua,自动初始化就行不通了,因为静态变量初始化的顺序在C++里没有定义。
Optionally, the prototype of the open function can be outputted to a header file, which name is given by the -H option.
Tolua生成的绑定代码使用了一系列tolua库里面的函数。因此,这个库同样需要被链接到应用程序中。同样,tolua.h需要加入编译生成代码。应用程序无需绑定任何package文件也可以使用tolua的面向对象框架(see exported utility functions)。在这种情况下,应用程序必须调用tolua初始化函数(此函数被称为任何package文件初始化功能) :
int tolua_open (void);
Basic Concepts
第一步是使用tolua创建package文件。从真正的头文件开始,我们重新将想要暴露给lua的特性转换成tolua可以理解的格式。
Including files
一个package文件可以包括其他的package文件。一般的格式是:
$pfile "include_file"
一个package文件同样可以包括一般的C/C++头文件,使用hfile或cfile指令:
$cfile "example.h"
在这种情况下, tolua将提取的代码封闭之间tolua_begin和tolua_end ,或tolua_export的一条直线上。以这个C++头为例思考:(注:这里并不是每个头文件都需要使用这些注释来告诉tolua要加入这些代码,仅仅是对于package文件包括的头文件而言)
#ifndef EXAMPLE_H
#define EXAMPLE_H
class Example { // tolua_export
private:
string name;
int number;
public:
void set_number(int number);
//tolua_begin
string get_name();
int get_number();
};
// tolua_end
#endif
In this case, the code that's not supported by tolua (the private part of the class), along with the function set_number is left outside of the package that includes this header.
最后,lua文件可以被包括在package文件里,使用$lfile:
$lfile "example.lua"
新的tolua++:自1.0.4版本以来的tolua++,提供了一个额外的方式可以包括源文件,使用ifile:
$ifile "filename"
ifile还额外的可选参数后的文件名(ifile also takes extra optional parameters after the filename),例如:
$ifile "widget.h", GUI
$ifile "vector.h", math, 3d
ifile的默认行为是包括整个文件的原样。但是,该文件的内容和额外的参数在被纳入package之前通过include_file_hook函数进行处理 (see Customizing tolua++ for more details)。