Как создать общую библиотеку (.so) без жестко запрограммированных полных путей зависимости? - PullRequest
16 голосов
/ 27 октября 2011

Мне нужно собрать две сторонние разделяемые библиотеки, чтобы их .so файлы были использованы в других проектах. Однако после сборки одна из этих библиотек содержит жестко заданный путь к другой. Этот путь недопустим на других компьютерах и вызывает предупреждения компоновщика. Как я могу предотвратить внедрение полного пути в итоговые файлы .so?

подробности:

Первый источник библиотеки: ~/dev/A
Второй источник библиотеки: ~/dev/B

У них обоих есть скрипт configure для генерации файлов make. Библиотека B зависит от A. Итак, сначала я строю A:

$ ~/dev/A/configure --prefix=~/dev/A-install
$ make && make install

Тогда я строю B:

$ ~/dev/B/configure --prefix=~/dev/B-install --with-A=~/dev/A-install
$ make && make install

Затем я хочу загрузить содержимое ~/dev/A-install и ~/dev/B-install на наш файловый сервер, чтобы другие команды и машины сборки могли использовать двоичные файлы. Но они получают предупреждения компоновщика, когда пытаются использовать B:

/usr/bin/ld: warning: libA.so.2, needed by /.../deps/B/lib/libB.so, not found (try using -rpath or -rpath-link)

Когда я запускаю ldd libB.so, это дает:

...
libA.so.2 => /home/alex/dev/A-install/lib/libA.so.2

Очевидно, этот путь существует только на моей машине и не может быть найден на других машинах.

Как удалить полный жестко заданный путь из libB.so?

Спасибо.

Ответы [ 6 ]

5 голосов
/ 27 октября 2011

Вы должны использовать значение --prefix, которое будет действительным в среде runtime для обоих пакетов!

Чем вы переопределяете prefix или DESTDIR (prefix заменяет префикс, к нему добавляется DESTDIR, но работает более надежно) в командной строке make при установке. Как:

~/dev/A$ ./configure
~/dev/A$ make 
~/dev/A$ make install prefix=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install

или (что является предпочтительным и как все инструменты для создания пакетов используют его):

~/dev/A$ ./configure
~/dev/A$ make 
~/dev/A$ make install DESTDIR=~/dev/A-install
~/dev/B$ ./configure --with-A=~/dev/A-install/usr/local
~/dev/B$ make
~/dev/B$ make install prefix=~/dev/B-install

потому что таким образом вы устанавливаете на ~/dev/A-install/$prefix, поэтому с префиксом по умолчанию ~/dev/A-install/usr/local. Преимущество этого более позднего варианта состоит в том, что если вы переопределите некоторые конкретные пути установки без указания префикса (скажем, --sysconfdir=/etc), к нему все равно будет добавлен DESTDIR, в то время как prefix.

2 голосов
/ 27 октября 2011
-Wl,-rpath,~/deps/A/lib:~/deps/B/lib:~/dev/MyApp/bin

Эта опция компоновщика отвечает за сохранение пути внутри библиотеки.Вам нужно как-то удалить это.

Посмотрите с помощью ./configure --help, если есть какая-то опция, которая может повлиять на это.Другой вариант - отредактировать make-файл вручную и удалить этот параметр.

== edit2 == Еще одна вещь

-L~/deps/A/lib -L~/deps/B/lib ~/deps/A/lib/libA.so ~/deps/B/lib/libB.so

Если libA.so и libB.so не имеют SONAME, связывая их как "~ / deps / A / lib / libA.so", вы также сохраните путь.Soname устанавливается с помощью опции компоновщика -Wl,-soname,<soname> при создании общей библиотеки.

Если soname установлен в общей библиотеке, связать его с помощью формы "~/deps/A/lib/libA.so" можно.

Как упомянуто Янв комментариях лучше использовать "-Llibrary/path -llibrary_name" без rpath.

-L~/deps/A/lib -L~/deps/B/lib -lA -lB
1 голос
/ 18 апреля 2013

Когда я запускаю ldd libB.so, он выдает:

libA.so.2 => /home/alex/dev/A-install/lib/libA.so.2

Низкоуровневое решение этой проблемы заключается в использовании опции "-soname = libA.so" при подключении библиотеки libA.so.Определив SONAME для общего объекта, компоновщик не будет встраивать абсолютные пути при связывании с этим общим объектом.

OP использует «configure», так что это не простое решение для реализации, если он нежелающих войти в недра Makefile, сгенерированного скриптом configure.

0 голосов
/ 01 февраля 2019

Совместно используемые библиотеки и исполняемые файлы имеют список каталогов для поиска общих библиотек, помимо списка в конфигурации операционной системы. RPATH используется для добавления общих путей поиска в библиотеке, используемых во время выполнения. Если вы хотите использовать относительный путь в RPATH, существует специальный синтаксис, который поддерживается большинством систем Linux / UNIX (но не AIX) - $ORIGIN или ${ORIGIN}.
$ORIGIN развернется во время выполнения в каталог, в котором находится двоичный файл - либо библиотека, либо исполняемый файл.

Таким образом, если вы поместите исполняемые двоичные файлы в префикс / bin / и общие библиотеки в prefix/lib/, вы можете добавить запись в RPATH, например ${ORIGIN}/../lib, и она будет расширена во время выполнения до prefix/bin/../lib/

Часто это маленький трюк для получения правильного синтаксиса в Makefile, потому что вам нужно экранировать $ в ORIGIN, чтобы он не расширялся. Обычно это делается в Makefile:

 g++  -Wl,-rpath=\$${ORIGIN}/../lib

И Make, и оболочка захотят поискать в вашей среде переменную с именем ORIGIN - поэтому ее необходимо экранировать дважды.

0 голосов
/ 25 октября 2012

Меня просто поймали на мысли, что у меня такая же проблема. Ни один из приведенных выше ответов не помог мне. Всякий раз, когда я пытался

ldd libB.so 

Я бы получил в выводе:

libA.so.1 => /home/me/localpath/lib/libA.so.1.0

и поэтому я подумал, что у меня жесткий путь. Оказывается, я забыл, что LD_LIBRARY_PATH установлен для локального тестирования. Очистка LD_LIBRARY_PATH означала, что ldd нашел правильную установленную библиотеку в / usr / lib /

0 голосов
/ 27 октября 2011

Возможно, может помочь использование параметров -rpath и -soname для ld (при условии, что пакет binutils или binutils.gold для ld в последней системе Linux)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...