Принудительно динамический компоновщик для загрузки библиотеки во время выполнения в 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);
}
и аналогично для других dlopen
s
Заметить, что 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".
Можешь попробовать.