我目前正在将 Lua 实现到我正在开发的应用程序之一中。目前我只是使用 C api 并使用 lua_register 注册函数,但我希望能够将静态和非静态函数指针传递给某些类方法。
我在网上找到了某些库,但是由于我需要它们提供的整体功能很少,我想知道是否有一种简单的方法可以做到这一点。
谢谢你。
复杂的库 API 通常可以使用SWIG快速和(几乎)完全包装。在这种情况下使用 SWIG 的一个优势是可以轻松构建基于 SWIG 的包装器,从而可以在18 种主要语言中使用该库,包括 Lua、Perl、Python、Ruby 和 Java 等。
如果 Lua 是您的首选(并且可能是唯一)关注点,那么我建议学习使用luaL_register()
C 语言构建 Lua 模块的策略的核心。以这种方式构建模块的一个优点是您可以将所有功能保留在没有任何开销的单个名称空间。您将需要制作一个与 Lua C 函数调用约定相匹配的包装函数(就像您对lua_register()
.堆。可以在《Lua 编程》一书中找到有关如何进行此操作的一个很好的概述。第一版的在线副本在第 26 章讨论了图书馆的创建,但是是为 Lua 5.0 编写的。我强烈敦促任何认真使用 Lua 的人拥有当前版本的 PiL 的副本。
不幸的是,Lua 5.1 与 5.0 最大不同的一个领域是使用require
.
这是在 Lua 5.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()
,其名称必须对应于将与 一起使用的模块require
的名称,以及 DLL 文件的名称。将该文件编译为名为sm.dll
(可能libsm.so
在类 Unix 系统上命名)的 DLL,然后可以在 Lua 脚本中加载和使用,如下所示:
需要“sm” 打印(sm.sin(sm.pi/3),sm.cos(sm.pi/3));
此示例虽然未经测试,但应该可以编译和运行。有关包装大多数函数的完整示例math.h
,请参阅与 Lua 一起分发的模块的源代码。math
因为这些瘦包装器包含大量重复代码,所以像 SWIG 之类的工具通常能够在仅给出每个函数的声明的情况下创建它们。
C++ 类的包装方法原则上是类似的。每个 Lua 可调用的包装函数都需要一个可以this
在 C++ 端映射的参数,并且它必须实现为模块静态函数或静态成员函数,该函数还定位目标对象实例并转换其他论点。SWIG 特别擅长构建这种包装器,并在此过程中隐藏了很多血腥的细节。