4

swig でラップされ、lua に登録されたクラスがあります。このクラスのインスタンスを lua スクリプトで作成でき、すべて正常に動作します。

しかし、新しい X への呼び出しを使用して C++ コードで作成されたクラスのインスタンスがあり、呼び出したい関数を含む la lua_state L があり、1 つの引数、X のインスタンスを受け入れるとします...その関数を呼び出すにはどうすればよいですか。これが問題のコードの(一部)です(エラー処理のものは省略しました):

main.cpp

class GuiInst;
extern "C"
{
    int luaopen_engine (lua_State *L);
}

int main()
{
    GuiInst gui=new GuiInst;
    lua_State *L=luaL_newstate();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);
    lua_getglobal(L,"Init");
    //Somehow push gui onto lua stack...
    lua_pcall(L, 1, 0, 0));
    lua_close(L);
}

mainmenu.lua

function Init(gui)
    vregion=gui:CreateComponent("GuiRegionVertical");
end

現時点で私が見つけたのは、swig で生成された cpp ファイルからいくつかの機能を公開し、それを呼び出すことだけです。これにはいくつかの理由があります...複数のモジュールがある場合は機能せず、swig ファイルのデフォルトのリンケージ仕様を変更する必要がありました (-DSWIGRUNTIME= を使用)。

以下を main.cpp に追加します

extern "C"
{
    struct swig_module_info;
    struct swig_type_info;
    int luaopen_engine (lua_State *L);
    swig_module_info *SWIG_Lua_GetModule(lua_State* L);
    void SWIG_Lua_NewPointerObj(lua_State* L,void* ptr,swig_type_info *type, int own);
    swig_type_info *SWIG_TypeQueryModule(swig_module_info *start,swig_module_info *end,const char *name);
}
//and then to push the value...
SWIG_Lua_NewPointerObj(L,gui,SWIG_TypeQueryModule(SWIG_Lua_GetModule(L),SWIG_Lua_GetModule(L),"GuiInst *"),0);

モジュールへのポインターを取得し、次に型へのポインターを取得し、swigs 関数を呼び出して登録します。人間が読めるはずのないファイルを掘り下げなければならないのは不合理なことでした (そのため、ファイルの上部に記載されています)。(しかし、それは機能します!)

確かに、私がやろうとしていることを達成するためのより良い方法があります。

高レベルの pov からの PS 私が望むのは、GuiInst の Object Factory によって作成された Gui コンポーネントを lua が参照しないようにすることです。いくつかの非常に単純な (そして非 swig) Python モジュールを除いて、スクリプト言語に機能を公開するのはこれが初めてなので、アドバイスを受ける準備ができています。

アドバイスをありがとう!


RBerteig によるコメントへの応答

GuiInst のコンストラクターは、lua がそのインスタンスを構築するのを防ぐために、swig が実行されるときにプライベートに #defined されるため、私にとってはうまくいきません。私が防ごうとしていたのは次のことでした(luaで):

r=engine.GuiRegionVertical()
r:Add(engine.GuiButton())

これは "g=new GuiButton" を呼び出し、GuiRegionVertical (さまざまな理由でポインターを格納する必要があります) に登録し、"delete g" を呼び出します。GuiRegionVertical には g へのポインターがぶら下がったままになります。

本当に必要なことは、GuiRegionVertical::Add(GuiButton*) が GuiButton* の参照カウントをインクリメントし、GuiRegionVertical のデストラクタがすべてのコンテンツの参照カウントをデクリメントすることだと思いますが、これがどのように行われるかはわかりませんスウィグで行われます。

これにより、プライベート コンストラクター、Gui オブジェクト ファクトリ、厄介な外部関数が不要になります。

私はこれについて間違っていますか?

ありがとう。

4

2 に答える 2

3

遅いほうがいいし、この解決策は他の人にも役立ちます。

void handle_web_request(WebRequest *request, WebResponse *response)
{
  lua_getfield(rackam->lua_state, LUA_GLOBALSINDEX, "handle_web_request");
  SWIG_Lua_NewPointerObj(rackam->lua_state, request, SWIGTYPE_p_WebRequest, 0);
  SWIG_Lua_NewPointerObj(rackam->lua_state, response, SWIGTYPE_p_WebResponse, 0);
  lua_call(rackam->lua_state, 2, 0);
}

SWIGTYPE_p_WebRequest が

#define SWIGTYPE_p_WebResponse swig_types[6]

swig_types[6] は

static swig_type_info *swig_types[12];

つまり、swig_types は、それが定義されている C++ ファイルからのみアクセス可能です。

この特定のスニペットは 2 つのラッパー ポインターを送信しているため、C++ 側から handle_web_request(request, response) を呼び出すと、グローバル lua 関数「handle_web_request」が実行され、SWIG マジックが適用された状態で 2 つのポインターが渡されます。

于 2012-03-02T00:50:05.627 に答える
1

最も効率的な答えではないかもしれない、単純で直接的な答えがあります。SWIG は、スクリプト言語側からオブジェクトを操作するためのラッパーを生成します。オブジェクトの場合、ラップされたコンストラクターも合成します。したがって、直接的な解決策は、Lua インタープリターが SWIG のコンストラクターを呼び出して新しいオブジェクトを作成することです。

ラップされたengine.GuiInstクラスの場合、ほぼ確実に次のようなことができます。

int main()
{
    lua_State *L=lua_open();
    luaopen_engine(L); //this is swigs module
    int error=luaL_loadfile(L,"mainmenu.lua")||
    lua_pcall(L, 0, 0, 0);

    luaL_dostring(L, "Init(engine.new_GuiInst())");

    lua_close(L);
}

スクリプト起動のような 1 回限りのケースでは、luaL_dostring() を介して文字列定数を実行するペナルティはまったく悪くありません。ただし、イベント コールバックまたは内部ループでそれを回避するのは難しいようです。

ポインタをラップされたオブジェクトに直接変換する方法が必要であるように思えますが、私自身の一握りの SWIG で生成されたラッパーでそれを見つけていません。

編集:もちろん、Lua フラグメントは API 呼び出しに分解して、エンジン テーブル グローバルをスタック上で取得し、そこからnew_GuiInstメンバーを抽出し、それを呼び出してから global を呼び出すことInitができますが、わずかな効率はいくつかの犠牲を伴います。明快さ。

明確な質問が示すように、ユーザーコードで偶然に構築されるべきではないオブジェクトを扱うことに関して、私の最初の衝動は、SWIGにコンストラクター関数を生成させ、後で必要に応じてプライベート参照を保持し、テーブルから削除することです. C モジュールでさえ、(通常は) 関数の値をメンバーに持つ単なるテーブルです。C で実装されても、特別な努力をしない限り読み取り専用にはなりません。

そのため、後で使用するために、いつでも の値を取得engine.new_GuiInstしてレジストリに保存できます (詳細については、疑似インデックスのLua リファレンス マニュアルのセクション 3.5 の説明luaL_ref()を参照してください)。次に、ユーザー コードを実行する前に、 と同等の操作を行うだけです。私が最近遊んでいた C データ型については、SWIG がそれぞれの型に対して と という名前の 2 つのコンストラクターを作成したことに注意してください。どちらもモジュールのテーブルに表示されていたので、両方の名前を に設定する必要があります。SWIG ラッピング C++ クラスの経験が少ない場合、結果が異なる場合があります...LUA_REGISTRYINDEXengine.new_GuiInst = nilnew_TYPETYPEnil

SWIG によって返されたテーブルの内容全体を確認して確認engineし、ユーザーが使用できるようにするメソッドのみを含むプロキシ オブジェクトを作成することができます。また、ユーザー スクリプトから見える環境を変更して、プロキシのみを使用できるようにし、プロキシengineにも名前を付けることができます。Lua リストlua-users wikiで、ユーザー スクリプトのサンドボックス化についてかなりの量の議論がありました。

于 2009-03-05T02:56:17.823 に答える