6

問題

LibYAML の Lua バインディング モジュールでrequire()あるLua スクリプトを C プログラムから呼び出したい。lyaml

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


問題

Programming in Lua, Chapter 25およびLua 5.2 Reference Manualhello()に従って、スクリプトから呼び出す C プログラムを作成しました。

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()呼び出しが何らかの形で失敗すると思います。

ドキュメントを読んで、フラグをtrueに設定する呼び出しによって設定されるluaL_requiref()と思いました:modnameglb

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

openf文字列を引数として関数を呼び出し、その関数が を介して呼び出されたかのようmodnameに、呼び出し結果を に設定します。 glb が true の場合、結果も global に格納されます。 その結果のコピーをスタックに残します。package.loaded[modname]require

modname

require()Lua スクリプトで呼び出しをコメントしようとしましたが、結果は同じです。

質問

私は何を間違えましたか?私は何かをするのを忘れていますか?


編集

次のように、非推奨の(削除された)関数/型を代替品で更新するモジュールをハッキングしました。

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

ただし、Lua スクリプトを使用してlyaml動作するため、問題は私のハックではないと思います。

オリジナル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でのみ実行されます-ハッキングされlyaml.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);

しかし、Lua標準モジュールluaopen_package()のローダー関数であるため、完全に間違っています...代わりに使用する必要がありました: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')

で、 C プログラムhello.luaを呼び出さずに。luaL_requiref()

于 2012-07-15T16:22:22.053 に答える