【问题标题】:Compiled python version: ModuleNotFoundError at import编译的python版本:ModuleNotFoundError at import
【发布时间】:2020-09-24 15:13:56
【问题描述】:

我在conda 环境中有一个项目,该项目使用 python 3.7.7(在 linux 上)运行。当我重新编译相同版本的python(3.7.7)并将可执行文件放在/替换相同位置时,我希望程序以相同的方式运行,但导入失败。

用原版python:

(condaenv) mypc:~/Proj$ /home/me/.conda/envs/condaenv/bin/python3.7.bak
Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gym
>>> quit()

编译后的版本:

(condaenv) mypc:~/Proj$ /home/me/.conda/condaenv/proj/bin/python3.7
Python 3.7.7 (default, Sep 24 2020, 16:28:06) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import gym
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'gym'
>>> quit()

环境变量应该与我从同一位置、同一终端上运行的环境变量相同,而不会在两次调用之间更改它。由于第一次导入没有任何问题,因此软件包已安装良好。

sys 等系统导入在两个版本中都可以正常工作,但我必须在编译版本之前导出LD_LIBRARY_PATH,而“正常”版本则不是这种情况。但是在两次调用之间保持LD_LIBRARY_PATH 不变不会改变任何东西。

第二次调用找不到匹配的包怎么办?我错过了什么?

-- 编辑 1 --

编译后的版本共享对象依赖如下:

$ ldd python3.7
        linux-vdso.so.1 (0x00007ffed457a000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f63e53a6000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f63e53a0000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f63e539b000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f63e524c000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f63e505a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f63e577f000)

原python如下:

$ ldd python3.7.bak 
        linux-vdso.so.1 (0x00007ffc0d1c8000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f89ab6bc000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f89ab4ca000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f89ab4c4000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f89ab4bf000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f89ab4b4000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f89ab365000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f89aba80000)

版本略有不同,因为它们不是用相同版本的编译器编译的(我猜)。然而,令我惊讶的是,新版本不需要librt.so,但原始版本需要。这可能是因为编译标志阻止了优化。我在配置步骤中添加了--without-pymalloc --with-pydebug --with-valgrind。但我认为它不应该干扰 python 库的正常行为。

【问题讨论】:

  • 或许比较在两个 Python 二进制文件上检查 ldd 的输出会有所帮助。例如,ldd /home/me/.conda/condaenv/proj/bin/python3.7ldd /home/me/.conda/condaenv/proj/bin/python3.7.bak。随意将这些输出添加到问题中。
  • @merv 感谢您的洞察!我修改了问题。对我来说没有什么不寻常的,但也许你会注意到一些不寻常的东西?
  • 是的,我也没有看到太多。我认为您关于编译标志的想法可能是富有成效的。也许值得在 GitHub 上查看 Python 的原料,以确切了解如何为 Conda 构建(例如 Anaconda 或 Conda Forge)完成编译。否则不知道还能去哪里看。
  • 也许太明显了,但sys.path 在每种情况下是什么?

标签: python linux conda


【解决方案1】:

./configure--without-pymalloc--with-pydebug 标志可能会导致错误。将 miniconda 中的 python3.7 二进制文件替换为使用 ./configure --without-pymalloc./configure --with-pydebug 构建的二进制文件可防止导入已编译的库,例如 mathnumpy。不带任何标志(即./configure &amp;&amp; make)的编译不会导致这些错误。使用./configure --with-valgrind 进行编译也不会在导入已编译的库时引发错误。


旧答案:

你能试试configure flags used by conda-forge吗?使用这些标志,我能够在 conda 环境中替换 python3.7 二进制文件,并且导入继续工作。如果我使用了 OP 的标志(即--without-pymalloc --with-pydebug --with-valgrind),那么导入已编译的库将不起作用(例如,数学、numpy)。

curl -L https://www.python.org/ftp/python/3.7.7/Python-3.7.7.tar.xz | tar xJ
cd Python-3.7.7
./configure \
    --prefix=/tmp/python3.7 \
    --enable-ipv6 \
    --with-ensurepip=no \
    --with-computed-gotos \
    --with-system-ffi \
    --enable-loadable-sqlite-extensions \
    --with-lto \
    --enable-optimizations \
    --with-valgrind
make -j

解决方案涉及这些标志之一——可能是--with-lto--enable-optimizations

【讨论】:

  • 确认,就是这个问题。我觉得奇怪的是,python 自述文件在设计为与 valgrind 一起使用时要求使用--without-pymalloc --with-pydebug --with-valgrind 标志进行编译,但它不适用于 numpy...
  • Python/pip 似乎“知道”numpy 轮子与使用./configure --without-pymalloc --with-pydebug --with-valgrind 构建的python 不兼容。如果您使用手动构建的 python 安装 numpy,那么它会从源代码构建 numpy,而不是下载已编译的轮子。
【解决方案2】:

您在哪里编译了新的 Python?可能是缺少 lib librt.so.1 是错误消息的罪魁祸首。有没有机会安装 librt 包(取决于你的 Linux 风格)并重新编译 Python。

【讨论】:

  • 好吧,ldd 给出了依赖关系。没有librt 作为对编译版本的依赖意味着python 甚至不会查看librt(afaik)。所以重新安装它不应该改变任何东西,或者可能会破坏依赖它的工作版本。
猜你喜欢
  • 2020-12-03
  • 2020-08-29
  • 1970-01-01
  • 2022-10-23
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 2020-09-14
  • 1970-01-01
相关资源
最近更新 更多