Lua脚本实现

发布于 2024-08-01 21:52:22 字数 181 浏览 4 评论 0原文

我目前正在致力于将 Lua 实现到我正在开发的应用程序之一中。 目前我只是使用 C api 并使用 lua_register 注册函数,但我希望能够将静态和非静态函数指针传递给某些类方法。

我在网上找到了某些库,但由于我只需要很少的它们提供的整体功能,我想知道是否有一种简单的方法可以做到这一点。

谢谢。

I'm currently working on implementing Lua into one of the applications that I'm working on. Currently I'm just using the C api and registering functions using lua_register, but I'd like to be able to pass static and non static function pointers to certain class methods.

I've found certain libraries on the net, but since I need very little of the overall functionality they provide I was wondering if there's an easy way to do this.

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

酷炫老祖宗 2024-08-08 21:52:22

复杂的库 API 通常可以使用 SWIG 快速且(几乎)完全地包装。 在这种情况下使用 SWIG 的一个优点是,可以轻松构建基于 SWIG 的包装器,从而可以在 18 种主要语言,包括 Lua、Perl、Python、Ruby 和 Java 等。

如果 Lua 是您首选(也可能是唯一)关注的问题,那么我建议您学习使用 luaL_register() 是用 C 语言构建 Lua 模块的策略的核心。以这种方式构建模块的优点是可以将所有函数保存在一个名称空间中没有任何开销。 您需要制作一个与 Lua C 函数调用约定相匹配的包装函数(就像使用 lua_register() 一样),并从堆栈中收集 Lua 参数、调用包装函数并推送任何返回值和输出参数返回Lua堆栈。 有关如何进行此操作的详细概述可以在《Lua 编程》一书中找到。 第一版的在线副本在第 26 章中讨论了库的创建,但是是为卢阿5.0。 我强烈建议任何认真使用 Lua 的人都拥有一份最新版本的 PiL。

不幸的是,Lua 5.1 与 5.0 最大的不同之处在于使用 require 动态加载模块(C 和 Lua)。

这是一个在 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 脚本中加载和使用它,例如this:

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

此示例虽然未经测试,但应该可以编译并运行。 有关包装 math.h 中大多数函数的完整示例,请参阅 与 Lua 一起分发的 math 模块的源代码。 由于这些薄包装器包含大量重复代码,因此 SWIG 等工具通常只需给出每个函数的声明即可创建它们。

C++ 类的包装方法原则上类似。 每个 Lua 可调用的包装函数都需要一个可以在 C++ 端映射到 this 的参数,并且它必须实现为模块静态函数或静态成员函数,该函数也可以定位目标对象实例以及转换其他参数。 SWIG 特别擅长构建这种包装器,并在此过程中隐藏了许多血淋淋的细节。

A complex library API can often be wrapped quickly and (nearly) completely using SWIG. An advantage of using SWIG in this case is that it is easy to build SWIG-based wrappers that enable use of the library in 18 major languages including Lua, Perl, Python, Ruby, and Java, among others.

If Lua is your preferred (and possibly only) concern, then I'd recommend learning to use luaL_register() at the core of a strategy to build Lua modules in C. An advantage of building a module this way is that you keep all of your functions in a single name space without any overhead. You will need to craft a wrapper function that matches the Lua C function calling convention (just as you do with lua_register()) and that gathers the Lua arguments from the stack, calls the wrapped function, and pushes any return value and out parameters back to the Lua stack. A good overview of how to go about this can be found in the book Programming in Lua. The online copy of the first edition discusses library creation in Chapter 26, but was written for Lua 5.0. I strongly urge anyone seriously using Lua to own a copy of the current edition of PiL.

Unfortunately, one area where Lua 5.1 differs the most from 5.0 is in the dynamic loading of modules (both C and Lua) with require.

Here's a complete (if small) example for a C library that works in Lua 5.1. We start with the implementation of the wrapper in a C file:

#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;
}

Note in particular that the only function that need be exported is luaopen_sm(), whose name must correspond to the name of the module that will be used with require, and with the name of the DLL file. With that file compiled as a DLL named sm.dll (probably named libsm.so on Unix-like systems), then it can be loaded and used in a Lua script like this:

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

This example, although untested, should compile and run. For a complete example wrapping most functions from math.h, see the source to the math module that is distributed with Lua. Because these thin wrappers contain a lot of repetitive code, tools like SWIG are often able to create them given only the declaration of each function.

Wrapping methods of a C++ class is similar in principle. Each Lua-callable wrapper function is going to need an argument that can be mapped into this on the C++ side, and it must be implemented as either a module-static function or static member function that also locates the target object instance as well as converts the other arguments. SWIG is particularly good at constructing this kind of wrapper and hides a lot of gory details along the way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文