Here's how you do it in pure Lua 5.1:
file1_env = setmetatable({}, {__index = _G})
local file1_chunk = loadfile('file1.lua')
setfenv(file1_chunk, file1_env)
file1_chunk()
file2_env = setmetatable({}, {__index = _G})
local file2_chunk = loadfile('file2.lua')
setfenv(file2_chunk, file2_env)
file2_chunk()
file1_env.doSomething() -- prints "Hello from file1"
file2_env.doSomething() -- prints "Hello from file2"
What's going on is you're changing the environment that each file's chunk runs in, so instead of putting their doSomething
functions in the global environment and thus stomping each other, they go in their own local environment (which uses a metatable so they can use things that are in the global environment like require
and print
). And as requested, common.lua
only has to run once, as you'll see if you put something like printHello('common')
at the end of it.
If you want to do this from C, all of the functionality I used can be straightforwardly converted to the C API, like this:
#include <lua5.1/lua.h>
#include <lua5.1/lualib.h>
#include <lua5.1/lauxlib.h>
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
/* stack is empty */
lua_createtable(L, 0, 1);
/* -1: file1_env */
lua_createtable(L, 0, 1);
/* -2: file1_env, -1: file1_env_mt */
lua_pushvalue(L, LUA_GLOBALSINDEX);
/* -3: file1_env, -2: file1_env_mt, -1: _G */
lua_setfield(L, -2, "__index");
/* -2: file1_env, -1: file1_env_mt */
lua_setmetatable(L, -2);
/* -1: file1_env */
luaL_loadfile(L, "file1.lua");
/* -2: file1_env, -1: file1_chunk */
lua_pushvalue(L, -2);
/* -3: file1_env, -2: file1_chunk, -1: file1_env */
lua_setfenv(L, -2);
/* -2: file1_env, -1: file1_chunk */
lua_call(L, 0, 0);
/* -1: file1_env */
lua_setglobal(L, "file1_env");
/* stack is empty */
lua_createtable(L, 0, 1);
/* -1: file2_env */
lua_createtable(L, 0, 1);
/* -2: file2_env, -1: file2_env_mt */
lua_pushvalue(L, LUA_GLOBALSINDEX);
/* -3: file2_env, -2: file2_env_mt, -1: _G */
lua_setfield(L, -2, "__index");
/* -2: file2_env, -1: file2_env_mt */
lua_setmetatable(L, -2);
/* -1: file2_env */
luaL_loadfile(L, "file2.lua");
/* -2: file2_env, -1: file2_chunk */
lua_pushvalue(L, -2);
/* -3: file2_env, -2: file2_chunk, -1: file2_env */
lua_setfenv(L, -2);
/* -2: file2_env, -1: file2_chunk */
lua_call(L, 0, 0);
/* -1: file2_env */
lua_setglobal(L, "file2_env");
/* stack is empty */
lua_getglobal(L, "file1_env");
/* -1: file1_env */
lua_getfield(L, -1, "doSomething");
/* -2: file1_env, -1: file1_env.doSomething */
lua_call(L, 0, 0);
/* -1: file1_env */
lua_pop(L, 1);
/* stack is empty */
lua_getglobal(L, "file2_env");
/* -1: file2_env */
lua_getfield(L, -1, "doSomething");
/* -2: file2_env, -1: file2_env.doSomething */
lua_call(L, 0, 0);
/* -1: file2_env */
lua_pop(L, 1);
/* stack is empty */
lua_close(L);
return 0;
}