要求子目录中的 LuaJIT 模块会覆盖父目录中的同名模块
Posted
技术标签:
【中文标题】要求子目录中的 LuaJIT 模块会覆盖父目录中的同名模块【英文标题】:Requiring a LuaJIT module in a subdir is overwriting a module of the same name in the parent dir 【发布时间】:2015-07-04 10:18:00 【问题描述】:我有这样的文件设置:
main.lua (requires 'mydir.b' and then 'b')
b.lua
mydir/
b.so (LuaJIT C module)
从main开始,我这样做:
function print_loaded()
for k, v in pairs(package.loaded) do print(k, v) end
end
print_loaded()
require 'mydir.b'
print_loaded()
-- This would now include 'mydir.b' instead of 'b':
local b = require 'b'
print
s 的输出表明我对require 'mydir.b'
的调用将返回值设置为package.loaded['b']
的值以及预期的package.loaded['mydir.b']
。我想让package.loaded['b']
保持未设置,以便我以后可以require 'b'
而不是最终得到来自mydir.b
的(我认为不正确的)缓存值。
我的问题是:有什么好的方法来解决这个问题?
就我而言,我希望能够将mydir
复制为我的任何LuaJIT 项目的子目录,而不必担心mydir.whatever
会通过销毁以后的require
s 来污染模块命名空间whatever
在父目录级别。
预期人们会说,“只需重命名您的模块!”是的。我能做到。但我很想知道是否有更好的解决方案让我根本不必担心名称冲突。
【问题讨论】:
你的b.lua
是否有机会使用module
函数?
不,它没有。此行为似乎与b.lua
的内容无关。
b.so
库是否在任何地方设置了packages.loaded
(例如使用module
)?
不,b.so
不会在任何地方使用module
。但!它确实调用了luaL_register
,这可能是导致问题的原因!感谢您帮助我意识到这一点。我会写一个答案。
【参考方案1】:
问题是我在 b.so
的源文件 (b.c
) 中错误地调用了 luaL_register
。
这是导致问题的错误代码:
static const struct luaL_reg b[] =
/* set up a list of function pointers here */
;
int luaopen_mydir_b(lua_State *L)
luaL_register(L, "b", b); // <-- PROBLEM HERE (see below)
return 1; // 1 = # Lua-visible return values on the stack.
突出显示的行的问题在于,它会专门设置package.loaded['b']
以在加载此模块时具有该模块的返回值。这可以通过将行替换为以下内容来解决:
luaL_register(L, "mydir.b", b);
这将改为设置package.loaded['mydir.b']
,从而为以后使用同名模块(不带mydir
前缀)留出空间。
直到我问了这个问题很久之后我才意识到这一点,当我终于有时间阅读 Lua 5.1 的官方 docs for luaL_register
时,这是 LuaJIT 所遵循的版本。
【讨论】:
IIRC,luaopen_whatever() 是使用 require() 中的单个 modname 参数调用的,因此使用它而不是硬编码名称可能更正确。 或使用lua_newtable(L); luaL_register(L, NULL, b);
。从模块内设置全局变量不是最佳实践any more。一个名为 mydir.b
的全局变量无论如何都不会那么有用,因为您必须编写 _G["mydir.b"]
才能实际使用它。以上是关于要求子目录中的 LuaJIT 模块会覆盖父目录中的同名模块的主要内容,如果未能解决你的问题,请参考以下文章
从 Cloud Functions 中的父目录或同级目录导入模块?