【问题标题】:Lua crases when loading dll extension加载 dll 扩展时 Lua 崩溃
【发布时间】:2017-01-16 19:57:26
【问题描述】:

我正在尝试在 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)) --should print 10

但是,当我实际尝试运行 Lua 代码时,它会在 require "mylib" 行崩溃。 DLL 能够打印“一”和“二”,但在崩溃之前无法打印“三”。这告诉我问题可能出在“lua_setglobal”调用上。

怎么了?如何进一步调试或修复它?

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

谢谢!

【问题讨论】:

  • 什么样的崩溃?它会从 Lua 生成堆栈跟踪吗? C 段错误?
  • @Oka 我收到一条 Windows 弹出消息“lua.exe 已停止工作”它有更多详细信息,但对我来说没有任何意义。
  • 我不是 Windows 开发人员,但这些细节可能对某些人来说很重要。在寻求帮助时包含错误消息/报告通常是个好主意。
  • 你为什么尝试使用 cdecl?你试过 stdcall 了吗?
  • @moteus 我从这里得到了__cdecllua-users.org/wiki/LoadLibrary 将其更改为__stdcall 使其显示“找不到指定的过程”。在 'require()' 调用中。

标签: c windows dll lua


【解决方案1】:

我编译了你的代码,它工作正常。所以你的问题不在于你的代码。我的猜测是您使用的是不同版本的 Lua,或者链接出了点问题。

可能在三个地方出现版本不匹配。

  1. 在您的#include &lt;lua.h&gt; 行中
  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)) --should print 10

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多