Lua:从不同的工作目录中相对导入失败

我正在尝试将一些由主模块和一些辅助模块组成的Lua库重新打包到Docker容器中。辅助模块被保存在库的子文件夹中,以便从主文件导入时使用

require 'helpers/SomeHelper'

问题是:因为我想让Docker容器以特定方式运行,所以如果我可以从不同的工作目录中调用这个库会非常有帮助。也就是说,我的调用主程序的方式是这样的

th /app/main.lua

而不管我实际站在哪个工作目录。不幸的是,当工作目录与主文件所在的目录不同时,相对导入似乎会失败。

是否有任何方法可以配置LUA_PATH或任何其他机制,使这些导入正常工作?请注意,更改库本身的代码是一种不良解决方案,因为它不是由我开发的,我希望能够轻松地更新它到更新版本。

点赞
用户805875
用户805875

如果您不关心工作目录,可以直接加载 lfs / LuaFileSytem,并使用 lfs.chdir ( src_dir ) 切换到源目录(可能要先用 lfs.currentdir ( ) 保存当前工作目录)。

您还可以扩展 Lua 的搜索路径,以便搜索这些额外的目录。搜索由 package.searchpath 驱动。要以支持所有通常支持的库布局的方式将目录 /foo/bar/ 添加到搜索中,请添加

  • /foo/bar/?.lua;/foo/bar/?/init.luapackage.path
  • /foo/bar/?.so (或其他操作系统上的 .dylib.dll)到 package.cpath

您可以使用多种方式来扩展路径。

一个有效的选项是设置 LUA_PATH / LUA_CPATH 环境变量。(其中一个中的 ;; 序列将扩展到完整的默认路径。)这可以通过 .profile 或其他设置脚本通过早期的 export LUA_PATH="..."(或(如果从包装脚本启动)内联设置变量)来完成。(请注意,如果在过于广泛的范围内导出此变量,则其他 Lua 脚本也将扩展其路径,可能会找到不兼容的 Lua 库。)

(您还可以从 LUA_INIT 手动修改 package.(c)path。这样,您将无法单独禁用 LUA_INITLUA_PATH,但您可以使用所有 Lua 动态生成路径。)

第三种选项(这可能是您特定情况下的最佳选择)是将 package.path 的扩展放在主脚本的顶部,如下所示:

do
   local dir = (arg[0]:match "^(.*)/$")
   if dir then -- else cwd is . which works by default
      package.path = dir.."/?.lua;"..dir.."/?/init.lua;"..package.path
      package.cpath = dir.."/?.so;"..package.cpath
   end
end

-- 此处是您程序的其余部分

在用 Lua 解释器运行脚本时,arg[0] 是该脚本。因此,无论程序位于何处,这将扩展路径以包括程序的目录,并且只会影响此特定脚本/程序的搜索路径。

2017-09-03 19:49:48
用户2328287
用户2328287

你不应该忘记并非所有的模块都是直接从文件系统中加载的。 例如,为了提高性能,可以将文件读取/编译到内存中,然后使用预加载表来提供从内存中加载模块的方法。 基本示例

--- 预加载代码。它可以由主机应用程序完成。
local FooUtils = function()
  return {
    print = function(...)
      print("foo", ...)
    end
  }
end

local Foo = function()
  local Utils = require "foo.utils"
  return {
    foo = function()
      Utils.print"hello"
    end
  }
end

package.preload['foo.utils'] = FooUtils
package.preload['foo'] = Foo

--- 主应用程序
require "foo".foo()

在此示例中,假设FooUtilsFoo只是编译模块的示例。 例如,它可以像FooUtils = loadstring('path/to/utils.lua)一样,甚至可以在单独的Lua状态中完成,然后在任何其他状态中使用。 重要的是要记住,Foo模块不知道主机应用程序如何查找foo.utils。 因此,没有提供原始文件路径或相关路径的标准方法。 因此,如果编写一些依赖于相对路径的模块,则此模块可能在某些环境中无法正常工作。 因此,我建议使用完整的命名空间,例如require 'foo.utils'而不是require 'utils'

2017-09-04 07:11:52