复杂的库API通常可以使用
SWIG
. 在这种情况下,使用swig的一个优点是,很容易构建基于swig的包装器,以便在
18 major languages
其中包括Lua、Perl、Python、Ruby和Java等。
如果Lua是您的首选(而且可能是唯一的)关注点,那么我建议您学习使用
luaL_register()
在C中构建Lua模块的策略的核心是,通过这种方式构建模块的一个优点是,您可以将所有功能保存在一个单一的名称空间中,而不需要任何开销。您需要创建一个与lua c函数调用约定相匹配的包装函数(正如您使用
lua_register()
)它从栈中收集lua参数,调用包装函数,并将任何返回值和out参数推回到lua栈。关于如何实现这一点的一个很好的概述可以在Lua的编程书中找到。第一版的在线版讨论了图书馆的创建
Chapter 26
但是是为Lua5.0编写的。我强烈敦促任何认真使用Lua的人拥有当前版本的PIL。
不幸的是,Lua5.1与5.0最大的不同之处在于动态加载模块(C和Lua),其中
require
.
下面是一个完整的(如果很小)例子,用于Lua5.1中的C库。我们从实现C文件中的包装开始:
#include <lua.h>
#include <luaxlib.h>
#include <math.h>
#undef PI
#define PI (3.14159265358979323846)
static int l_sin (lua_State *L) {
double r = luaL_checknumber(L,1);
lua_pushnumber(L, sin(r));
return 1;
}
static int l_cos (lua_State *L) {
double r = luaL_checknumber(L,1);
lua_pushnumber(L, cos(r));
return 1;
}
static const struct luaL_reg smlib [] = {
{"sin", l_sin},
{"cos", l_cos},
{NULL, NULL} /* sentinel */
};
int luaopen_sm (lua_State *L) {
luaL_openlib(L, "sm", smlib, 0);
lua_pushnumber(L,PI);
lua_rawset(L,-2,"pi");
return 1;
}
特别注意,唯一需要导出的函数是
luaopen_sm()
,其名称必须与将与一起使用的模块的名称对应
要求
以及dll文件的名称。将该文件编译为一个名为
sm.dll
(可能命名)
libsm.so
在类Unix系统上),然后可以像下面这样加载和使用lua脚本:
require "sm"
print(sm.sin(sm.pi/3), sm.cos(sm.pi/3));
这个示例虽然没有经过测试,但应该编译并运行。对于一个完整的示例,包装来自
math.h
,请参见
source to the
math
module
与Lua一起分发。因为这些薄包装器包含大量重复的代码,所以像swig这样的工具通常能够在只声明每个函数的情况下创建它们。
C++类的包装方法在原理上是相似的。每个Lua可调用包装函数都需要一个可以映射到
this
在C++侧,它必须实现为模块静态函数或静态成员函数,该函数还定位目标对象实例以及转换其他参数。Swig特别擅长构建这种包装,一路上隐藏了许多血淋淋的细节。