Search code examples
cmodulelualuajit

C - LuaJit Assign custom module name to a compiled string


I have a small C program that has a string which must represent a Lua module and it looks like this:

const char *lua_str = " local mymodule = {} \
    function mymodule.foo() \
        print(\"Hello World!\") \
    end
    return mymodule";

Or maybe using the old way (if required):

const char *lua_str = "module(\"mymodule\", package.seeall \
    function foo() \
        print(\"Hello World!\") \
    end";

And let's assume that this is my small host application:

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main(int argc, char** argv)
{
    lua_State *L = lua_open();
    luaL_openlibs(L);

    luaL_dostring(L, lua_str);
    luaL_dofile(L, "test.lua");

    return 0;
}

Now in test.lua to be able to use that module with a static name that isn't decided by the file name:

local mymodule = require "mymodule"
mymodule.foo()

Basically, I need to execute that string and give it a custom name which represents the actual module name. Currently the name is decided by the file name and I don't want that.


Solution

  • If you look at the documentation for require:

    Loads the given module. The function starts by looking into the package.loaded table to determine whether modname is already loaded. If it is, then require returns the value stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module.

    To find a loader, require is guided by the package.loaders array. By changing this array, we can change how require looks for a module. The following explanation is based on the default configuration for package.loaders.

    First require queries package.preload[modname]. If it has a value, this value (which should be a function) is the loader. Otherwise require searches for a Lua loader using the path stored in package.path. If that also fails, it searches for a C loader using the path stored in package.cpath. If that also fails, it tries an all-in-one loader (see package.loaders).

    Once a loader is found, require calls the loader with a single argument, modname. If the loader returns any value, require assigns the returned value to package.loaded[modname]. If the loader returns no value and has not assigned any value to package.loaded[modname], then require assigns true to this entry. In any case, require returns the final value of package.loaded[modname].

    If there is any error loading or running the module, or if it cannot find any loader for the module, then require signals an error.

    You will see that it explains, in some detail, what methods require uses to find the code for the given module name. Implicit in that explanation is an indication as to how you can assign arbitrary chunks of loaded (or loadable) code to any given name you would like.

    Specifically, if you set a value in package.loaded[modname] that value will be returned immediately. Failing that, package.preload[modname] is used as a loader (which is a function that takes the module name).