【问题标题】:Lua 'require' but files are only in memoryLua 'require' 但文件只在内存中
【发布时间】:2013-09-28 17:13:22
【问题描述】:

设置:我在 C/C++ 环境中使用 Lua。

我在磁盘上有几个 lua 文件。这些被读入内存,并且在运行时可以使用更多仅内存的 lua 文件。想想例如一个编辑器,还有其他未保存的 lua 文件。

所以,我在内存中有一个list<identifier, lua_file_content>。其中一些文件中有require 语句。当我尝试将所有这些文件加载​​到 lua 实例(当前通过lua_dostring)时,我得到attempt to call global require (a nil value)

是否有可能提供一个require 函数,它替换旧函数并只使用内存中提供的文件(那些文件在 C 端)?

是否有另一种方法可以在这些文件中允许require 而磁盘上没有所需的文件?

一个例子是只从内存中加载 lua 标准库而不改变它。 (这实际上是我的测试用例。)

【问题讨论】:

    标签: lua


    【解决方案1】:

    模拟require 的非常简单的 C++ 函数可能是:(伪代码)

    int my_require(lua_State* state) {
        // get the module name
        const char* name = lua_tostring(state);
        // find if you have such module loaded
        if (mymodules.find(name) != mymodules.end())
            luaL_loadbuffer(state, buffer, size, name);
        // the chunk is now at the top of the stack
        lua_call(state)
        return 1;
    }
    

    将此函数作为require 公开给 Lua,然后你就可以开始了。

    我还想补充一点,以完全模仿require 的行为,您可能需要注意package.loaded,以避免代码被加载两次。

    【讨论】:

    • 对不起,我不是 Lua 专家。我猜我在从内存中加载文件之前向 lua 实例提供了这个名为 require 的函数?
    • @MikeM 请查看我对package.path 的编辑,我觉得这可能是我忘记提及的重要事情。
    • lua_call 不需要 3 个参数吗?
    • 我尝试拥有自己的package.loaded,在第二次加载包时将其设为真。但这不起作用。在我看来,我真的必须为每个要求将文件放在堆栈上。但是,由于我有内存中的文件,我不必再次加载它们。 @BartekBanachewicz 你觉得这合理吗?顺便说一句lua_call真的需要3个参数,但是我用luaL_dostring替换了loadbuffer和调用,效果很好。
    • “合理”取决于您的用例。 Lua 的默认行为(未嵌入时)是每个文件只加载一次并填满package.path
    【解决方案2】:

    与其替换require,不如给package.loaders添加一个函数?代码几乎相同。

    int my_loader(lua_State* state) {
        // get the module name
        const char* name = lua_tostring(state);
        // find if you have such module loaded
        if (mymodules.find(name) != mymodules.end())
        {
            luaL_loadbuffer(state, buffer, size, name);
            // the chunk is now at the top of the stack
            return 1;
        }
    
        // didn't find anything
        return 0;
    }
    
    // When you load the lua state, insert this into package.loaders
    

    http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders

    【讨论】:

    • 非常感谢,效果也很好。由于它似乎是更好的解决方案,因为它隐含地处理了 package.loaded,所以我将接受的解决方案更改为这个。
    【解决方案3】:

    lua 5.2 中没有 package.loaders
    它现在调用 package.searchers。

    #include <stdio.h>
    #include <string>
    #include <lua.hpp>
    
    std::string    module_script;
    
    
    int MyLoader(lua_State *L)
    {
        const char *name = luaL_checkstring(L, 1);  // Module name
    
    //  std::string    result = SearchScript(name); // Search your database.
        std::string    result = module_script;      // Just for demo.
    
        if( luaL_loadbuffer(L, result.c_str(), result.size(), name) )
        {
            printf("%s", lua_tostring(L, -1));
            lua_pop(L, 1);
        }
    
        return 1;
    }
    
    void SetLoader(lua_State* L)
    {
        lua_register(L, "my_loader", MyLoader);
    
        std::string     str;
    
    //  str += "table.insert(package.loaders,   2, my_loader) \n";   // Older than lua v5.2
        str += "table.insert(package.searchers, 2, my_loader) \n";
    
        luaL_dostring(L, str.c_str());
    }
    
    void SetModule()
    {
        std::string     str;
    
        str += "print([[It is add.lua]]) \n";
        str += "return { func = function() print([[message from add.lua]]) end } \n";
    
        module_script=str;
    }
    
    void LoadMainScript(lua_State* L)
    {
        std::string     str;
    
        str += "dev = require [[add]] \n";
        str += "print([[It is main.lua]]) \n";
        str += "dev.func() \n";
    
        if ( luaL_loadbuffer(L, str.c_str(), str.size(), "main") )
        {
            printf("%s", lua_tostring(L, -1));
            lua_pop(L, 1);
            return;
        }
    }
    
    int main()
    {
        lua_State*  L = luaL_newstate();
    
        luaL_openlibs(L);
    
        SetModule(L);       // Write down module in memory. Lua not load it yet.
        SetLoader(L);
        LoadMainScript(L);
    
        lua_pcall(L,0,0,0);
        lua_close(L);
    
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 2017-08-28
      • 2020-04-08
      • 1970-01-01
      • 2014-04-24
      • 2014-06-11
      • 1970-01-01
      相关资源
      最近更新 更多