Search code examples
moduleluarequire

Is it possible to require() a script that is loaded using luaL_loadstring()?


I'm a beginner in Lua.

I wonder if it is possible to use require('filename') to require a script that is loaded using luaL_loadstring().

Since luaL_loadstring(lua_State *L, const char *s) doesn't specify any filename, I don't know how to use require() to load this script from other script.

Does require() only works with actual .lua files?


Solution

  • luaL_loadstring creates a Lua function which, when called, executes the string it was given. We can use this fact, because Lua C modules also simply call a function luaopen_MODULE. This function returns a table with the module content. That is to say, if we want to load a module via luaL_loadstring the script given as a string has to return a table. The only thing left to do is letting the interpreter know where to find the module. Therefore we simply create an entry in package.preload.

    The interesting part is between the dashes. The rest is just boilerplate to get the interpreter running. (Might not work in 5.1)

    #include <stdio.h>
    
    #include <lua.h>
    #include <lualib.h>
    #include <lauxlib.h>
    
    int main(int argc, char *argv[]) {
        if (argc != 2) {
            fprintf(stderr, "Usage: %s <script.lua>\n", argv[0]);
            return 1;
        }
    
        lua_State * L = luaL_newstate();
        luaL_openlibs(L);
    
        // ---- Register our "fromstring" module ----
        lua_getglobal(L, "package");
        lua_getfield(L, -1, "preload");
        luaL_loadstring(L, "return { test = function() print('Test') end }");
        lua_setfield(L, -2, "fromstring");
        // ------------------------------------------
    
        if (luaL_dofile(L, argv[1]) != 0) {
            fprintf(stderr,"lua: %s\n", lua_tostring(L, -1));
            lua_close(L);
            return 1;
        }
    
        lua_close(L);
    }
    

    Input script:

    local fromstring = require("fromstring")
    fromstring.test()
    

    Output:

    Test