2010-08-07 127 views
0

我正在研究一个尝试将lua与C++集成的小项目。 但我的问题如下:从.lua的使用手柄调用lua函数?

我有多个lua脚本,可以称它们为s1.lua s2.lua和s3.lua。其中每个都有以下功能:setVars()和executeResults()。

现在我可以通过LuaL_dofile并在使用setVars()和/或executeResults()后立即调用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()。

回答

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 

我省略了所有的错误处理的简洁,但您需要检查的返回值并使用lua_pcall而不是lua_call

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 

+0

首先,谢谢! 我正在环视lua的C++部分,我无法找到哪个函数会在C++环境中替换lua的setfenv()。这主要是因为我想在我的C++代码中保留插件/插件控件(除了比lua更精通C++)。 假设我可以将环境创建合并到我的Load_Plugins()函数中,我会否正确?让环境列表可用于C++代码的其他部分? 在此先感谢 – Karrok 2010-08-08 03:42:51

+0

发现纠错http://pgl.yoyo.org/luai/i/lua_setfenv 虽然通过lua-users.org列表飞奔,但它暗示此功能已弃用,但我仍会尝试: ) – Karrok 2010-08-08 04:04:22

+0

弃用将取决于您使用的Lua版本。 'setfenv()'将在5.2中被弃用。请参阅http://www.corsix.org/content/look-lua-52-work3 – gwell 2010-08-08 04:15:41

1

你可以为每个文件创建一个新的状态lua_newstate()。这将比我以前的答案更容易。但是,它可能会有性能损失。

+0

那么,如果为每个lua文件只创建一次新的状态不会太大,那么它不应该成为问题。和下面的访问状态不应该经常发生。我想我会尝试新的事情,因为我仍然无法让lua_setfenv在没有崩溃应用程序的情况下工作:( 再次感谢:) – Karrok 2010-08-09 04:35:39