【发布时间】: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——我最终弄明白了,有点)。
- 我已经用 C++ 实现了一个类
- 我已经用 thunk 包装了构造函数、析构函数和函数
- 我已经将它构建为一个共享库,并且没有错误
然而,当我尝试将其加载为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 都有未定义的行为,你需要非常小心。