В чем разница между LD_LIBRARY_PATH и -L во время соединения? - PullRequest
23 голосов
/ 15 декабря 2009

У меня проблемы с LD_LIBRARY_PATH при ссылке времени (этот вопрос не имеет отношения ко времени выполнения).

Строка ссылки выглядит так, когда я запускаю make (это система Linux, использующая g ++ версии 4.1.x):

g++ a.o b.o c.o -o myapp \
 -L/long/path/to/libs/ \
 -L/another/long/path/ \
 -labc -ldef -lghi

Опции -l ссылаются на общие библиотеки (например, libabc.so), которые существуют в каталогах, указанных параметрами -L. Эти каталоги также появляются в LD_LIBRARY_PATH. С такой конфигурацией связь установлена ​​успешно, и я могу запустить приложение.

Если я удаляю каталоги из LD_LIBRARY_PATH, я получаю одну строку с ошибкой, такую ​​как:

/usr/bin/ld: cannot find -labc

С другой стороны, если я удаляю каталоги из списка -L параметров, я получаю много предупреждений, таких как:

/usr/bin/ld: warning: libabc.so, needed by /long/path/to/libs/libxyz.so,
    not found (try using -rpath or -rpath-link)

, а затем еще много ошибок, таких как:

/long/path/to/libs/libdef.so: undefined reference to `Foo::Bar<Baz>::junk(Fred*)'

Может кто-нибудь объяснить разницу между LD_LIBRARY_PATH и -L? Я хотел бы понять это подробно, поэтому ссылки очень ценятся!

Кроме того, что я должен добавить к строке ссылки, чтобы избежать использования LD_LIBRARY_PATH?

EDIT: Когда каталоги отсутствовали в -L, компилятор предложил «попробовать использовать -rpath или -rpath-link». Я не думаю, что когда-либо видел эти варианты в make-файле. У тебя есть? Не уверен, что это поможет решить проблему LD_LIBRARY_PATH.

Ответы [ 5 ]

32 голосов
/ 15 декабря 2009

Есть два ответа на этот вопрос, часть ответа заключается в компоновке во время компиляции (т.е. gcc -lfoo -L/usr/lib ..., которая, в свою очередь, вызывает ld), и поиске компоновщика во время выполнения.

Когда вы компилируете свою программу, компилятор проверяет синтаксис, и затем компоновщик гарантирует, что символы, необходимые для выполнения, существуют (например, переменные / методы / и т. Д.), Среди прочего. LD_LIBRARY_PATH, как было отмечено, имеет побочный эффект изменения способа поведения gcc / ld, а также поведения компоновщика во время выполнения путем изменения пути поиска.

Когда вы запускаете вашу программу, компоновщик во время выполнения фактически выбирает общие библиотеки (на диске или из памяти, если это возможно) и загружает в совместно используемые символы / код / ​​и т. Д. Опять же, LD_LIBRARY_PATH неявно влияет на этот путь поиска (иногда не очень хорошая вещь, как уже упоминалось.)

Правильное решение этой проблемы без использования LD_LIBRARY_PATH в большинстве систем Linux - добавить путь, содержащий ваши общие библиотеки, в /etc/ld.so.conf (или в некоторых дистрибутивах создать файл в /etc/ld.so.conf.d/ с путем в нем) и запустите ldconfig (/sbin/ldconfig от имени пользователя root), чтобы обновить кэш привязок компоновщика среды выполнения.

Пример в Debian:

jewart@dorfl:~$ cat /etc/ld.so.conf.d/usrlocal.conf 
/usr/local/lib

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

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

jewart@dorfl:~$ ldconfig -v 

/usr/lib:
libbfd-2.18.0.20080103.so -> libbfd-2.18.0.20080103.so
libkdb5.so.4 -> libkdb5.so.4.0
libXext.so.6 -> libXext.so.6.4.0

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

jewart@dorfl:~$ ldd /bin/ls
linux-vdso.so.1 =>  (0x00007fffda1ff000)
librt.so.1 => /lib/librt.so.1 (0x00007f5d2149b000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00007f5d2127f000)
libacl.so.1 => /lib/libacl.so.1 (0x00007f5d21077000)
libc.so.6 => /lib/libc.so.6 (0x00007f5d20d23000)
20 голосов
/ 15 декабря 2009

Настройки LD_LIBRARY_PATH имеют наивысший приоритет, поэтому, когда он установлен, поиск по каталогам, упомянутым LD_LIBRARY_PATH, выполняется в первую очередь, даже до стандартного набора
каталогов. Так что в вашем случае настройка LD_LIBRARY_PATH влияет на поиск
библиотеки, указанные с параметром -l. Без LD_LIBRARY_PATH некоторых зависимостей
возможно, были решены из стандартного набора каталогов.

Хотя установка LD_LIBRARY_PATH поможет с отладкой и опробовать более новую версию
использование библиотеки в общей среде разработки и развертывания считается плохим.

Также см. этот документ HOWTO из документации Linux для получения дополнительной информации об общих библиотеках

8 голосов
/ 15 декабря 2009

LD_LIBRARY_PATH предназначен для поиска общих библиотек при запуске приложения. Это побочный эффект, который влияет на вашу ссылку, и вы не должны на это полагаться.

Как часто нежелательный побочный эффект, LD_LIBRARY_PATH также будет найден на этапе ссылки (ld) после каталогов указывается с помощью -L (также если нет флага -L дано).

Почему LD_LIBRARY_PATH плохой

3 голосов
/ 15 декабря 2009

Если бы я догадался, я бы сказал, что компоновщик возвращается к использованию LD_LIBRARY_PATH для разрешения библиотек, с которыми динамически связаны ваши прямые ссылки (например, libabc.so, libdef.so и libghi.so) , Глядя на страницу руководства для ld, похоже, что связывание с .so, созданным с использованием -rpath, повлияет на работу поиска динамически связанных символов.

1 голос
/ 04 декабря 2013

Проверяя человека на g ++, я обнаружил, что опция -lxxxxx ищет libxxxxx.a в указанном пути -L, поэтому во время компоновки будет загружен только файл .a. Во время выполнения, если библиотека отсутствует, то будет загружена только библиотека как общий объект, поэтому .so будет выглядеть и LD_LIBRARY_PATH. В исполняемом файле, над которым я работаю, я вижу, что в некотором каталоге библиотеки есть версии libxxxx.a и libxxxx.so, поэтому я думаю, что это означает, что библиотека может быть связана во время компоновки или связана во время выполнения как общий объект.

Если библиотека существует только как общий объект, то это означает, что путь к каталогу библиотеки должен быть LD_LIBRARY_PATH, чтобы быть найденным во время выполнения. Если библиотека существует только в виде архива, то есть .a, то это означает, что ее необходимо связать при сборке исполняемого файла, а затем необходимо указать -L directorypath и -lxxxxx на g ++ во время компиляции.

Это мое понимание .... и, по крайней мере, оно соответствует вашим наблюдениям

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