Lua 5.2 C API和要求

dav*_*ave 6 c lua yaml

问题

我想从一个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
Run Code Online (Sandbox Code Playgroud)


问题

我写了一个C程序应该调用hello()从脚本,下面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;
}
Run Code Online (Sandbox Code Playgroud)

我编译发行:

gcc -Wall -o foo foo.c -ldl -lm -llua
Run Code Online (Sandbox Code Playgroud)

然后在运行时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
Run Code Online (Sandbox Code Playgroud)

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

luaL_requiref(L, "lyaml", luaopen_package, 1);
Run Code Online (Sandbox Code Playgroud)

重新编译后,错误变为:

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

所以我想,没有lyaml符号,require()呼叫以某种方式失败.

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

void luaL_requiref (lua_State *L, const char *modname, 
                    lua_CFunction openf, int glb);
Run Code Online (Sandbox Code Playgroud)

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

如果glb为true,则还将结果存储到global中modname.
将该结果的副本留在堆栈上.

我试图require()用Lua脚本来评论这个调用,结果是一样的.

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


编辑

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

lua_strlen() -> luaL_len()
luaL_reg     -> luaL_Reg
luaL_getn()  -> luaL_len()
Run Code Online (Sandbox Code Playgroud)

然而Lua脚本使用lyaml工作,所以我认为问题不是我的黑客.

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

UPDATE

根据Doug Currie的回答,添加以下行,C程序与Lua 5.1完美配合.我仍然在5.2中得到相同的错误.

lyaml = require('lyaml')
Run Code Online (Sandbox Code Playgroud)

Dou*_*rie 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')
Run Code Online (Sandbox Code Playgroud)


dav*_*ave 5

我解决了......所有问题的根源都是使用不当luaL_requiref().

阅读这篇帖子我得到了这个后续的启发:

在Lua 5.2中,库不再创建全局变量; 他们只是返回图书馆表.

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

所以有必要调用luaL_requiref()加载模块并设置lyaml全局.

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

luaL_requiref(L, "lyaml", luaopen_package, 1);
Run Code Online (Sandbox Code Playgroud)

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

luaL_requiref(L, "lyaml", luaopen_lyaml, 1);
Run Code Online (Sandbox Code Playgroud)

并编译

gcc -L/path/to/5.2 -Wall -o foo foo.c -ldl -lm -llua -l:lyaml.so.1
Run Code Online (Sandbox Code Playgroud)

获得参考luaopen_lyaml().


在Lua 5.1中,正如Doug Currie所说,它足以发布

lyaml = require('lyaml')
Run Code Online (Sandbox Code Playgroud)

hello.lua,没有调用luaL_requiref()C程序.