如何将自定义模块加载到Lua中

How do you load a custom module into Lua?

本文关键字:Lua 加载 模块 自定义      更新时间:2023-10-16

这已经让我抓狂很长时间了。我遵循了我在互联网上能找到的每一个教程(以下是通过谷歌搜索找到的六个好教程中的几个例子[1],[2]),但仍然没有明确的解释。尽管这看起来一定很简单,因为缺乏书面解释意味着这是大多数人认为理所当然的事情。

如何将自定义模块加载到Lua中

根据这类问题的建议,我编写了一个模块,该模块构建了一个共享库,希望能够通过require调用加载它。然而,当我这样做的时候,我会得到未定义的符号错误,尽管这些确切的符号出现在命令nm -g mylib.so的列表中。

我之前链接的这两个教程旨在创建看起来像*.lua文件包装器的可执行文件。也就是说,应该调用构建的*.exe文件来运行带有自定义模块的Lua程序。

我知道这些类型的问题在这里被问得相当频繁(正如这个答案中所指出的),但我仍然不知所措。我尝试了一些绑定包(Luabind和OOLua),但效果并不好(例如,我之前的问题——我最终解决了)。

  1. 我已经用C实现了一个类++
  2. 我已经用thunk包装了构造函数、析构函数和函数
  3. 我把它建成了一个共享图书馆

然而,无论发生什么,当我尝试将其加载为mod = require('mylib.so')时,都会出现undefined symbol: ...错误。我该怎么做?


函数库的工作示例

记录在案,只需注册一个基本函数就可以了。当构建为libluatest.so时,可以使用以下命令在Lua中运行以下代码:

> require('libluatest')
> greet()
hello world!

libimulatest.cpp

extern "C"
{
    #include <lualib.h>
    #include <lauxlib.h>
    #include <lua.h>
}
#include <iostream>
static int greet(lua_State *L)
{
    std::cout << "hello world!" << std::endl;
    return 0;
}
static const luaL_reg funcs[] =
{
    { "greet", greet},
    { NULL, NULL }
};

extern "C" int luaopen_libluatest(lua_State* L) 
{
    luaL_register(L, "libluatest", funcs);
    return 0;
}

类的失败示例

这就是我目前所坚持的。它似乎不起作用。

myObj.h

#include <string>
class MyObj
{
    private:
            std::string name_;
    public:
            MyObj();
            ~MyObj();
            void rename(std::string name);
};

myObj.cpp

extern "C"
{
    #include <lualib.h>
    #include <lauxlib.h>
    #include <lua.h>
}
#include <iostream>
#include "myObj.h"
void MyObj::rename(std::string name)
{
    name_ = name;
    std::cout << "New name: " << name_ << std::endl;
}
extern "C"
{
    // Lua "constructor"
    static int lmyobj_new(lua_State* L)
    {
            MyObj ** udata = (MyObj **)lua_newuserdata(L, sizeof(MyObj));
            *udata = new MyObj();
            luaL_getmetatable(L, "MyObj");
            lua_setmetatable(L, -1);
            return 1;
    }
    // Function to check the type of an argument
    MyObj * lcheck_myobj(lua_State* L, int n)
    {
            return *(MyObj**)luaL_checkudata(L, n, "MyObj");
    }
    // Lua "destructor": Free instance for garbage collection
    static int lmyobj_delete(lua_State* L)
    {
            MyObj * obj = lcheck_myobj(L, 1);
            delete obj;
            return 0;
    }
    static int lrename(lua_State* L)
    {
            MyObj * obj = lcheck_myobj(L, 1);
            std::string new_name = luaL_checkstring(L, 2);
            obj->rename(new_name);
            return 0;
    }
    int luaopen_libmyObj(lua_State* L)
    {
            luaL_Reg funcs[] =
            {
                    { "new", lmyobj_new }, // Constructor
                    { "__gc", lmyobj_delete }, // Destructor
                    { "rename", lrename }, // Setter function
                    { NULL, NULL } // Terminating flag
            };
            luaL_register(L, "MyObj", funcs);
        return 0;
    }
}

使用在.上带有C++11标准标志的简单CMake构建编译为libmyObj.so

错误

> require('libmyObj')

从文件"加载模块"libmyObj"时出错/libmyObj.so':./libmyObj.so:未定义的符号:_ZN5MyObjC1Ev堆栈回溯:[C]:?[C] :在函数"require"中stdin:1:在主区块[C]中:?


我正在处理Ubuntu 14.04上的Lua 5.1。

我想知道这是否与C和C++的混合有关。。。

  1. 似乎你没有实现:

    MyObj() ; ~MyObj();

  2. 注意luaopen_*函数,由于模块名称为myObj,因此函数名称应为luaopen_libmyObj