2010-08-07 120 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