|
Got it (though less happy to be using the debug module):-- this wraps require to ensure that it is always called in the environment of the master state:
local oldrequire = require local master = _G function require(...) -- cache the current thread environment: local env = debug.getfenv(coroutine.running()) -- set to 'master' environment: debug.setfenv(coroutine.running(), master) -- call the real require: local ret = { oldrequire(...) } -- restore to the current thread environment: debug.setfenv(coroutine.running(), env) -- return the return value(s): return unpack(ret) endOnce again, sorry for noise. Thought this may be useful for anyone else with a similar problem.
On May 13, 2008, at 9:59 AM, Graham Wakefield wrote:
OK, I admit, the globals / environments thing is really confusing. That script doesn't work, because getfenv(), getfenv(1), etc doesn't give me the environment of the calling thread; it always returns _G. But the LUA_GLOBALSINDEX is different in each thread, because of a lua_setfenv call.Back to the drawing board. (and sorry for the noise) Graham On May 13, 2008, at 9:47 AM, Graham Wakefield wrote:That should be:-- this wraps require to ensure that it is always called in the environment of the master state:local oldrequire = require local master = _G function require(...) -- cache the current calling environment: local env = getfenv() -- change to 'master' environment: setfenv(0, master) -- call the real require: local ret = { oldrequire(...) } -- restore to the current calling environment: setfenv(0, env) return unpack(ret) end On May 13, 2008, at 9:45 AM, Graham Wakefield wrote:Yes, that's what I suspected. Tthe mapping of lua_setfenv, setfenv, LUA_GLOBALSINDEX and LUA_ENVIRONINDEX, for threads, userdata and C functions is quite confusing.lfs = require "lfs" works, but some modules make other changes to the globals table besides returning themselves.This works (run in the master state before any other scripts):local oldrequire = requirelocal master = _Gfunction require (...) -- cache the current calling environment:local env = getfenv() -- change to 'master' environment: setfenv(0, master) -- call the real require: oldrequire(...) -- restore to the current calling environment: setfenv(0, env)end On May 13, 2008, at 4:40 AM, Peter Cawley wrote:Have you tried: lfs = require "lfs" Also, the Lua manual states: " The thread environment (where global variables live) is always at pseudo-index LUA_GLOBALSINDEX. The environment of the running C function is always at pseudo-index LUA_ENVIRONINDEX."Hence, setting a thread environment is the same as setting the thread globals index. My guess is that LFS loaded its global table using theglobals index, so while the require function's environment index is the globals table for the master state, because require was calledfrom a thead, using the globals index gives you the globals for thatthread, whereas if LFS loaded into the environment index, it would load into (in this case) the master state globals. My 2 cents. 2008/5/13 Graham Wakefield <lists@grahamwakefield.net>:Hi,I have an application in which lua scripts may be loaded by the user. Each script is given a 'child' lua_State created by lua_newthread(). Keeping each table's variables separate is beneficial to the application, so the child state is given a local environment, with a metatable __index to the masterglobals, like this: lua_State *Ls = lua_newthread(L);// Create a local environment with a link to globalenvironment via __index metamethod// this means that script variables are not shared betweenscripts lua_pushthread(Ls); lua_newtable( Ls ); lua_pushvalue( Ls, -1 );lua_setmetatable( Ls, -2 ); // Set itself asmetatablelua_pushvalue( Ls, LUA_GLOBALSINDEX );lua_setfield( Ls, -2, "__index" ); lua_setfenv( Ls, -2 ); lua_pop(Ls, 1);A user script can load a module using require (e.g. require "lfs"), which works as normal. However, if a second script is loaded, the global 'lfs' isnot accessible to the second script. script 1: require "lfs" print(lfs) -- table (0x....) script 2: require "lfs" print(lfs) -- nil print(package.loaded.lfs) -- table (0x...)I can't quite figure out why the second script doesn't get global access to the module. I wonder if the require() call is pushing the module as a global into script 1's environment, rather than the master state. Is this the case? [in fact, does lua_setfenv() on a lua_State do the same as lua_replace(Ls,LUA_GLOBALSINDEX)?] Is there a known workaround? Thanks, GrahamBe seeing you grrr waaa www.grahamwakefield.netBe seeing you grrr waaa www.grahamwakefield.netBe seeing you grrr waaa www.grahamwakefield.net
Be seeing you grrr waaa www.grahamwakefield.net