【问题标题】:Set LD_LIBRARY_PATH before importing in python在 python 中导入之前设置 LD_LIBRARY_PATH
【发布时间】:2014-06-08 07:02:20
【问题描述】:

Python 使用PYTHONPATH 环境变量来确定它应该在哪些文件夹中查找模块。 您可以通过修改 sys.path 来玩弄它,这对于纯 Python 模块非常有效。 但是当一个模块使用共享对象文件或静态库时,它会在LD_LIBRARY_PATH(在 linux 上)中查找那些,但这不能轻易更改,并且据我所知取决于平台。

这个问题的快速修复当然是设置环境变量或调用像LD_LIBRARY_PATH=. ./script.py这样的脚本,但是你必须为你打开的每个新shell重新设置它。 此外,在我的情况下,.so 文件将始终与.py 文件位于同一目录中,但很可能会移动到另一个绝对路径,所以我想在每次调用脚本时自动设置它们.

如何编辑 Python 解释器在运行时独立于平台查找库的路径?

编辑:

我已经尝试过os.environ['LD_LIBRARY_PATH'] = os.getcwd(),但无济于事。

【问题讨论】:

标签: python import environment-variables sys


【解决方案1】:

更新:请参阅下面的编辑。

我会使用:

import os

os.environ['LD_LIBRARY_PATH'] = os.getcwd()  # or whatever path you want

这会将LD_LIBRARY_PATH 环境变量设置为仅用于当前进程执行的持续时间/生命周期。

编辑:看起来需要在启动 Python 之前进行设置:Changing LD_LIBRARY_PATH at runtime for ctypes

所以我建议使用包装器.sh(或.py,如果你坚持的话)脚本。此外,正如@chepner 指出的那样,您可能需要考虑将.so 文件安装在标准位置(在 virtualenv 中)。

另见Setting LD_LIBRARY_PATH from inside Python

【讨论】:

  • 对不起,我应该提到我已经尝试过了,但它不起作用,之后的导入语句仍然会抛出一个 ImportError,如果我用 LD_LIBRARY_PATH=. ./script.py 调用脚本就不会发生这种情况.
  • 我完全不清楚包装脚本应该包含什么。
  • 将库安装到标准位置 virtualenv 的好建议。
  • 这行得通吗?我在编译的 pyqt5 中的 __init__.py 中尝试了这个,以添加额外的 LD_LIBRARY_PATH 路径到 Maya 2017 安装,但是当我从 python 解释器运行 from PyQt5.QtWidgets import QApplication, QWidget 时,它仍然显示 ImportError: libQt5Widgets.so.5: cannot open shared object file: No such file or directory
  • 尝试用 Qt、Python、Maya 标签提问
【解决方案2】:

我对这个问题的解决方案是将其作为 Python 脚本的第一行(而不是通常的 shebang):

exec env LD_LIBRARY_PATH=/some/path/to/lib /path/to/specific/python -x "$0" "$@"

这就是它的工作原理:

  • 如果没有 shebang,当前 shell 会将文件视为 shell 脚本,
  • "exec" 确保第一行也是 shell 执行的该文件中的最后一条命令,
  • “env”在这里用于设置任何环境变量,例如LD_LIBRARY_PATH,
  • 可以指定 Python 解释器的确切路径,或者“env”可以在 PATH 中找到一个,
  • “-x”是 Python 的一个选项,它会导致 Python 解释器忽略第一行,
  • “$0”是脚本名称,“$@”由位置参数代替。

【讨论】:

    【解决方案3】:

    Python,当获取os.environ[‘LD_LIBRARY_PATH’]os.environ[‘PATH’]中的环境变量值时,它会将值从其父进程的环境中复制到字典中,通常是bash(bash进程的环境get被带到子进程, python运行实例)。

    您可以通过 bash 的 env 命令输出看到此环境变量部分。

    您还可以通过在修改任何环境变量后引入无限循环(while 1: pass) 从/proc/<pid>/environ 查看/读取此环境数据。

    如果您在 python 脚本中修改它之后从/proc/<pid>/environ 看到/读取此变量值/数据,您会看到实际变量的数据没有被修改,尽管 python 脚本显示修改后的字典键值,已更新。

    当你在 python 脚本中修改环境变量时,实际上会发生什么,如os.environ['LD_LIBRARY_PATH']='/<new_location>',它只是更新本地字典中的值,它没有映射到进程的环境变量部分。因此它不会一直传播回来以反映在当前进程的环境中,因为只有本地字典被修改/更新/填充。

    因此,如果我们想让新的环境变量被反映,我们应该用新的环境变量数据覆盖进程的内存映像,使用execv

    示例:

    new_lib = '/<new_location>'
    if not new_lib in os.environ['LD_LIBRARY_PATH']:
        os.environ['LD_LIBRARY_PATH'] += ':'+new_lib
        try:
            os.execv(sys.argv[0], sys.argv)
        except Exception as e:
            sys.exit('EXCEPTION: Failed to Execute under modified environment, '+e)
    
    import xyz
    #do something else
    

    限制:理想情况下,python 不应允许对 os.environ 变量进行此类修改。 但是因为没有常量字典数据类型,它允许修改数据变量。修改值是绝对没有用的,因为它对反映运行进程的真实环境没有任何用处,除非使用execv

    【讨论】:

    • 关于这一点:But because there is no constant dictionary data type type(type.__dict__)) 中的 nt/posix 模块变量导入到os 用于静态环境变量,其中os.environ 可能是一个 envdict 实例,它合并了__getitem__() 上的静态和非静态名称,但这没什么大不了的,所以他们不在乎。 ;)
    • 或许需要找出执行程序的实际命令行...
    • 不,这不应该是只读字典。修改 os.environ 很有用,因为它是传递给子进程的内容(这就是您的 execve 技巧起作用的原因)。 Python 确实将环境复制到dict;它通过getenv/putenv访问进程的环境。您的大点仍然是正确的:更改环境不会影响当前过程。 LD_LIBRARY_PATH 特别是在您的 python 代码运行时已经被咨询过。来自man dlopenIf, at the time that the program was started, the environment variable LD_LIBRARY_PATH was defined...
    【解决方案4】:

    如果 env 重新初始化,解决方案可以正常工作

    import os
    
    os.environ['LD_LIBRARY_PATH'] = os.getcwd()  # or whatever path you want 
    

    代码需要到位......

    os.execv(sys.argv[0], sys.argv)
    

    【讨论】:

      【解决方案5】:

      从 coreutils 8.30 开始,可以使用 env -S 将 shebang 行拆分为单独的参数:

      #!/usr/bin/env -S LD_LIBRARY_PATH=/path/to/lib python options
      

      为了与旧系统兼容,您可以使用 shell 允许将所有命令括在引号中的事实,而在 python 中它将只是字符串:

      #!/bin/sh
      "export" "LD_LIBRARY_PATH=/path/to/lib:$LD_LIBRARY_PATH"
      "exec" "python3" "$0" "$@"
      # Further python program
      import somemodule
      

      【讨论】:

        猜你喜欢
        • 2013-02-13
        • 2011-09-26
        • 1970-01-01
        • 2011-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-22
        • 1970-01-01
        相关资源
        最近更新 更多