如何使lua在包含require调用的模块所在的同一文件夹中搜索模块?

例如,我有一个项目文件夹:

mxn:lab axn$ tree .
.
├── lib
│   ├── a.lua
│   └── b.lua
└── main.lua

其中main.lua

require("lib.a")

a.lua中,我只是使用了字符串"b",试图告诉lua-首先在a.lua所在的同一文件夹中查找名为b.lua的文件:

require("b")

b.lua中:

print('b loaded!')

然后我运行lua main.lua命令并得到错误:

[Running] lua "/Users/axn/lab/main.lua"
lua: ./lib/a.lua:1: module 'b' not found:
    no field package.preload['b']
    no file './b.lua'
    no file '/usr/local/share/lua/5.1/b.lua'
    no file '/usr/local/share/lua/5.1/b/init.lua'
    no file '/usr/local/lib/lua/5.1/b.lua'
    no file '/usr/local/lib/lua/5.1/b/init.lua'
    no file './b.so'
    no file '/usr/local/lib/lua/5.1/b.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'
stack traceback:
    [C]: in function 'require'
    ./lib/a.lua:1: in main chunk
    [C]: in function 'require'
    /Users/axn/lab/main.lua:1: in main chunk
    [C]: ?

我知道可以使用类似package.path = package.path..';'..'lib/?.lua'的解决方案,但是如果结构更改为:

.
├── foo
│   └── lib
│       ├── a.lua
│       └── b.lua
└── main.lua

我不想再修改package.path。不论结构如何,在a.lua中的require("b")将始终使lua首先搜索与a.lua相同的文件夹中的b

点赞
用户734069
用户734069

与其重写 require 并影响到所有的代码,最好是创建一个专门为这个目的而设计的特殊函数:

-- 在 Lua 5.1 中的实用函数,Lua 5.2 及以后的版本可以使用 table.pack 代替
function pack_params(...)
    return {n = select("#", ...), ...}
end

local curr_local_path = ""

function require_local_path(local_path, ...)
    -- 将旧路径保存在栈中
    local old_path = package.path
    local old_local_path = curr_local_path

    -- 构建新的搜索路径并将其添加到 package.path 的开头
    curr_local_path = curr_local_path .. local_path
    package.path = "./" .. curr_local_path .. "?.lua;" .. package.path

    -- 执行 require,临时存储结果
    local rets = pack_params(require(...))

    -- 修复以前的路径
    package.path = old_path
    curr_local_path = old_local_path

    return unpack(rets, 1, rets.n)
end

注意,这个函数强制你将本地路径与要求模块的名称分开。给定的 local_path 通常期望是最近层次的嵌套调用中的本地路径。同时,它也期望以 / 目录分隔符字符结尾。

如果你绝对需要给它一个单独的字符串而非一个分离的路径,我相信你可以编写一个版本,将给定的模块拆分为一个基本名称和一个本地路径。

2020-04-06 04:59:08
用户4984564
用户4984564

一般来说,你不应该这样做。在 require 中使用 . 是为了子模块,但是 ab 都不是 lib 模块的子模块;那只是你为了组织它们而放在那里。

package.path 正是为了这个目的而存在。你可以像这样做:

package.path = './lib/?.lua;./lib/?/init.lua;' .. package.path

Lua 现在会在 lib 目录中搜索模块(除了它通常搜索的地方)。

你也可以在启动 Lua 前使用 LUA_PATH 环境变量来做到这一点。


否则,如果你真的不想使用使用 package.path 的 "正确" 方法,尝试把下面的代码放在 a.lua 的顶部:

print(...)

它应该会打印类似于

lib.a ./lib/a.lua

这样你就可以得到你想要的效果了。

2020-04-06 08:19:22