Dlopen() возвращает 0

В моем каталоге у меня есть два файла. Один foo.cpp, другой bar.so. В foo.cpp я пытаюсь загрузить библиотеку bar.so:

#include <dlfcn.h>
#include <iostream>

int main()
{
    void* handle = dlopen("bar.so", RTLD_NOW | RTLD_GLOBAL);
    std::cout << handle << std::endl;
    return 0;
}

Затем в этом же каталоге я компилирую код из командной строки с помощью:

g++ foo.cpp -ldl -o test

Однако при выполнении test выводится 0, и согласно документации для dlopen:

If dlopen() fails for any reason, it returns NULL

Так почему же это возвращает NULL, когда файл библиотеки находится в том же каталоге, что и файл CPP?


Обновлять:

Теперь я добавил dlopen() в свой файл CPP, и это выводит:

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

Но я не понимаю... bar.so и foo.cpp находятся в одном каталоге, исполняемый файл создается в этом же каталоге, и я нахожусь в этом же каталоге, когда запускаю исполняемый файл.

Итак, я попытался использовать абсолютный путь для bar.so, но затем получаю новую ошибку:

invalid ELF header

После быстрого поиска в Google я думаю, что это может быть связано с моей установкой Ubuntu. На самом деле я использую MacBook и установил родную копию Ubuntu (а не виртуальную машину). Кажется, что это вызывает проблему, но я не знаю, как это исправить. Возможно, этот файл библиотеки просто не будет работать на MacBook Ubuntu.

Не могу сказать вам, почему это не удается, может быть любая из ряда причин. Вы должны просто напечатать dlerror() и посмотреть, что там написано.

StoryTeller - Unslander Monica 10.06.2019 22:17

Вывести dlerror(). Это должно дать вам хорошее направление. Вы можете отредактировать сообщение с выводом dlerror().

Naseef Chowdhury 10.06.2019 22:18

Используйте objdump в исполняемом файле, чтобы увидеть, есть ли запись RPATH, в которой указан каталог, содержащий библиотеку.

Barmar 10.06.2019 22:21

Вам нужно "./bar.so". В противном случае dlopen() не будет искать файл в текущем каталоге.

Nikos C. 10.06.2019 22:25

Однако другое решение — добавить -Wl,-rpath='$ORIGIN' к флагам компиляции при компиляции foo.cpp. Таким образом, не имеет значения, какой текущий каталог. dlopen() всегда будет сначала искать в каталоге исполняемого файла. Но обратите внимание, что это приведет к тому, что все библиотеки будут искать в текущем каталоге в первую очередь, а не только те, которые вы пытаетесь найти dlopen(). Это может быть или не быть тем, что вы хотите. Абсолютно лучшее решение - получить каталог исполняемого файла и среды выполнения и использовать его вместо этого.

Nikos C. 10.06.2019 22:33

Первое, что нужно изменить, это ./bar.so, как предлагает @Nikos. Во-вторых, попробуйте разные dlopen флаги. Debian и Red Hat различаются тем, что им требуется для dlopen. Попробуйте и RTLD_GLOBAL, и затем RTLD_GLOBAL | RTLD_LAZY. В-третьих, используйте RUNPATH (не RPATH) при создании программы. Используйте что-то вроде -Wl,-R,<path> -Wl,--enable-new-dtags.

jww 10.06.2019 22:35

Я проверил свои записи в Линукс | Примечание для общих вызывающих объектов. Похоже, что Debian и Ubuntu требуют dlopen флагов RTLD_GLOBAL | RTLD_LAZY.

jww 10.06.2019 22:48

@ πάντα - Этот вопрос не может быть дубликатом приведенных вопросов.

jww 10.06.2019 23:29
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
1 361
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

So why is this returning NULL, when the library file is in the same directory as the CPP file?

Расположение файла.cpp здесь не имеет значения.

Расположение исполняемого файла, соответственно, настройка LD_LIBRRY_PATH — это то, что используется для разрешения во время выполнения.

В любом случае, LD_LIBRRY_PATH не является рекомендуемым долгосрочным решением. Самый простой — использовать "./bar.so" вместо "bar.so", чтобы dlopen() сначала искал в текущем каталоге. Но текущий каталог может не совпадать с каталогом, в котором хранится исполняемый файл. В этом случае dlopen() все равно не удастся.

Другое решение — добавить -Wl,-rpath='$ORIGIN' к флагам компиляции при компиляции исполняемого файла (в данном случае foo.cpp) и передать "bar.so", как вы это уже делали. При использовании $ORIGIN в качестве rpath не имеет значения, какой текущий каталог. dlopen() всегда будет сначала искать в каталоге исполняемого файла. Но учтите, что это приведет к тому, что сначала будут искаться все библиотеки в текущем каталоге, а не только те, которые вы пытаетесь вызвать с помощью dlopen(). Это может быть или не быть тем, что вы хотите.

Таким образом, лучшее решение — получить путь к каталогу, в котором находится исполняемый файл, во время выполнения и использовать его как путь к bar.so. Это зависит от системы. В Linux см.: Получить путь к исполняемому файлу

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