Не можете найти.so в той же директории, что и исполняемый файл?
У меня есть исполняемый файл, который нужно связать с 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
который уже находится в том же каталоге, что и сам исполняемый файл?
9 ответов
Загрузчик никогда не проверяет текущий каталог на наличие общих объектов, если он явно не направлен через $LD_LIBRARY_PATH
, Увидеть ld.so(8)
Страница man для более подробной информации.
Хотя вы можете установить LD_LIBRARY_PATH, чтобы динамический компоновщик знал, где искать, есть лучшие варианты. Вы можете разместить свою общую библиотеку в одном из стандартных мест, см. /etc/ld.so.conf
(в Linux) и /usr/bin/crle
(на Солярисе) для списка этих мест
Вы можете пройти -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!
Чтобы загрузить общие объекты из той же директории, что и ваш исполняемый файл, просто выполните:
$ LD_LIBRARY_PATH=. ./binary
Примечание: это не изменит переменную LD_LIBRARY_PATH вашей системы. Изменение влияет только на это, и только на это, выполнение вашей программы.
Для тех, кто использует CMake для своей сборки, вы можете установить CMAKE_EXE_LINKER_FLAGS
к следующему:
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")
Это правильно распространит флаги компоновщика для всех типов сборки (например, Debug, Release и т. Д.), Чтобы сначала искать файлы.so в текущем рабочем каталоге.
Для любого, кто все еще борется без ответа, я нашел один со следующим предложением:
Вы можете попробовать обновить ld.so.cache, используя: sudo ldconfig -v
Работал на меня.
Могут быть тонкие ситуации, демонстрирующие одни и те же симптомы. Я использую для создания проекта CMake, как локально, так и/path/to/myproj
и удаленно на сервере, по адресу/path/to/myproj-deploy
. Проект содержит.so
построить артефакт и несколько файлов ELF в зависимости от этого.
Когда я извлек двоичные файлы с сервера сборки, я обнаружил, что (локальный) вызов ELF приводит к тем же проблемам. Спасибо automatthias, звоню
$ objdump -p bin/myelf | grep my
bin/myelf: file format elf64-x86-64
NEEDED libmyso.so
RUNPATH /path/to/myproj-deploy/bin
приводит к неудивительному последствию: жестко запрограммированный удаленный путь системы CMake кRUNPATH
, демонстрируя некоторую непереносимость (полагаю, без соответствующих дополнительных действий)
Я получил работу с этим:
$ gcc file.c -L. -lmylib
и запустить:
$ LD_LIBRARY_PATH=. ./a.out
Если ваши зависимости также имеют зависимости, RUNPATH не будет работать (это тег по умолчанию для последних компоновщиков). Чтобы решить эту проблему, вам следует использовать старую версию RPATH, добавив--disable-new-dtags
.
-Wl,--disable-new-dtags,-rpath=path/to/libs
Динамический компоновщик решит, где искать библиотеки. В случае Linux динамический компоновщик обычно GNU ld.so
(или альтернатива, которая обычно ведет себя идентично по причинам совместимости.
На цитаты из Википедии:
Динамический компоновщик библиотеки GNU C ищет общие библиотеки в следующих местах:
- (Разделенные двоеточием) пути в
DT_RPATH
атрибут динамического раздела двоичного файла, если он есть, иDT_RUNPATH
атрибут не существует.- (Разделенные двоеточием) пути в переменной среды
LD_LIBRARY_PATH
, если исполняемый файл не являетсяsetuid
/setgid
двоичный файл, в этом случае он игнорируется.LD_LIBRARY_PATH
можно переопределить, вызвав динамический компоновщик с параметром --library-path (например, /lib/ld-linux.so.2 --library-path $HOME/mylibs myprogram).- (Разделенные двоеточием) пути в
DT_RUNPATH
атрибут динамического раздела двоичного файла, если он есть.- Поиск на основе файла кэша ldconfig (часто находится в
/etc/ld.so.cache
) который содержит скомпилированный список библиотек-кандидатов, ранее найденных в пути расширенной библиотеки (устанавливается/etc/ld.so.conf
). Если, однако, двоичный файл был связан с-z nodefaultlib
опция компоновщика, библиотеки в путях к библиотекам по умолчанию пропускаются.- В доверенном пути по умолчанию
/lib
, а потом/usr/lib
, Если двоичный файл был связан с параметром компоновщика -z nodefaultlib, этот шаг пропускается.
Источник: https://en.wikipedia.org/wiki/Rpath