我正在尝试将lua与c ++集成的小项目。 我的问题如下:
我有多个lua脚本,我们称之为s1.lua s2.lua和s3.lua。其中每个都具有以下功能:setVars()和executeResults()。
现在我可以在使用setVars()和/或executeResults()之后立即通过LuaL_dofile调用lua文件。这里的问题是,在我加载s2.lua之后,我再也无法调用s1.lua的函数了。这意味着我必须重做s1.lua上的LuaL_dofile以重新获得对该函数的访问权限,这样我就无法访问s2.lua中的函数。
有没有办法简单地加载所有lua文件,然后开始随意调用它们的函数?类似于s1-> executeResults()s5-> executeResults()s3-> setVars()等。
我目前已经有一个系统使用boost :: filesystem来检测文件夹中的所有lua文件,然后我将这些文件名保存在一个向量中,然后简单地迭代向量以连续加载每个lua文件。
在使用lua文件名填充向量时,我的插件加载函数现在看起来像这样:
void Lua_plugin::load_Plugins(){
std::vector<std::string>::const_iterator it;
for (it=Lua_PluginList.begin(); it!=Lua_PluginList.end(); it++){
std::cout<<"File loading: " << *it << std::endl;
std::string filename = *it;
std::string filepath = scriptdir+filename;
if (luaL_loadfile(L, filepath.c_str()) || lua_pcall(L, 0, 0, 0)) {
std::cout << "ScriptEngine: error loading script. Error returned was: " << lua_tostring(L, -1) << std::endl;
}
}
}
为了使它更清楚一点,我在.lua中的所有东西都是这样的:
-- s1.lua
setVars()
--do stuff
end
executeResults()
--dostuff
end
等,但我希望能够在连续加载两个之后调用s1.lua的setVars()和s2.lua的setVars()。
答案 0 :(得分:5)
这实际上是使用C API提出的 gwell :
#include <stdio.h>
#include "lua.h"
static void
executescript(lua_State *L, const char *filename, const char *function)
{
/* retrieve the environment from the resgistry */
lua_getfield(L, LUA_REGISTRYINDEX, filename);
/* get the desired function from the environment */
lua_getfield(L, -1, function);
return lua_call(L, 0, 0);
}
static void
loadscript(lua_State *L, const char *filename)
{
/* load the lua script into memory */
luaL_loadfile(L, filename);
/* create a new function environment and store it in the registry */
lua_createtable(L, 0, 1);
lua_getglobal(L, "print");
lua_setfield(L, -2, "print");
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, filename);
/* set the environment for the loaded script and execute it */
lua_setfenv(L, -2);
lua_call(L, 0, 0);
/* run the script initialization function */
executescript(L, filename, "init");
}
int
main(int argc, char *argv[])
{
lua_State *L;
int env1, env2;
L = (lua_State *) luaL_newstate();
luaL_openlibs(L);
loadscript(L, "test1.lua");
loadscript(L, "test2.lua");
executescript(L, "test1.lua", "run");
executescript(L, "test2.lua", "run");
executescript(L, "test2.lua", "run");
executescript(L, "test1.lua", "run");
return 0;
}
测试脚本:
-- test1.lua
function init() output = 'test1' end
function run() print(output) end
-- test2.lua
function init() output = 'test2' end
function run() print(output) end
输出:
test1
test2
test2
test1
为简洁起见,我省略了所有错误处理,但您需要检查luaL_loadfile
的返回值,并使用lua_pcall
代替lua_call
。
答案 1 :(得分:1)
setfenv()
函数可用于为每个加载的文件创建sandbox或环境。
此示例显示所有三个文件都可以加载冲突的函数,并且可以按任何顺序调用这些函数。类似的代码可以用C ++编写。此示例仅将打印功能导出到每个环境,在您的方案中可能需要更多。
function newEnv()
-- creates a simple environment
return {["print"]=print}
end
local e={} -- environment table
local c -- chunk variable
-- first instance
c = loadstring([[function f() print("1") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e]) -- set the loaded chunk's environment
pcall(c) -- process the chunk (places the function into the enviroment)
-- second instance
c = loadstring([[function f() print("2") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)
-- third instance
c = loadstring([[function f() print("3") end]])
e[#e+1] = newEnv()
setfenv(c, e[#e])
pcall(c)
pcall(e[3].f) --> 3
pcall(e[2].f) --> 2
pcall(e[1].f) --> 1
pcall(e[1].f) --> 1
pcall(e[2].f) --> 2
pcall(e[3].f) --> 3
答案 2 :(得分:1)
您可以为每个文件创建一个新状态lua_newstate()
。这比我之前的回答更容易。但是,它可能会有性能损失。