Не можете знайти .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що вже є в тому самому каталозі, що і сам виконуваний файл?

Відповіді:


25

Завантажувач ніколи не перевіряє поточний каталог на спільні об'єкти, якщо це прямо не спрямовано до через $LD_LIBRARY_PATH. Детальнішу інформацію див. На ld.so(8)сторінці чоловіка.


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");
}

hello.c:

#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. Ось один із способів зробити це:

$ 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розширенню до порожнього рядка.
Морпорк

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'")

Це дозволить правильно розповсюдити прапорці посилання для всіх типів збірки (наприклад, налагодження, випуск тощо), щоб спочатку шукати файли .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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.