Lua脚本实现

我目前正在把 Lua 集成到我的某个应用程序中。目前,我只是使用 C API 和 lua_register 注册函数,但我想要能够将静态和非静态函数指针传递给某些类方法。

我在网上找到了一些库,但由于我只需要它们提供的非常少的功能,所以我想知道是否有一种简单的方法来实现它。

谢谢。

原文链接 https://stackoverflow.com/questions/1281972

点赞
stackoverflow用户68204
stackoverflow用户68204

使用 SWIG 包装 C 库 API

一个复杂的库 API 经常可以使用 SWIG 快速包装(近乎完全地)。在这种情况下使用 SWIG 的一个优点是可以很容易地构建基于 SWIG 的包装器,使得库在 18 种主要语言 中可以使用,包括 Lua、Perl、Python、Ruby 和 Java 等。

如果 Lua 是您首选的(甚至是唯一的)选择,那么我建议您学习使用luaL_register() 来作为构建 C 语言模块策略的核心。通过这种方式构建模块的一个好处是,您可以在一个命名空间中保留所有函数,而没有额外的开销。您需要编写一个包装器函数,以匹配 Lua C 函数调用约定(就像 lua_register() 一样),并从堆栈中获取 Lua 参数,调用包装函数,将任何返回值和输出参数推回到 Lua 堆栈中。在书籍《Programming in Lua》中,可以找到有关如何构建这个函数的概述。第一版的在线副本在第 26 章中讨论了库的创建,但是是为 Lua 5.0 编写的。我强烈建议所有严肃使用 Lua 的人拥有当前版本的《PiL》。

不幸的是,在模块(包括 C 和 Lua)动态加载时,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 的 DLL(在类 Unix 系统中可能命名为 libsm.so)后,可以像这样在 Lua 脚本中加载并使用它:

require "sm"
print(sm.sin(sm.pi/3), sm.cos(sm.pi/3));

这个示例虽然未经测试,但应该可以编译并运行。有关包装来自 math.h 的大多数函数的完整示例,请参见随 Lua 分发的 源代码 math 模块。由于这些薄包装器包含大量重复的代码,因此像 SWIG 这样的工具通常可以仅根据每个函数的声明来创建它们。

在原则上,包装 C++ 类的方法是类似的。每个可在 Lua 中调用的包装器函数都需要一个可以映射到 C++ 一侧的 this 参数,并且必须作为模块静态函数或静态成员函数实现,也相应地定位目标对象实例以及转换其他参数。SWIG 在构建这种包装器方面特别优秀,并在整个过程中隐藏了很多恶心的细节。

2009-08-17 20:04:42