【问题标题】:Lua: relative import fails from different working directoryLua:来自不同工作目录的相对导入失败
【发布时间】:2017-09-03 14:22:55
【问题描述】:

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

require 'helpers/SomeHelper'

问题是:由于我希望 Docker 容器工作的方式,如果我可以从不同的工作文件夹调用这个库,那将非常有帮助。也就是说,我对主程序的调用类似于

th /app/main.lua

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

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

【问题讨论】:

    标签: lua


    【解决方案1】:

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

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

    • /foo/bar/?.lua;/foo/bar/?/init.luapackage.path
    • /foo/bar/?.so(或 .dylib.dll 在其他 OSen 上)到 package.cpath

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

    一个很好的选择是设置LUA_PATH / LUA_CPATH 环境变量。 (其中一个中的;; 序列将扩展为完整的默认路径。)这可以通过.profile 或其他设置脚本通过较早的export LUA_PATH="..." 或(如果从包装脚本启动)通过设置变量内联来完成只是为了那个电话LUA_PATH="..." lua /foo/bar.lua。 (请注意,如果您在太宽的范围内导出此变量,其他 Lua 脚本也会扩展其路径,并且可能会发现可能不兼容的 Lua 库。)

    (你也可以手动修改LUA_INIT中的package.(c)path,这样你就不能独立禁用LUA_INIT或者LUA_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
    
    -- rest of your program goes here
    

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

    【讨论】:

    • 非常完整的答案!由于我将应用程序打包在 Docker 容器中并且不想修改其代码,因此最适合我的选项是更改 LUA_PATH 环境变量。我只需要声明 LUA_PATH="/app/?.lua;/app/helpers/?.lua;;"使要求的操作工作。
    【解决方案2】:

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

    --- preload code. It can be done by host application.
    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
    
    --- main application
    require "foo".foo()
    

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

    【讨论】:

    • 我不明白这应该如何帮助解决这个特定问题。特别是,这如何解决 “请注意,更改库本身的代码将是一个糟糕的解决方案,因为它不是由我开发的,我希望能够轻松地将其更新到较新的版本。 " 部分? (require "foo.bar" inside 使用的库是问题的一部分。)
    • 我只是说不要使用相对路径,因为 lua 不太支持它。可以将/app/?.lua 添加到 LUA_PATH。但它不应该在系统范围内完成,而只适用于这个特定的脚本。例如。通过一些启动脚本
    猜你喜欢
    • 2020-10-25
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多