2012-06-13 47 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'函数采用了从零开始或从一开始的索引,则文档不清楚。看起来他们是基于一个人的。 –