Общие зависимости библиотеки с distutils

Я новичок в distutils, и у меня есть проблема, из-за которой я действительно застрял. Я компилирую пакет, для которого требуется расширение, поэтому я делаю расширение следующим образом:

    a_module = Extension(
          "amodule",
          ["initmodule.cpp"],
          library_dirs=libdirs,
          extra_objects = [
                    "unix/x86_64/lib/liba.so"
                    "unix/x86_64/lib/lib.so",
                    "unix/x86_64/lib/libc.so"],
    )

Затем я запускаю метод установки:

    setup(name="apackage", version="7.2",
      package_dir = {'':instdir+'/a/b/python'},
      packages=['apackage','package.tests'],
      ext_modules=[hoc_module]
)

Распределение пакетов выполнено правильно, и я могу «установить python setup.py» в порядке, но когда я пытаюсь импортировать свой пакет, я получаю сообщение об ошибке ImportError: liba.so.0: cannot open shared object file: No such file or directory

Я понимаю, что когда я добавляю местоположение liba.so.0 в свой LD_LIBRARY_PATH, программа работает нормально. К сожалению, я не писал эти модули и плохо разбираюсь в компиляции. Я пытался понять это в течение нескольких дней безрезультатно.

ОБНОВЛЕНИЕ: я попытался передать файлы liba.a, libb.a и т. д. в extra_objects, но это не сработало, и возникла следующая ошибка: liba.a: не удалось прочитать символы: неверное значение collect2: ld вернул 1 статус выхода. То, что я пытаюсь сделать, это упаковать модуль python, который требует компиляции библиотеки, которая сама зависит от других библиотек, которые мне нужно как-то включить в пакет. Я подозреваю, что моя проблема очень похожа на эту: http://mail.python.org/pipermail/distutils-sig/2009-February/010960.html но это не было разрешено, я подумал, может быть, с тех пор, как ему два года, решение было найдено?

ОБНОВЛЕНИЕ 2. На данный момент я решил это, выполнив следующие действия:

      data_files=[('/usr/local/lib', glob.glob('unix/x86_64/lib/*'))]

То есть я копирую нужные мне библиотеки в /usr/local/lib. Однако я не очень доволен этим решением, не в последнюю очередь потому, что оно требует от моих пользователей прав root, а также потому, что это может по-прежнему не работать с дистрибутивами Redhat. Поэтому, если кто-то может предложить что-то лучше, чем это исправление, пожалуйста, дайте мне знать.


person Mike Vella    schedule 20.03.2012    source источник


Ответы (2)


Вы можете сделать так, чтобы компоновщик хранил пути для поиска в выходном двоичном файле, поэтому LD_LIBRARY_PATH не требуется. Некоторые примеры:

# Will link fine but at run-time LD_LIBRARY_PATH would be required
gcc -o blah blah.o -lpcap -L/opt/csw/lib

# Without LD_LIBRARY_PATH=/opt/csw/lib it will fail to link, but
# it wouldn't be needed at run-time
gcc -o blah blah.o -lpcap -Wl,-R/opt/csw/lib

# LD_LIBRARY_PATH not needed at link or run-time
gcc -o blah blah.o -lpcap -Wl,-{L,R}/opt/csw/lib

# This makes it possible to use relative paths; run `readelf -d binary_name`
# and you'll see '$ORIGIN/../lib/' in RPATH.  This plus `-zorigin` make it look
# relative to the binary for libraries at run-time
gcc -o blah blah.o -lsomelib -L/whatever/path/floats/your/boat -Wl,-R'$ORIGIN/../lib/' -Wl,-zorigin

.. куда:

  • пути, указанные с помощью -L, используются во время link-time
  • пути, указанные с помощью -R, используются во время времени выполнения
person Brian Vandenberg    schedule 20.04.2012
comment
Фантастический ответ, объединив ваш ответ с этим sebsauvage.net/python/mingw.html, я был способный построить нужный модуль именно таким образом, как требуется. Большое спасибо. - person Mike Vella; 23.04.2012
comment
Не проблема, я рад, что смог помочь - person Brian Vandenberg; 23.04.2012
comment
К вашему сведению: вместо добавления опции -R'$ORIGIN/../lib/' вы можете добавить runtime_library_dirs="$ORIGIN/../lib/" к вашему определению Extension (на практике это делает то же самое). - person David Robinson; 12.07.2012
comment
Однако имейте в виду, что runtime_library_dirs зависит от Python. - person Brian Vandenberg; 12.07.2012
comment
Я должен был предупредить/предупредить что-то при использовании $ORIGIN: ldd будет использовать только полные пути во время выполнения, если приложение запускается с suid/setuid. Не каждая ОС справляется с этим одинаково; некоторые могут просто пропускать пути с $ORIGIN полностью, другие, которые я видел, просто используют строку дословно (т.е., используя truss/strace, вы увидите попытку открыть $ORIGIN/../lib/libsomelib.so). - person Brian Vandenberg; 01.10.2013
comment
Мне пришлось использовать -Xlinker -R с gcc, а не просто -R при компиляции. Это делается для того, чтобы аргумент был передан на этап компоновки, а не на этап компиляции. - person Tobias Bergkvist; 24.09.2020
comment
работает ли runtime_library_dirs, когда пользователь устанавливает колесо? это время выполнения связано с созданием колеса или с установкой колеса? - person Chaitanya Bapat; 11.01.2021

Аргумент extra_objects для класса Extension — это не столько список библиотек, которые нужно связать с вашим расширением, сколько список объектных файлов, которые будут переданы компоновщику (и имена файлов не должны включать расширения, так как distutils добавит их. ) Это не делает то, что вы, кажется, хотите.

Если вы хотите выполнить компоновку с определенными разделяемыми библиотеками, как следует из названий этих файлов, вы должны сделать две вещи: сказать distutils, чтобы компилятор компоновался с этими разделяемыми библиотеками, и сообщить динамическому компоновщику (обычно ld.so), где чтобы найти эти общие библиотеки. Вы можете сообщить distutils, чтобы компилятор компоновал библиотеки, используя аргумент libraries для Extension, который должен быть списком имен библиотек (без префикса lib и суффикса .so). В вашем примере это выглядит как ['a', 'b', 'c'] (хотя это похоже, что 'b' выпало из 'lib.so', а 'c' фактически столкнулось бы с системной libc.)

Сообщить компоновщику, где найти эти общие библиотеки, можно, установив переменную среды LD_LIBRARY_PATH, как вы это сделали, или изменив общесистемный параметр конфигурации (с помощью ldconfig или отредактировав /etc/ld.so.conf), или жестко запрограммировав путь поиска в расширении. модуль; вы можете сделать последнее, передав аргумент runtime_library_dirs в Extension. Однако у жесткого кодирования пути есть свои проблемы — вы должны хранить эти библиотеки в одном месте и быть доступными для всех пользователей модуля расширения.

(В качестве альтернативы вы можете использовать статическое связывание вместо динамического, например, предоставляя библиотеки только в статической форме, liba.a архивах (в этом случае distutils будет автоматически связываться с ними статически). Это в основном означает, что вся библиотека включена в модуль расширения. , который имеет различные недостатки и преимущества.)

person Thomas Wouters    schedule 20.03.2012
comment
Большое спасибо за ваш подробный и отличный ответ. Правильно ли я понимаю, что тогда runtime_library_dirs должен быть установлен как относительный путь, иначе я не понимаю, как его можно жестко запрограммировать? Кроме того, следует ли передавать статически связанные библиотеки (т. е. архивы liba.a) библиотекам или ключевым словам extra_objects. К сожалению, документация не очень помогает мне в этих двух вопросах. - person Mike Vella; 21.03.2012
comment
Передача относительного каталога как runtime_library_dirs может быть выполнена, но это не очень хорошая идея (поскольку модуль расширения перемещается в процессе сборки, и один и тот же путь должен работать для всех). Что касается статического связывания, вы можете попробовать передать .a архивирует в качестве аргумента extra_objects, хотя extra_objects не для этого, и я не уверен, что это сработает. Возможно, вам следует уточнить, что вы на самом деле хотите сделать. - person Thomas Wouters; 21.03.2012
comment
Спасибо за ваш ответ, я добавил некоторые подробности в свой первоначальный вопрос. - person Mike Vella; 21.03.2012
comment
ОК, я понял, что способ решить мою проблему — разместить библиотеки в /usr/lib. Я понимаю, что это не совсем идеально, но есть ли какая-то важная причина, по которой мне не следует этого делать? - person Mike Vella; 21.03.2012
comment
Нет, размещение разделяемых библиотек в местах, уже учитываемых динамическим компоновщиком, является обычной практикой. Единственная причина не делать этого — если что-то еще, например, диспетчер пакетов ОС, контролирует /usr/lib, и в этом случае ваши файлы могут помешать при последующей установке какого-либо другого пакета ОС. /usr/local/lib - лучший выбор (и существует именно для этой цели). Вы также можете использовать какое-то другое место и указать динамическому компоновщику рассмотреть его (через /etc/ld.so.conf или команду ldconfig -m или что-то подобное). - person Thomas Wouters; 22.03.2012
comment
Кажется, что он хорошо работает с /usr/local/lib, однако меня беспокоит то, что я иду по этому маршруту, потому что не выполняется поиск общих объектов в Redhat/Fedora. Есть ли общепринятый способ справиться с этой ситуацией? - person Mike Vella; 22.03.2012
comment
Почему параметр с именем runtime_library_dirs может влиять на фазу компиляции или компоновки? Я ожидаю, что это будет папка, возможно, включенная в яйцо python, которое содержит .so или подобное, используемое всякий раз, когда вы делаете import some_package (то есть во время выполнения). Это то, что предполагает название, а также то, что я бы сделал из документации здесь: docs.python .org/3.5/distutils/apiref.html - person Herbert; 24.06.2016