Установите LD_LIBRARY_PATH перед импортом в Python

Python использует переменную среды PYTHONPATH, чтобы определить, в каких папках следует искать модули. Вы можете поэкспериментировать с ним, изменив sys.path, который хорошо работает для чистых модулей Python. Но когда модуль использует общие объектные файлы или статические библиотеки, он ищет их в LD_LIBRARY_PATH (в linux), но это не так легко изменить и, насколько мне известно, зависит от платформы.

Быстрое решение этой проблемы, конечно, состоит в том, чтобы установить переменную среды или вызвать сценарий, например LD_LIBRARY_PATH=. ./script.py, но тогда вам придется устанавливать его снова для каждой новой оболочки, которую вы открываете. Кроме того, файлы .so в моем случае всегда будут находиться в том же каталоге, что и файл .py, но вполне могут быть перемещены на другой абсолютный путь, поэтому я хотел бы устанавливать их автоматически каждый раз, когда я вызываю сценарий.

Как изменить путь, по которому интерпретатор Python ищет библиотеки независимо от платформы во время выполнения?

РЕДАКТИРОВАТЬ:

Я уже пробовал os.environ['LD_LIBRARY_PATH'] = os.getcwd(), но безуспешно.


person iFreilicht    schedule 23.04.2014    source источник
comment
Вероятно, это должно быть выполнено установщиком модуля путем установки общих библиотек в стандартное (хотя, возможно, зависящее от компьютера) место.   -  person chepner    schedule 23.04.2014
comment
... используя virtualenv :) @chepner   -  person Erik Kaplun    schedule 23.04.2014
comment
@chepner, подумав об этом, при установке программного обеспечения следует учитывать зависимость от платформы. Кроме того, в Windows используются не .so или .a, а файлы .dll и .lib, и мои библиотеки так или иначе придется перекомпилировать для этого. Мне просто казалось, что быстрое и грязное решение облегчит тестирование и разработку.   -  person iFreilicht    schedule 23.04.2014
comment
Я удалил свой ответ в связанной теме и разместил новый вопрос: Попытка импортировать модуль pypyodbc выдает ошибку «Библиотека ODBC не найдена. Настроен ли LD_LIBRARY_PATH? '.   -  person fedorqui 'SO stop harming'    schedule 20.07.2017
comment
Возможный дубликат Изменение LD_LIBRARY_PATH во время выполнения для ctypes   -  person sdikby    schedule 29.08.2018
comment
проверьте это: stackoverflow.com/questions/1178094/   -  person cdarlint    schedule 11.05.2020


Ответы (5)


ОБНОВЛЕНИЕ: см. РЕДАКТИРОВАНИЕ ниже.

Я хотел бы использовать:

import os

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

Это устанавливает переменную среды LD_LIBRARY_PATH для продолжительности / времени жизни выполнения только текущего процесса.

РЕДАКТИРОВАТЬ: похоже, что это необходимо установить перед запуском Python: Изменение LD_LIBRARY_PATH во время выполнения для ctypes

Поэтому я предлагаю использовать сценарий оболочки .sh (или .py, если вы настаиваете). Кроме того, как указал @chepner, вы можете рассмотреть возможность установки ваших .so файлов в стандартном месте (в пределах virtualenv).

См. Также Установка LD_LIBRARY_PATH изнутри Python

person Erik Kaplun    schedule 23.04.2014
comment
извините, я должен был упомянуть, что я уже пробовал это, и это не работает, оператор импорта после этого все еще выдает ImportError, чего не происходит, если я вызываю скрипт с LD_LIBRARY_PATH=. ./script.py. - person iFreilicht; 23.04.2014
comment
мне совершенно непонятно, что должен содержать скрипт-оболочка. - person dbliss; 19.03.2016
comment
Хорошее предложение по установке библиотек в стандартное место внутри virtualenv. - person Ioannis Filippidis; 27.05.2016
comment
Это работает? Я пробовал это в __init__.py в моем скомпилированном pyqt5, чтобы добавить дополнительный путь LD_LIBRARY_PATH к установке maya 2017, но когда я запускаю from PyQt5.QtWidgets import QApplication, QWidget из интерпретатора python, он все еще говорит ImportError: libQt5Widgets.so.5: cannot open shared object file: No such file or directory - person Shuman; 26.07.2016
comment
Попробуйте задать вопрос с помощью тегов Qt, Python, Maya - person Erik Kaplun; 26.07.2016
comment
Этот ответ мне очень помог! Спасибо! - person Manav; 27.04.2020
comment
В качестве альтернативы вы можете установить LD_LIBRARY_PATH и перезапустить интерпретатор Python, используя те же аргументы командной строки. Подробнее см. Stackoverflow.com/a/25457751/603136. - person samwyse; 18.06.2020

Мое решение этой проблемы - поместить это как первую строку скрипта Python (вместо обычного shebang):

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

А вот как это работает:

  • без shebang текущая оболочка обрабатывает файл как сценарий оболочки,
  • "exec" гарантирует, что эта первая строка также будет последней командой из этого файла, выполняемой оболочкой,
  • "env" используется здесь для установки любых переменных среды, например LD_LIBRARY_PATH,
  • можно указать точный путь к интерпретатору Python или "env" может найти его в PATH,
  • "-x" - это параметр Python, который заставляет интерпретатор Python игнорировать первую строку,
  • «$ 0» - это имя скрипта, «$ @» заменяется позиционными параметрами.
person Jarek    schedule 20.04.2018

Python, когда получает значения переменных среды, как в os.environ[‘LD_LIBRARY_PATH’] или os.environ[‘PATH’], он копирует значения в словарь из среды родительского процесса, обычно bash (среда процесса bash переносится в дочерний процесс, запущенный экземпляр python).

вы можете увидеть этот раздел переменных среды с выводом команды env из bash.

вы также можете увидеть / прочитать эти данные env из /proc/<pid>/environ, введя бесконечный цикл (while 1: pass) после изменения любой переменной среды.

Если вы видите / читаете это значение переменной / данные из /proc/<pid>/environ после его изменения внутри скрипта python, вы увидите, что данные реальной переменной не изменяются, хотя скрипт python показывает измененное значение ключа словаря, обновленное.

Что на самом деле происходит, когда вы изменяете переменную env внутри скрипта python, как в os.environ['LD_LIBRARY_PATH']='/<new_location>', так это то, что она просто обновляет значение в локальном словаре, которое не отображается в раздел переменной env процесса. Следовательно, он не будет распространяться полностью назад для отражения в среде текущего процесса, потому что ТОЛЬКО локальный словарь был изменен / обновлен / заполнен.

Следовательно, если мы хотим, чтобы была отражена новая переменная среды, мы должны перезаписать образ памяти процесса новыми данными переменной среды, используя 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.

person Sundeep471    schedule 23.03.2018
comment
относительно этого: But because there is no constant dictionary data type ‹Я уверен, что если бы они попытались, они могли бы разместить элементы только для чтения в mappingproxy (type(type.__dict__)) в _3 _ / _ 4_ модуле var, импортированном в os для статических переменных env, где os.environ может быть экземпляром envdict, объединяющим оба статических и нестатические имена на __getitem__(), но это не так уж важно, поэтому им все равно. ;) - person Tcll; 29.02.2020
comment
возможно, нужно узнать фактическую командную строку, используемую для выполнения программы ... - person Antti Haapala; 08.05.2020

Решение отлично работает, если env повторно запускается

import os

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

Код нужно ввести на место ....

os.execv(sys.argv[0], sys.argv)
person Michele Belotti    schedule 11.08.2020

Начиная с coreutils 8.30, можно использовать env -S для разделения строки shebang на отдельные аргументы:

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

Для совместимости со старыми системами вы можете использовать тот факт, что оболочка позволяет заключать все команды в кавычки, тогда как в python это будут просто строки:

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