【问题标题】:Setting LD_LIBRARY_PATH from inside Python从 Python 内部设置 LD_LIBRARY_PATH
【发布时间】:2011-09-26 11:53:48
【问题描述】:

有没有办法设置指定在运行时 Python 查找共享库的位置?

我有位于fontforge_binfontforge.so 并尝试了以下操作

os.environ['LD_LIBRARY_PATH']='fontforge_bin'
sys.path.append('fontforge_bin')
import fontforge

得到

ImportError: fontforge_bin/fontforge.so: cannot open shared object file: No such file or directory

fontforge_bin/fontforge.so 上执行ldd 会得到以下结果

linux-vdso.so.1 =>  (0x00007fff2050c000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f10ffdef000)
libc.so.6 => /lib/libc.so.6 (0x00007f10ffa6c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f110022d000)

【问题讨论】:

  • 如果我在运行脚本之前执行export LD_LIBRARY_PATH=fontforge_bin,这将有效,现在我想从脚本内部设置它
  • 使用sys.path.append 是正确的方法,从错误消息中可以看出,它确实尝试打开它。我建议您使用目录的完整路径名,而不是相对路径名。

标签: python linux fontforge


【解决方案1】:

LD_LIBRARY_PATH 设置动态链接器路径;通常不能在运行时更改,因为它通常由动态链接器缓存。

这不是 Python 寻找 imports 的地方,包括模块导入。更改sys.path 是正确的。

# ls foo/
_csv.so
# python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48)
>>> import sys
>>> sys.path.insert(0, "foo")
>>> import _csv
>>> _csv.__file__
'foo/_csv.so'

(顺便说一下,您可能想 ldd 库,看看库中是否有任何奇怪的导入路径。“ImportError: fontforge_bin/fontforge.so”看起来很奇怪。)

【讨论】:

  • 我在我的问题中添加了 ldd 输出,不确定它是否符合奇数。但是 fontforge_bin 中有 3 个必需的库,我认为链接器找不到。我发现了另一种奇怪的链接器错误消息——当我尝试在 32 位 Python 下加载 64 位“fontforge.so”时,当它尝试加载“fontforge.so”时我得到“找不到文件”
【解决方案2】:

您的脚本可以在导入模块之前检查环境变量的存在/正确性,然后在 os.environ 中设置它是否丢失,然后调用os.execv() 使用相同的命令行重新启动 python 解释器参数,而是一组更新的环境变量。

这仅在任何其他导入(除了 os 和 sys)之前 是可取的,因为潜在的模块导入副作用,例如打开的文件描述符或套接字,可能难以干净地关闭.

此代码设置 LD_LIBRARY_PATH 和 ORACLE_HOME:

#!/usr/bin/python
import os, sys
if 'LD_LIBRARY_PATH' not in os.environ:
    os.environ['LD_LIBRARY_PATH'] = '/usr/lib/oracle/XX.Y/client64/lib'
    os.environ['ORACLE_HOME'] = '/usr/lib/oracle/XX.Y/client64'
    try:
        os.execv(sys.argv[0], sys.argv)
    except Exception, exc:
        print 'Failed re-exec:', exc
        sys.exit(1)
#
# import yourmodule
print 'Success:', os.environ['LD_LIBRARY_PATH']
# your program goes here

将环境变量设置为启动环境的一部分(在父进程或 systemd/etc 作业文件中)可能更简洁。

【讨论】:

  • 这可能仅适用于 linux 和其他 unix 变体。我不知道它是否适用于 Windows 或 Darwin。
  • 看来apache只接受来自/etc/sysconfig/httpd的LD_LIBRARY_PATH。上面提到的方法不适用于我的情况。
  • 不要在reticulate内尝试这个。
  • 如果 os.environ 中有 'LD_LIBRARY_PATH'?
【解决方案3】:

...好吧,您可以通过 ctypes 从您选择的某个文件夹中加载所有库,从而使它们对您可用,而不管 LD_LIBRARY_PATH 是什么。

from ctypes import *
lib1 = cdll.LoadLibrary('/home/username/lib/some_library.so')

或遍历该目录中的文件......你明白了,一旦加载它就在那里[如果依赖项也超出默认路径,你也应该加载它们......]。

【讨论】:

  • 对我不起作用。随后导入使用它的模块时仍然找不到该库。
  • 我确认此解决方案在与问题中描述的场景非常相似的场景中工作。在 Linux (Ubuntu 16.04) 中。需要在同一本地路径中导入依赖于 libfoo.so 的本机 Python 模块 foo.so。首先,我尝试在 foo.so 中将 RPATH 设置为 $ORIGIN/.。只有当我在同一目录中运行脚本时它才有效。
  • 请记住,不要在 32 位 python 中加载 64 位 dll/so 文件,反之亦然。
  • 如果你的so文件有更多的依赖,这不起作用....
  • 这对我有用 lightgbm...used: cdll.LoadLibrary('/mnt/data-science/miniconda3/lib/libgomp.so.1')
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-31
  • 2020-05-24
  • 1970-01-01
相关资源
最近更新 更多