代码之家  ›  专栏  ›  技术社区  ›  Charles

Lua脚本实现

  •  4
  • Charles  · 技术社区  · 15 年前

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

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

    谢谢您。

    1 回复  |  直到 15 年前
        1
  •  4
  •   RBerteig Keith Adler    15 年前

    复杂的库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特别擅长构建这种包装,一路上隐藏了许多血淋淋的细节。