使用句柄从 .lua 调用 lua 函数?

2021-12-30 00:00:00 lua c++ lua-api

我正在做一个小项目,试图将 lua 与 C++ 集成.然而,我的问题如下:

I'm working on a small project trying to integrate lua with c++. My problem however is as follows:

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

I have multiple lua scripts, lets call them s1.lua s2.lua and s3.lua. Each of these has the following functions: setVars() and executeResults().

现在我可以通过 LuaL_dofile 并在使用 setVars() 和/或 executeResults() 之后立即调用 lua 文件.然而这里的问题是,在我加载 s2.lua 之后,我无法再调用 s1.lua 的函数.这意味着我必须在 s1.lua 上重做 LuaL_dofile 以重新获得对该函数的访问权限,这样做我将无法访问 s2.lua 中的函数.

Now I am able to to call a lua file through LuaL_dofile and immediately after use setVars() and/or executeResults(). The problem here however is that after I load s2.lua I can no longer call the functions of s1.lua. This would mean I have to redo the LuaL_dofile on s1.lua to regain access to the function and by doing so I lose access to the functions in s2.lua.

有没有办法简单地连续加载所有lua文件,然后开始随意调用它们的函数?像 s1->executeResults() s5->executeResults() s3->setVars() 等

Is there a way to simply load all lua files in a row, and afterwards start calling their functions at will? Something like s1->executeResults() s5->executeResults() s3->setVars() etc.

我目前已经有一个系统,使用 boost::filesystem 来检测文件夹中的所有 lua 文件,然后我将这些文件名保存在一个向量中,然后简单地遍历该向量以连续加载每个 lua 文件.

I currently already have a system in place using boost::filesystem to detect all lua files in a folder, I then save these files names in a vector and then simply iterate over the vector to load each lua file in a row.

放弃用 lua 文件名填充向量,我的插件加载函数现在看起来像这样:

Foregoing the filling of the vector with lua file names my plugin load function looks like this at the moment:

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 中的所有内容是这样的:

To make it a bit more clear, all I have in the .lua's is something like this:

-- s1.lua

setVars()
--do stuff
end

executeResults()
--dostuff
end

等,但我希望能够在简单地连续加载后调用 s1.lua 的 setVars() 和 s2.lua 的 setVars().

etc, but I would like to be able to call s1.lua's setVars() and s2.lua's setVars() after simply having loaded both in a row.

推荐答案

这实际上是 gwell 提出的使用 C API 的建议:

This is effectively what gwell proposed using the C API:

#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.

I omitted all error handling for brevity, but you'll want to check the return value of luaL_loadfile and use lua_pcall instead of lua_call.

相关文章