【问题标题】:How do you load a custom module into Lua?如何将自定义模块加载到 Lua 中?
【发布时间】:2016-12-10 02:16:20
【问题描述】:

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

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

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

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

我知道这些类型的问题在这里被问得相当频繁(如this answer 中所述),但我仍然不知所措。我尝试了一些绑定包(Luabind 和 OOLua),但效果不佳(例如我的 earlier question——我最终弄明白了,有点)。

  1. 我已经用 C++ 实现了一个类
  2. 我已经用 thunk 包装了构造函数、析构函数和函数
  3. 我已经将它构建为一个共享库,并且没有错误

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


函数库的工作示例

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

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

libluatest.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.so”加载模块“libmyObj”时出错: ./libmyObj.so:未定义符号:_ZN5MyObjC1Ev 堆栈回溯:[C]: ? [C]:在函数'require'中标准输入:1:在主块中[C]:?


我在 Ubuntu 14.04 上处理 Lua 5.1。

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

【问题讨论】:

  • 感谢您发布一些有用的东西,您能否发布一些失败的东西,也许我们可以看到您的问题是什么?
  • @dave:完成。也许不相关,我确实不喜欢没有评论就投反对票的做法......没有人会这样
  • 您能否添加编译上述失败示例时遇到的确切错误?究竟哪些符号未定义?
  • @harmic:将其添加到 OP。当我运行 nm -g libmyObj.so 时,会出现那个符号 _ZN5MyObjC1Ev
  • (Unrelated:) 你想要像luaT_checkudata 这样的东西,至少来自 C。从 C++ 开始,大部分 Lua API 都有未定义的行为,你需要非常小心。

标签: c++ lua


【解决方案1】:
  1. 你好像没有实现:

    MyObj() ; ~MyObj();

  2. 注意luaopen_*函数,因为模块名是myObj,函数名应该是luaopen_libmyObj

【讨论】:

  • 哎呀,到#2,这是正确的。我正在概括我的文件名,但忘记将其从我的项目名称更改为 myObj。我已经编辑了 OP,但无论如何,这是一个很好的说明,请保留在您的答案中。
猜你喜欢
  • 1970-01-01
  • 2022-01-18
  • 2019-03-22
  • 2021-07-15
  • 1970-01-01
  • 2013-08-02
  • 2012-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多