2009-03-05 32 views
4

我有一個包裹着swig的類,並且註冊了lua。我可以在lua腳本中創建這個類的一個實例,並且它一切正常。如何將用swig包裝的C++類的實例推送到lua堆棧上?

但是說我有一個在我的C++代碼中創建的類的實例,調用了新的X,並且我有la lua_state L,它帶有一個我想要調用的函數,它接受一個參數, 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註冊它。不得不挖掘一個本不應該是人類可讀的文件是非常不合理的(所以它在文件的頂部說明)並且只是MESSY! (但它確實有用!)

當然,這是一種更好的方式來完成我想要做的事情。

PS從高級pov我想要的是讓lua不會引用GuiInst中的Object Factory創建的Gui組件,以防萬一我錯了。這是我第一次將功能暴露給一些非常簡單的(和非swig)Python模塊的腳本語言,所以我準備好接受建議。

感謝您的任何建議!


響應由RBerteig

痛飲時運行,以防止LUA構建它的實例,這樣就不會爲我工作GuiInst的構造器已經#defined私人評論。我試圖阻止了以下內容(LUA):

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

其稱之爲「G =新GuiButton」,則與GuiRegionVertical(這需要存儲各種原因指針)進行註冊,然後調用「刪除g」,GuiRegionVertical留下一個指向g的懸掛指針。我想懷疑真正需要發生的是GuiRegionVertical :: Add(GuiButton *)應該增加GuiButton *的引用計數,然後GuiRegionVertical的析構函數應該減少其所有內容的refcounts,儘管我並不是確定這應該如何用swig來完成。

這將消除對私有構造函數,Gui對象工廠和令人討厭的extern的需求。

我該怎麼處理這個錯誤?

謝謝。

+0

可能重複[SWIG:Lua - 將C++實例作爲lua函數參數傳遞](http://stackoverflow.com/questions/9455552/swiglua-passing-ac-instance-as-a-lua-function-參數) – 2012-03-02 02:51:26

+1

@NicolBolas:這個問題怎麼可能是重複的?它比那個年長三歲:)。感謝鏈接壽。 – DaedalusFall 2012-04-10 13:28:47

回答

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); 
} 

對於像腳本啓動一杆的情況下,運行一個字符串通過luaL_dostring()不變的罰不壞所有。但是,在事件回調或內部循環中,我會更難以避免它。

看起來好像應該有一種方法將指針直接轉換爲包裝對象,我沒有在我自己的SWIG生成的包裝中找到它。

編輯:當然,Lua的片段可被分解到API調用,獲得發動機臺上的疊層全球,從中提取出new_GuiInst成員,調用它,然後調用全局Init,但點點的效率是以一定的清晰度爲代價的。

至於處理在用戶代碼中不應該被意外構造的對象,如澄清的問題所指出的,我的第一個衝動是讓SWIG生成構造函數,稍後保留私有引用,然後刪除它從桌子上。即使是C模塊(通常)也只是一個其成員包含函數值的表。在C語言中實現並不會使其變爲只讀,除非採取額外的努力。

所以,你總是可以檢索engine.new_GuiInst值,並在註冊表中停放(見luaL_ref()和細節的僞指數LUA_REGISTRYINDEXsection 3.5 of the Lua Reference Manual的討論)以備後用。然後,在讓任何用戶代碼運行之前,只需執行相當於engine.new_GuiInst = nil。我應該注意到,對於我最近玩過的C數據類型,SWIG爲每種類型創建了兩個構造函數,分別命名爲new_TYPETYPE。兩者都可以在模塊的表格中看到,並且您希望將這兩個名稱都設置爲nil。如果SWIG包裝C++類的經驗少得多,結果可能會有所不同...

您可能需要檢查並查看SWIG返回的engine表的全部內容,並創建一個代理對象,該對象只包含您希望可供您的用戶使用的方法。您還可以更改用戶腳本所看到的environment,以便它僅具有可用的代理,並將代理engine也命名爲。關於Lua listlua-users wiki上的sandboxing用戶腳本已經有相當多的討論。

+0

感謝您的回覆(及其速度),我更新了我的問題,因爲評論中沒有足夠的空間。 我會投你的答案,但我的評價還不夠高。 – DaedalusFall 2009-03-05 04:13:05

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); 
} 

這個代碼必須%{}%塊內部在.i文件,因爲SWIGTYPE_p_WebRequest是

#define SWIGTYPE_p_WebResponse swig_types[6] 

和swig_types [6]是

static swig_type_info *swig_types[12]; 

這意味着swig_types只能從定義它的C++文件訪問。

這個特定的代碼片段發送了兩個我的包裝指針,所以從C++端調用handle_web_request(request,response)將運行全局lua函數「handle_web_request」並將它傳遞給我的兩個指針,帶有SWIG魔術應用。