2012-06-13 49 views
7

可以說我至少有兩個lua腳本文件。沙盒嵌入Lua在5.2 /設置環境函數的環境lua.file

test1.lua test2.lua

都定義一個初始化功能和其它功能具有類似名稱。

如何將每個使用C++/c的腳本文件加載到使用Lua 5.2的獨立環境中,以便相同的函數名稱不會發生衝突 - 我找到了5.1的示例代碼,這對我不起作用(因爲setenv已經消失和lua_setuservalue似乎不工作)

樣品這裏Calling lua functions from .lua's using handles?

基本上,如果我有setuservalue取代SETENV - 我得到一個訪問衝突。

+0

這就是爲什麼我一直堅持用LUA 5.1在我自己的項目,現在的原因之一。我相信v5.2'load'和'loadfile'函數可以讓你指定一個環境;他們可能是開始尋找解決方案的最佳場所。 – Rook

+0

謝謝,但我讀了關於加載和加載文件,但我找不到解決方案 – Steve

+0

'setuservalue'絕對不是嘗試操作環境時使用的正確函數。但是,lua文檔似乎對你應該做的事情不太清楚。 'lua_load'表示一個與被加載的塊相關聯的單值被設置爲它的環境,但沒有提到你如何去關聯一個upvalue和來自C的塊。如果你是從lua加載塊,那麼lua版本的'load'函數看起來應該正確設置環境。 – Rook

回答

8

unofficial Lua FAQ在Lua有一個關於沙箱的條目。 我的猜測是,您可以輕鬆地將該邏輯轉置爲您的C/C++代碼。請參閱LuaFiveTo on the lua-users wiki

修正

這的確不是因爲它似乎微不足道。但最終的觀點很簡單:加載你的塊,按下_ENV表,使用lua_setupvalue(L,-2,1)。重要的是表格應該位於堆棧的頂部。

作爲一個小例子,使用2-環境經由元表默認爲_G用於讀取的東西:

#include <lua.h> 
#include <lualib.h> 
#include <lauxlib.h> 

int main(void){ 
     lua_State *L = luaL_newstate(); 
     char *file1 = "file1.lua"; 
     char *file2 = "file2.lua"; 

     luaL_openlibs(L); 

     luaL_loadfile(L,file2); // S: 1 
     luaL_loadfile(L,file1); // S: 2 
     lua_newtable(L); // ENV for file 1: S: 321 
     lua_newtable(L); // ENV for file 2: S: 4321 

     //lets have each function have its metatable, where missed lookups are 
     //instead looked up in the global table _G 

     lua_newtable(L); // metatable S: 54321 
     lua_getglobal(L,"_G"); // pushes _G, which will be the __index metatable entry S: 654321 

     lua_setfield(L,-2,"__index"); // metatable on top S: 54321 
     lua_pushvalue(L,-1); // copy the metatable S: 554321 
     lua_setmetatable(L,-3); // set the last copy for env2 S: 54321 
     lua_setmetatable(L,-3); // set the original for env1 S: 4321 
     // here we end up having 2 tables on the stack for 2 environments 
     lua_setupvalue(L,1,1); // first upvalue == _ENV so set it. S: 321 
     lua_setupvalue(L,2,1); // set _ENV for file S: 21 
     // Remaining on the stack: 2 chunks with env set. 
     lua_pcall(L,0,LUA_MULTRET,0); 
     lua_pcall(L,0,LUA_MULTRET,0); 
     lua_close(L); 
     return 0; 
} 

而對於2的Lua文件:

-- file1.lua 
function init() 
     A="foo" 
     print("Hello from file1") 
     print(A) 
end 
init() 

-- file2.lua 
-- this shows that stuff defined in file1 will not polute the environment for file2 
print("init function is",tostring(init)) 
function init() 
     A="bar" 
     print("Hello from file2") 
     print(A) 
end 
init() 
+0

謝謝,但我知道這些資源 - 但即時無法重現這在C/C++ – Steve

+0

事實上,問題在於'load'和'loadfile'的C等價物沒有相當接近的接口或文檔。 lua用戶的維基頁面似乎也有點兒缺乏數據,並且包含了從未達到5.2規範的功能。 – Rook

+0

jpjacobs,我們今天在lua-irc見面了,正如我所說的,我得到了解決方案,但是再次感謝您提供了另一個示例! – Steve

0

都定義INIT功能和其他具有相似名稱的功能。

首先,爲什麼這些功能global?他們應該是本地的腳本。如果你要在其他文件中使用require,他們應該創建並返回一個包含他們希望公開的函數的表。

需要這些文件時,現代成語是做這樣的事情:

local Library = require 'library' 

Library.Func1(...) 

因此,你不污染Lua全局命名空間。你使用局部變量。但是,如果你堅持使用像這樣的全局變量,你可以完全按照文檔所說的做:改變已編譯塊的第一個最大值。

基本上如果我用setuservalue替換setenv - 我得到訪問衝突。

當然你有。這不是什麼lua_setuservalue確實。它用於設置與userdata相關的值。你想要的是適當的叫做lua_setupvalue

使用你舉的示例代碼,正確的答案應該是:

lua_setupvalue(L, -2, 1); 
+0

我不小心弄明白了 - lua_setupvalue(L,-2,0);崩潰! - 我用lua_setupvalue(L,-2,1)逃脫了; - 我的知識是有限的,我完全知道在這方面是什麼1。但它似乎工作 - 現在是否有可能暴露我的對象只在這個「命名空間」,而不是在全局表?即時通訊使用luabind來公開我的類,目前即時通訊使用luabind :: globals(myLuaState)[「myObj」] = myObj – Steve

+0

至於爲什麼是全局函數 - 我喜歡用多個實體的腳本創建一個事件系統,它使用相同的功能簽名,例如init,因爲腳本通常不是由開發人員創建的,所以我希望儘可能無痛苦,並且不打擾任何具有libaries或模塊的人 - 因此,我想確保每個腳本都在自己的環境中執行 - 它不是來源! – Steve

+0

@Steve:如果'lua_setupvalue'函數採用了從零開始或從一開始的索引,則文檔不清楚。看起來他們是基於一個人的。 –