Как указать предпочтение пути к библиотеке?

96

Я компилирую программу на C ++, используя g++и ld. У меня есть .soбиблиотека, которую я хочу использовать при компоновке. Однако библиотека с таким же именем существует /usr/local/libи ldвыбирает эту библиотеку вместо той, которую я прямо указываю. Как я могу это исправить?

В приведенных ниже примерах используется файл моей библиотеки /my/dir/libfoo.so.0. То, что я пробовал, но не работает:

  • моя команда g ++ g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • добавление /my/dirв начало или конец моей $PATHпеременной en`
  • добавление /my/dir/libfoo.so.0в качестве аргумента к g ++
Генрих Шметтерлинг
источник
1
Какие еще libfoo.*файлы существуют и где - .soбез .0, .aи т. Д.?
Alex Martelli

Ответы:

94

Добавьте путь туда, где находится ваша новая библиотека LD_LIBRARY_PATH(на Mac у нее немного другое имя ...)

Ваше решение должно работать с использованием -L/my/dir -lfooопций, во время выполнения используйте LD_LIBRARY_PATH, чтобы указать местоположение вашей библиотеки.

Осторожно с использованием LD_LIBRARY_PATH - вкратце (из ссылки):

..implications ..:
Безопасность : Помните, что каталоги, указанные в LD_LIBRARY_PATH, ищутся до (!) стандартных местоположений? Таким образом, злой человек может заставить ваше приложение загрузить версию разделяемой библиотеки, содержащую вредоносный код! Это одна из причин, по которой исполняемые файлы setuid / setgid игнорируют эту переменную!
Производительность: Загрузчик ссылок должен искать во всех указанных каталогах, пока не найдет каталог, в котором находится разделяемая библиотека - для ВСЕХ разделяемых библиотек, с которыми связано приложение! Это означает множество системных вызовов open (), которые завершатся ошибкой с «ENOENT (Нет такого файла или каталога)»! Если путь содержит много каталогов, количество неудачных вызовов будет линейно увеличиваться, и вы можете определить это по времени запуска приложения. Если некоторые (или все) каталоги находятся в среде NFS, время запуска ваших приложений может действительно увеличиться - и это может замедлить работу всей системы!
Непоследовательность: Это самая частая проблема. LD_LIBRARY_PATH заставляет приложение загружать разделяемую библиотеку, с которой оно не было связано, и это, скорее всего, несовместимо с исходной версией. Это может быть либо очень очевидным, то есть сбой приложения, либо может привести к неверным результатам, если выбранная библиотека не совсем выполняет то, что сделала бы исходная версия. Особенно последнее иногда бывает трудно отладить.

ИЛИ

Используйте параметр rpath через gcc для компоновщика - путь поиска библиотеки времени выполнения, будет использоваться вместо поиска в стандартном каталоге (параметр gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Это хорошее временное решение. Компоновщик сначала ищет библиотеки в LD_LIBRARY_PATH, а затем просматривает стандартные каталоги.

Если вы не хотите постоянно обновлять LD_LIBRARY_PATH, вы можете сделать это на лету из командной строки:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Вы можете проверить, что знает компоновщик библиотек об использовании (пример):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

И вы можете проверить, какую библиотеку использует ваше приложение:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
СтефанБ
источник
23
LD_LIBRARY_PATHищется во время выполнения, во время компиляции, которое вы хотите установить LIBRARY_PATH. См. Gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Бьорн Дальгрен
1
Если ваша библиотека полностью отличается от системной библиотеки, т. Е. Используется всегда, используйте решение rpath. LD_LIBRARY_PATH - это взлом для тестирования, и он не должен требоваться для правильной работы исполняемого файла.
user2746401
1
его DYLD_LIBRARY_PATH для Mac
cbinder
Вот полный пример команды (для C), которая работает на основе этого ответа:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
25

Это старый вопрос, но, кажется, никто об этом не упомянул.

Вам повезло, что эта штука вообще связывает.

Вам нужно было изменить

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

к этому:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Ваш компоновщик отслеживает символы, которые необходимо разрешить. Если он сначала читает библиотеку, в ней нет необходимых символов, поэтому символы в ней игнорируются. Укажите библиотеки после объектов, которые необходимо связать с ними, чтобы у вашего компоновщика были символы, которые можно было найти в них.

Кроме того, -lfooон выполняет поиск файла с именем libfoo.aили по libfoo.soмере необходимости. Нет libfoo.so.0. Так что либо lnназвание, либо переименуйте библиотеку как подходящую.

Процитируем страницу руководства gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Добавление файла непосредственно в g++командную строку должно было сработать, если, конечно, вы не поместили его раньше bar.cpp, из-за чего компоновщик проигнорировал его из-за отсутствия каких-либо необходимых символов, потому что символы еще не нужны.

Майкл Спир
источник
22

Указание абсолютного пути к библиотеке должно работать нормально:

g++ /my/dir/libfoo.so.0  ...

Вы не забыли удалить -lfooпосле добавления абсолютного пути?

R Сэмюэл Клатчко
источник
1
Это решение также отлично сработало для меня - я пытался установить ссылку на версию Qt5, отличную от пакета разработки дистрибутива. Спасибо.
wump
Как заставить это работать для @версионных символов? Минимальный пример: github.com/cirosantilli/cpp-cheat/blob/…
Чиро Сантилли 郝海东 冠状 病 六四 事件
11

В качестве альтернативы вы можете использовать переменные среды LIBRARY_PATHи CPLUS_INCLUDE_PATH, которые соответственно указывают, где искать библиотеки и где искать заголовки ( CPATHтакже будут выполнять эту работу), без указания параметров -L и -I.

Изменить: CPATHвключает заголовок с -Iи CPLUS_INCLUDE_PATHс -isystem.

Александр Хамес
источник
Не могли бы вы добавить пример для использования?
Hanna Khalil
export LIBRARY_PATH = /path/to/libв том же консольном сеансе, где вы компилируете
Александр Хамез
0

Если кто-то используется для работы с DLL в Windows и вы хотите пропустить номера версий .so в linux / QT, добавление CONFIG += pluginприведет к удалению номеров версий. Чтобы использовать абсолютный путь к .so, передача его компоновщику работает нормально, как сказал г-н Клатчко.

Пекка Лехтикоски
источник