5

Lua5.2.1を使用するVisualStudio2008 C++03アプリケーションがあります。「foo」というモジュールでLuaを拡張したいのですがrequire("foo")、Luaスクリプトを呼び出すと、次のエラーが発生します。

foo_test.lua:1: module 'foo' not found:
    no field package.preload['process']
    no file '!\lua\process.lua'
    no file '!\lua\process\init.lua'
    no file '!\process.lua'
    no file '!\process\

私のLuaスクリプト:

foo.bar()

私のlua_foo.hファイル:

#include <lua.h>
extern "C" int luaopen_foo( lua_State* L );

私のlua_foo.cppファイル:

#include "lua_foo.h"
#include <lua.hpp>

static int l_bar( lua_State *L )
{
    puts( "in bar()" );
    return 1;
}

int luaopen_foo( lua_State *L ) 
{
    static const luaL_Reg foo[] = {
        { "bar", l_bar },
        { NULL, NULL }
    };

    luaL_newlib( L, foo );
    return 1;
}

これらは、メインのLua実行可能ファイルに静的にリンクされている静的ライブラリ「lua_foo.lib」にコンパイルされます。

誰かが私がどこで間違っているのかを理解するのを手伝ってくれますか?ありがとう。(今のところ)c ++ラッパーは避けたいので、このライブラリをメインのLuaエンジンとは別のDLLとしてパッケージ化したくありません。


編集

問題はluaエンジンコードにありました。luaL_requiref@NicolBolasごとの提案を追加しました。

lua_State* L = luaL_newstate();
if( NULL != L )
{
    luaL_openlibs( L );
    luaL_requiref( token.get(), "foo", luaopen_foo, 1 );
    luaL_dofile( L, "foo_test.lua" );
    lua_close( L );
}
4

2 に答える 2

12

require機械がどのように機能するのか、したがってコードが機能しない理由を理解することが重要です。

requireファイルシステムとDLLでLuaスクリプトを探すように設計されています。静的ライブラリはDLLではありません。実際、C / C ++に関する限り、リンクが終了すると、静的ライブラリはそれらの.c/.cppファイルをアプリケーションに直接コンパイルするのと同じです。

適切な名前のDLLが見つかると、それをロードして、モジュールの名前である、という名前のrequire関数を見つけようとします。その場合、この関数を実行し、返された値をロードされたモジュールの内部データベースに格納します。luaopen_<modname><modname>

モジュールを呼び出すrequireと、この関数が返したものは何でも返されます。モジュールがすでにロードされている場合、戻り値はデータベースから取得され、直接返されます。

単に呼び出すだけでは、これは何も行われluaopen_fooませ。実際、この関数を単に呼び出すことは悪い考えです。これはLua関数であり、Lua関数として呼び出す必要があります(つまり、でLuaスタックにプッシュし、lua_pushcfunctionで呼び出す必要がありますlua_call)。

ローカルモジュール(LuaスクリプトまたはDLLにはないが、コードから公開されているモジュール)を作成する場合は、Lua機能を使用して作成する必要があります。具体的には、次を使用しますluaL_requiref

luaL_requiref(L, "foo", luaopen_foo, 0);

直接呼び出すのではなく、これを呼び出しluaopen_fooます。これにより、ロードされたモジュールの内部データベースにからluaopen_fooの戻り値が自動的に登録されます。requireしたがって、以降の呼び出しはrequire "foo"このテーブルを返します。

もう1つ:Luadoキーワードです。Luaテーブルのキー名にはキーワードを使用しないでください。できますが、常に引用符で囲む必要があります(つまり、スクリプトfoo["do"](...)で呼び出す必要があります)。

于 2012-08-21T17:16:09.350 に答える
1
  • luaopen_foo1つの関数を含むテーブルを作成しますが、Luaに公開することはありません。アクセスする場合は、スクリプトがアクセスできるものに割り当てる必要があります。これは、パッケージメカニズムを使用して行うことも、グローバルに割り当てることもできます(これは、Luaの組み込みライブラリが行うことです)。
  • 、という名前のフィールドがあります。これは、キーワードであるため、構文doを使用する場合に問題があります。foo.dodo
  • Lua関数の戻り値は、スタックに残っている値の数をLuaに通知します。あなたのl_do関数はその戻り値にあります。
  • の場合、luaopen_foo直接呼び出して戻り値を無視しているので、何も返す必要はありません。

コードを次のように変更します。

static int l_bar( lua_State *L )
{
   puts("l_bar called.");
   return 0;
}

void luaopen_foo( lua_State *L ) 
{
   static const struct luaL_Reg foo[] = {
      { "bar", l_bar },
      { NULL, NULL }
   };
   luaL_newlib( L, foo );   // create table containing `bar`
   lua_setglobal(L, "foo"); // assign that table to global `foo`
}

そして、スクリプトを次のように変更します。

foo.bar()
于 2012-08-21T16:43:46.323 に答える