Принудительно динамический компоновщик для загрузки библиотеки во время выполнения в Linux

Итак, немного истории, у меня есть 3 библиотеки:

  • "lib1.so" без зависимостей
  • "lib2.so", который связан с "lib1.so"
  • "тестовая" исполняемая программа без зависимостей

Что мне нужно, это динамически загружать "lib2.so" во время выполнения из исполняемого файла "test" с помощью метода "dlopen". Проблема в том, что "lib1.so" не может быть загружен автоматически, потому что компоновщик не знает, где его найти.

Я попытался загрузить "lib1.so" сначала так:

void* ptr_lib1 = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
void* ptr_lib2 = dlopen("/usr/local/test/lib2.so", RTLD_NOW | RTLD_GLOBAL);

Но это не работает по какой-то причине, это выдает ошибку после вызова второго dlopen (текст из dlerror):

"lib1.so: cannot open shared object file: No such file or directory"

Это означает, что "lib1.so" пытается быть загружен дважды: первый раз, когда я вызываю dlopen для "lib1.so", и второй, когда я вызываю dlopen для "lib2.so".

Кто-нибудь может объяснить, почему и что нужно сделать, чтобы это исправить? Пожалуйста, не советуйте изменять LD_LIBRARY_PATH перед запуском исполняемого файла. Также не советуем изменять флаги компоновщика исполняемого файла. Мне нужно иметь возможность загружать эту библиотеку во время выполнения из любой папки.

ОБНОВИТЬ. После некоторых исследований я сделал это:

LD_DEBUG=all ./test

И обнаружил, что библиотека lib1.so пытается загрузиться дважды (сначала, когда я вызываю dlopen, затем, когда LD пытается разрешить зависимость для lib2.so"):

add /usr/local/test/lib1.so [0] to global scope
opening file=/usr/local/test/lib1.so [0]; direct_opencount=1
...
    30031:  file=lib1.so [0];  needed by /usr/local/test/lib2.so [0]
 30031: find library=lib1.so [0]; searching
 30031:  search path=./tls/x86_64:./tls:./x86_64:.      (RPATH from file ./test)
 30031:   trying file=./tls/x86_64/lib1.so
 30031:   trying file=./tls/lib1.so
 30031:   trying file=./x86_64/lib1.so
 30031:   trying file=./lib1.so
 30031:  search cache=/etc/ld.so.cache
 30031:  search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64        (system search path)
 30031:   trying file=/lib64/tls/x86_64/lib1.so
 30031:   trying file=/lib64/tls/lib1.so
 30031:   trying file=/lib64/x86_64/lib1.so
 30031:   trying file=/lib64/lib1.so
 30031:   trying file=/usr/lib64/tls/x86_64/lib1.so
 30031:   trying file=/usr/lib64/tls/lib1.so
 30031:   trying file=/usr/lib64/x86_64/lib1.so
 30031:   trying file=/usr/lib64/lib1.so
 30031:
 30031:
 30031: file=/usr/local/test/lib2.so [0];  destroying link map 

Все еще не понимаю, что происходит...

UPDATE2. Есть полный журнал LD_DEBUG

Примечание: есть другая библиотека lib_other.so, просто проигнорируйте ее

3 ответа

Когда dlopen(3) не работает, вы должны использовать dlerror(3), чтобы получить полезное сообщение.

Так что код по крайней мере:

void* ptr_lib1 
   = dlopen("/usr/local/test/lib1.so", RTLD_NOW | RTLD_GLOBAL);
if (!ptr_lib1) {
   fprintf(stderr, "dlopen lib1 failure: %s\n", dlerror());
   exit(EXIT_FAILURE);
}

и аналогично для других dlopens

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

Вы, вероятно, забыли установить какой-либо rpath при связывании lib1.so или же lib2.so, Или вам нужно установить явно LD_LIBRARY_PATHили беги ldconfig

Прочитайте статью Дреппера " Как написать общие библиотеки" для получения подробной информации. Читайте внимательно ld-linux(8)

dlopen из lib2 не удается, потому что его зависимость lib1 не найден. Вы должны это исправить (через rpath, LD_LIBRARY_PATH, ldconfig так далее...)

Вы могли бы добавить некоторые -Wl,-rpath,/usr/local/test/lib1.so в lib1 варианты и т. д.

Вы также можете (проще) решить, что все ваши общие библиотеки /usr/local/lib/ который вы бы упомянули в /etc/ld.so.conf, Тогда вам нужно бежать ldconfig после каждого добавления библиотеки там.

Коренная причина этой проблемы, кажется, в том, что lib1.so является NEEDED от lib2.soЭто происходит потому, что вы связали его во время сборки. Так что просто не связывайте это во время сборки - не упоминайте lib1 вообще при строительстве lib2, Тогда вы можете загрузить его с dlopen() по вашему желанию и lib2 не буду пытаться загрузить его самостоятельно.

У меня похожая проблема, но она просто работает. Я просто использую "RTLD_LAZY" вместо "RTLD_NOW".

Можешь попробовать.

Другие вопросы по тегам