Скомпилированная версия python: ошибка ModuleNotFoundError при импорте

#python #linux #conda

#python #linux #conda

Вопрос:

У меня есть проект в 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 с библиотекой.

Комментарии:

1. Возможно, было бы полезно сравнить результаты проверки ldd двух двоичных файлов Python. Например, ldd /home/me/.conda/condaenv/proj/bin/python3.7 vs . ldd /home/me/.conda/condaenv/proj/bin/python3.7.bak Не стесняйтесь добавлять эти выходные данные к вопросу.

2. @merv Спасибо за ваше понимание! Я изменил вопрос. Для меня ничего необычного, но, может быть, вы заметите что-то необычное?

3. Да, я тоже ничего не вижу. Я думаю, что ваша идея о флагах компиляции может быть плодотворной. Возможно, стоит проверить исходное сырье для Python на GitHub, чтобы точно увидеть, как выполняется компиляция для сборок Conda (например, Anaconda или Conda Forge). В противном случае не уверен, где еще искать.

4. Возможно, слишком очевидно, но что sys.path в каждом конкретном случае?

Ответ №1:

--without-pymalloc --with-pydebug ./configure Вероятно, причиной ошибки являются флаги и . Замена python3.7 двоичного файла в miniconda на файл, созданный с ./configure --without-pymalloc помощью or ./configure --with-pydebug , предотвращает импорт скомпилированных библиотек, таких как math and numpy . Компиляция без каких-либо флагов (т.Е. ./configure amp;amp; make ) Не вызывает этих ошибок. Компиляция с ./configure --with-valgrind помощью также не вызывает ошибок при импорте скомпилированных библиотек.


Более старый ответ:

Не могли бы вы попробовать настроить флаги, используемые conda-forge? Используя эти флаги, я смог заменить python3.7 двоичный файл в среде conda, и импорт продолжал работать. Если я использовал флаги OP (т. Е. --without-pymalloc --with-pydebug --with-valgrind ), То импорт скомпилированных библиотек не работал (например, math, 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 .

Комментарии:

1. Подтверждено, что это проблема. Однако я нахожу странным, что python readme запрашивает компиляцию с --without-pymalloc --with-pydebug --with-valgrind флагами, когда он предназначен для использования с valgrind, но на практике он не работает с numpy…

2. Python / pip, похоже, «знает», что колесо numpy несовместимо с python, созданным с ./configure --without-pymalloc --with-pydebug --with-valgrind помощью. Если вы устанавливаете numpy с помощью python, созданного вручную, он создает numpy из исходного кода вместо загрузки скомпилированного колеса.

Ответ №2:

Где вы скомпилировали новый Python? Возможно librt.so.1 , причиной сообщения об ошибке является отсутствие библиотеки. Есть ли возможность установить librt пакет (зависит от вашего Linux) и перекомпилировать Python.

Комментарии:

1. Ну, ldd выдает зависимости. Отсутствие librt зависимости от скомпилированной версии означает, что python даже не будет смотреть librt (afaik). Поэтому переустановка не должна ничего менять или, возможно, нарушать рабочую версию, которая зависит от нее.