我想从C程序中调用一个Lua脚本require()
lyaml
模块,Lua绑定LibYAML。
我从源代码编译了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
我写了一个C程序,应该在Programming in Lua, Chapter 25和Lua 5.2 Reference Manual之后从脚本中调用hello()
。
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
所以我尝试从C程序加载lyaml
,在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为true,则还将结果存储到全局modname
中 将该结果的副本留在堆栈中。
我尝试在Lua脚本中评论require()
调用,结果是一样的。
我做错了什么?我忘了做某事吗?
我用其替代品破解了模块更新已弃用(已删除)的函数/类型,如下所示:
lua_strlen() -> luaL_len()
luaL_reg -> luaL_Reg
luaL_getn() -> luaL_len()
然而,使用lyaml
的Lua脚本工作,所以我认为问题不是我的黑客。
我尝试使用Lua 5.1创建原始lyaml
模块。结果是一样的,所以我确定问题不是我的黑客。
根据Doug Currie的回答,添加以下行,C程序与Lua 5.1完美配合。我仍然在5.2中得到同样的错误。
lyaml = require('lyaml')
答案 0 :(得分:6)
foo.lua
只会在Lua 5.1.x中运行 - 您的被黑色lyaml.c
未设置全局lyaml
,并且在Lua 5.2中也不需要。我怀疑你的PATH没有Lua 5.2,当你运行第一个测试“就像魅力一样”时,或者你在加载lyaml
之前手动设置foo.lua
。
foo.lua
应以
lyaml = require('lyaml')
答案 1 :(得分:5)
我解决了......所有问题的根源都是对luaL_requiref()
的错误使用。
阅读this thread我受到了这次跟进的启发:
在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')
<{1>}中的,未在C程序中调用hello.lua
。