Не можете найти .so в той же директории, что и исполняемый файл?

45

У меня есть исполняемый файл, с которым нужно libtest.soдинамически связываться , поэтому я помещаю их в тот же каталог, затем:

cd path_to_dir
./binary

Но получил это:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

Как он не может найти, libtest.soкоторый уже находится в том же каталоге, что и сам исполняемый файл?

linuxer
источник

Ответы:

25

Загрузчик никогда не проверяет текущий каталог на наличие общих объектов, если он явно не направлен на via $LD_LIBRARY_PATH. Смотрите ld.so(8)man-страницу для более подробной информации.

Игнасио Васкес-Абрамс
источник
echo $LD_LIBRARY_PATHна моей машине пусто :(
linuxer
Обычно это так.
Игнасио Васкес-Абрамс
2
Он определяет дополнительные каталоги для загрузчика, чтобы искать библиотеки.
Игнасио Васкес-Абрамс
1
Пути в * nix разделяются двоеточием ( :), а не точкой с запятой.
Игнасио Васкес-Абрамс
3
LD_LIBRARY_PATH, как правило, плохой выбор в производстве. Это хорошо для быстрого взлома и таких вещей, как помощь неустановленным двоичным файлам в поиске общих библиотек при запуске модульных тестов (подумайте ./configure; make; make check). При сборке вашего бинарного файла вы можете либо поместить свою библиотеку в стандартное место (указано в /etc/ld.so.conf), либо передать флаг -R компоновщику, чтобы дать бинарному файлу знать, где искать.
автомат
57

Хотя вы можете установить LD_LIBRARY_PATH, чтобы динамический компоновщик знал, где искать, есть лучшие варианты. Вы можете поместить свою общую библиотеку в одно из стандартных мест, список этих мест см. В /etc/ld.so.conf(для Linux) и /usr/bin/crle(в Solaris)

Вы можете перейти -R <path>к компоновщику при сборке вашего двоичного файла, который добавит <path>в список каталогов, отсканированных для вашей общей библиотеки. Вот пример. Во-первых, показывая проблему:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

Привет:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile (вкладки должны быть использованы):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

Давайте запустим это:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

Как это исправить? Добавьте -R <path>к флагу компоновщика (здесь, путем настройки LDFLAGS).

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

Глядя на двоичный файл, вы можете увидеть, что ему нужно libtest.so.0:

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

Двоичный файл будет искать свои библиотеки, кроме стандартных мест, в указанном каталоге:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

Если вы хотите, чтобы двоичный файл смотрел в текущем каталоге, вы можете установить RPATH в $ORIGIN. Это немного сложно, потому что вам нужно убедиться, что знак доллара не интерпретируется маркой. Вот один из способов сделать это:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!
автоматов
источник
1
Если вы не используете make, например, при ручном вызове g++, попробуйте -Wl,-rpath='$ORIGIN'(обратите внимание на одинарные кавычки), чтобы предотвратить $ORIGINрасширение до пустой строки.
Morpork
14

Чтобы загрузить общие объекты из той же директории, что и ваш исполняемый файл, просто выполните:

$ LD_LIBRARY_PATH=. ./binary

Примечание: это не изменит переменную LD_LIBRARY_PATH вашей системы. Изменение влияет только на это, и только на это, выполнение вашей программы.

лебеди
источник
4

Для любого, кто все еще борется без ответа, я нашел один со следующим предложением:

Вы можете попробовать обновить ld.so.cache, используя: sudo ldconfig -v

Работал на меня.

Ян Фрисби
источник
У меня тоже сработало.
Джоэл
3

Для тех, кто использует CMake для своей сборки, вы можете установить CMAKE_EXE_LINKER_FLAGSследующее:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

Это правильно распространит флаги компоновщика для всех типов сборки (например, Debug, Release и т. Д.), Чтобы сначала искать файлы .so в текущем рабочем каталоге.

Михаил Гольдштейн
источник
0

Динамический компоновщик решит, где искать библиотеки. В случае Linux, динамический компоновщик обычно GNU ld.so(или альтернатива, которая обычно ведет себя идентично по причинам совместимости).

На цитаты из Википедии:

Динамический компоновщик библиотеки GNU C ищет общие библиотеки в следующих местах:

  1. Пути (разделенные двоеточиями) в DT_RPATHатрибуте динамического раздела двоичного файла, если он присутствует, а DT_RUNPATHатрибут не существует.
  2. Пути (разделенные двоеточиями) в переменной среды LD_LIBRARY_PATH, если исполняемый файл не является setuid/ setgidдвоичным, и в этом случае он игнорируется. LD_LIBRARY_PATHможно переопределить, вызвав динамический компоновщик с параметром --library-path (например, /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram).
  3. (Разделенные двоеточиями) пути в DT_RUNPATHатрибуте динамического раздела двоичного файла, если он есть.
  4. Поиск на основе файла кэша ldconfig (часто расположенного по адресу /etc/ld.so.cache), который содержит скомпилированный список библиотек-кандидатов, ранее найденных в пути расширенной библиотеки (установленный /etc/ld.so.conf) Однако, если двоичный файл был связан с параметром -z nodefaultlibкомпоновщика, библиотеки в путях к библиотекам по умолчанию пропускаются.
  5. В доверенном пути по умолчанию /lib, а затем /usr/lib. Если двоичный файл был связан с параметром компоновщика -z nodefaultlib, этот шаг пропускается.

Источник: https://en.wikipedia.org/wiki/Rpath

Mecki
источник