6

问题

我想从一个 C 程序调用一个 Lua 脚本,它require()是一个lyaml模块,用于 LibYAML 的 Lua 绑定。

我从源代码编译了 Lua 5.2,并破解了模块以使其与 Lua 5.2 一起使用。它可以在github上找到。

下面是 Lua 脚本,它适用于 Lua 5.1 和 5.2:

-- foo.lua
require('lyaml')

function hello ()
  res = lyaml.load("a: 4\n")
  return res.a
end

-- then calling hello() it works like a charm
print( hello() ) -> 4


问题

hello()我编写了一个应该从脚本调用的 C 程序,遵循《Lua 编程》第 25 章和Lua 5.2 参考手册

C程序如下:

/* foo.c */
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

int main(void)
{
  double z;

  lua_State *L = luaL_newstate();
  luaL_openlibs(L);

  if (luaL_dofile(L, "foo.lua"))
    luaL_error(L, "error running script: %s", lua_tostring(L, -1));

  lua_getglobal(L, "hello");

  if (lua_pcall(L, 0, 1, 0) != 0)
    luaL_error(L, "error calling hello: %s", lua_tostring(L, -1));

  if (!lua_isnumber(L, -1))
    luaL_error(L, "result must be number");        

  z = lua_tonumber(L, -1);
  lua_pop(L, 1);

  lua_close(L);
  return 0;
}

我编译发行:

gcc -Wall -o foo foo.c -ldl -lm -llua

然后在运行时foo,我在运行时收到以下错误:

PANIC: unprotected error in call tu Lua API (
    error running script: error loading module 'lyaml' from file '/path/to/lyaml.so':
       /path/to/lyaml.so: undefined symbol: lua_gettop)
Aborted

所以我尝试lyaml从 C 程序加载,在调用后添加以下行luaL_openlibs()

luaL_requiref(L, "lyaml", luaopen_package, 1);

重新编译后错误变为:

PANIC: unprotected error in call tu Lua API (
    error running script: 
       hello.lua:4: attempt to index global 'lyaml' (a nil value))
Aborted

所以我想没有lyaml符号,require()调用以某种方式失败。

通过阅读luaL_requiref()文档,我认为modname将其调用设置glb标志设置为 true:

void luaL_requiref (lua_State *L, const char *modname, 
                    lua_CFunction openf, int glb);

openf使用字符串modname作为参数调用函数并将调用结果设置在 中package.loaded[modname],就好像该函数已通过 调用一样require

如果 glb 为真,也将结果存储到 globalmodname中。
在堆栈上留下该结果的副本。

我试图require()在 Lua 脚本中注释调用,结果是一样的。

问题

我做错什么了?我忘记做某事了吗?


编辑

我破解了模块更新已弃用(已删除)的功能/类型及其替代品,如下所示:

lua_strlen() -> luaL_len()
luaL_reg     -> luaL_Reg
luaL_getn()  -> luaL_len()

然而 Lua 脚本使用lyaml工作所以我认为问题不是我的 hack。

我尝试lyaml使用 Lua 5.1 的原始模块。结果是一样的,所以我确定问题不是我的黑客。

更新

添加以下行,正如 Doug Currie 在他的回答中所建议的那样,C 程序与 Lua 5.1 完美配合。不过,我在 5.2 中仍然遇到同样的错误。

lyaml = require('lyaml')
4

2 回答 2

6

foo.lua所写的将仅在 Lua 5.1.x 中运行——您的 hackedlyaml.c不会设置全局lyaml,在 Lua 5.2 中也不需要。我怀疑当您运行第一个测试“就像魅力一样”时,您的 PATH 没有 Lua 5.2,或者您lyaml在加载之前手动设置foo.lua

foo.lua应该从

lyaml = require('lyaml')
于 2012-07-14T19:36:16.437 回答
5

我解决了...所有问题的根源是luaL_requiref().

阅读此主题后,我受到了后续的启发:

在 Lua 5.2 中,库不再创建全局变量;他们只是归还图书馆桌子。

luaL_openlibs调用luaL_requiref而不是调用luaopen_*,并luaL_requiref设置相应的全局变量。

所以需要调用luaL_requiref()来加载模块并设置lyaml全局。

正如我尝试使用的问题中所述

luaL_requiref(L, "lyaml", luaopen_package, 1);

但这是完全错误的,因为luaopen_package()是 Lua 标准package模块的加载器功能......我不得不改用:

luaL_requiref(L, "lyaml", luaopen_lyaml, 1);

并编译

gcc -L/path/to/5.2 -Wall -o foo foo.c -ldl -lm -llua -l:lyaml.so.1

获取对luaopen_lyaml().


在 Lua 5.1 中,正如 Doug Currie 所说,发布就足够了

lyaml = require('lyaml')

in hello.lua,不调用luaL_requiref()C 程序。

于 2012-07-15T16:22:22.053 回答