Lua加载dll扩展时崩溃

我正在尝试在Windows上创建Lua dll扩展。我正在使用Lua 5.3。我的编译器是来自MinGW的gcc 4.9.3。

我的dll扩展的C代码类似于这样:

#include <stdio.h>
#include <lua.h>

static int dub(lua_State *L) {
    const double a = lua_tonumber(L, 1);
    lua_pushnumber(L, a*2);
    return 1;
}

__declspec(dllexport) int __cdecl luaopen_mylib(lua_State *L){
    printf("One\n");
    lua_pushcfunction(L, dub);
    printf("Two\n");
    lua_setglobal(L, "dub");
    printf("Three\n");
    return 1;
}

我这样编译我的dll:

gcc mylib.c -shared -o mylib.dll -llua

想法是我可以从Lua中加载它并像这样使用它:

require "mylib"
print (dub(5)) --应该打印10

但是,当我实际尝试运行Lua代码时,在require "mylib"行上崩溃了。 DLL能够打印“One”和“Two”,但在崩溃之前无法打印“Three”。这告诉我问题可能与'lua_setglobal'调用有关。

出了什么问题?我如何进一步调试或修复它?

作为一个额外的问题:luaopen_mylib的返回值应该是什么?

谢谢!

点赞
用户6811384
用户6811384

我编译了你的代码并且它很好地工作了。所以你的问题不是来自你的代码。我的猜测是你正在使用不同版本的Lua,或者链接出现了问题。

三个可能出现版本不匹配的地方如下:

  1. 在你的 #include <lua.h> 行中
  2. 在你的编译行中使用了 -llua
  3. 当你运行 lua 可执行文件时

这三个必须是相同的Lua版本。如果其中一个不匹配,那就可能会导致你遇到的问题。我猜测你的Lua可执行文件版本与其他版本不匹配。

另一个需要尝试的方法是,你的dll库应该链接到Lua的dll库。你的系统上应该有一个名为 lua53.dll 的文件。将它复制到你的构建目录中。当你用 gcc 编译时,试着这样做:

gcc mylib.c -shared -o mylib.dll lua53.dll

这意味着你的dll扩展调用的正是Lua可执行文件使用的完全相同的Lua代码。现在你的方式,使用 -llua 行,看起来你正在静态链接Lua。这几乎永远不是dll库中想要的,因为Lua可执行文件将调用 lua53.dll 中的代码,而你的dll库将调用静态库中的不同代码。我不认为仅仅这样会导致你的崩溃,但这不是很好的做法。如果Lua使用的是全局状态(它没有这样做),这个链接问题肯定会导致崩溃。此外,如果你编译成 lua53.dll,你会发现 mylib.dll 更小。

_总之_,我认为你的Lua版本在某个地方不匹配,导致了你的崩溃。你还应该链接到Lua的dll库,而不是静态库,以符合良好的规范。

顺带一提的问题:luaopen_mylib 的返回值应该是什么?

在你的代码中,它实际上应该是 0 而不是 1。返回值是你希望 require() 调用返回的栈上剩余的元素数。你的库只是将自己塞入全局状态中,不返回任何Lua值。一个替代的方法是返回一个包含库函数的表。这样你就不会污染全局状态了。由于你的库只有一个函数,你可以像这样直接返回它:

__declspec(dllexport) int __cdecl luaopen_mylib(lua_State *L){
    lua_pushcfunction(L, dub);
    return 1;
}

然后你可以像这样从Lua中使用它:

local dub = require("mylib")
print (dub(5)) --应该打印10

我更喜欢这种方法,因为调用者可以决定导入的名称,它不会污染全局空间。

2016-09-08 23:34:13