Я добавляю два класса и библиотеки в систему, parent.so
а также child.so
исходя из этого.
Проблема в том, когда программа загружается child.so
он не может найти определение родительской виртуальной функции из parent.so
,
Что просходит,
nm -D child.so
даст что-то вроде (я только что изменил имена)
U _ZN12PARENT15virtualFunctionEv
Программа аварийно завершится
_handle = dlopen(filename, RTLD_NOW|RTLD_GLOBAL); //filename is child.so
это даст ошибку с LD_DEBUG = libs
symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv (fatal)
То, что я не могу объяснить, я пытался LD_DEBUG = symbols
используя GDB, при запуске dlopen
, журнал показывает, что он пытался искать в основном во всех библиотеках в системе, кроме parent.so
где символ определяется. Но из журнала libs parent.so
уже загружен, и код запущен, и он находится по тому же пути, что и все остальные библиотеки.
......
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/tls/libm.so.6
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/tls/libc.so.6
27510: symbol=_ZN12PARENT15virtualFunctionEv; lookup in file=/lib/ld-linux.so.2
27510: child.so: error: symbol lookup error: undefined symbol: _ZN12PARENT15virtualFunctionEv(fatal)
Как программа или система управляют библиотекой для поиска определения символа?
Я новичок в Linux, кто-нибудь может указать мне несколько направлений для работы?
Благодарю.
РЕДАКТИРОВАТЬ
Команда, используемая для генерации parent.so
файл
c++ -shared -o parent.so parent.o
Аналогично для child.so
, Отсутствует ли какая-либо информация для ссылки здесь? Похоже, ребенок только включает заголовочный файл родителя.
EDIT2
После очередного теста звоню
_handle = dlopen("parent.so", RTLD_NOW|RTLD_GLOBAL);
до сбоя линии решит проблему, которая, я думаю, означает изначально parent.so
не был загружен. Но я все еще не очень ясно о причине.
Вы должны сообщить компоновщику, что ваша библиотека libchild.so
использует функциональность в libparent.so
, Вы делаете это при создании дочерней библиотеки:
g++ -shared -o libchild.so child_file1.o child_file2.o -Lparent_directory -lparent
Обратите внимание, что порядок важен. Укажите -lparent
после всех ваших объектных файлов. Вам также может понадобиться передать дополнительные параметры компоновщику через -Wl
вариант g ++.
Это все еще может быть недостаточно хорошо. Возможно, вам придется добавить библиотеку, которая содержит libparent.so
к LD_LIBRARY_PATH
переменная окружения.
Несколько ошибок: если вы не называете эти библиотеки lib
Приставку вы будете путать с компоновщиком большое время. Если вы не компилируете свои исходные файлы с -fPIC
или же -fpic
у вас не будет перемещаемых объектов.
добавление
Существует большая потенциальная проблема с библиотеками, которые зависят от других библиотек. Предположим, вы используете версию 1.5 родительского пакета при компиляции исходных файлов вашей дочерней библиотеки. Вам удается преодолеть все проблемы библиотечных зависимостей. Вы указали, что ваш libchild.so
зависит от libparent.so
, Ваш материал просто работает. Так продолжалось до версии 2.0 родительского пакета. Теперь ваши вещи ломаются везде, где они используются, и вы не изменили ни одной строки кода.
Способ преодоления этой проблемы заключается в том, чтобы указать во время сборки своей дочерней библиотеки, что результирующая разделяемая библиотека зависит конкретно от версии 1.5 libparent.so`.
Для этого вам нужно будет передать опции из g ++ / gcc компоновщику через -Wl
вариант. использование -Wl,<linker_option>,<linker_option>,...
Если для этих опций компоновщика нужны пробелы, вам нужно использовать обратную косую черту в команде g ++. Пара ключевых вариантов -rpath
а также -soname
, Например, -rpath=/path/to/lib,-soname=libparent.so.1.5
,
Обратите внимание, очень хорошо: вам нужно использовать -soname=libparent.so.1.5
вариант, когда вы создаете libparent.so. Это то, что позволяет системе обозначить, что ваш libchild.so (версия 1.0) зависит от libparent.so (версия 1.5). И вы не создаете libparent.so. Вы создаете libparent.so.1.5. Что насчет libparent.so? Это должно существовать, но это должна быть символическая ссылка на какую-нибудь пронумерованную версию (предпочтительно самую последнюю версию) libparent.so.
Теперь предположим, что обратно-совместимая родительская версия 2.0 скомпилирована и встроена в новый блестящий libparent.so.2.0, а libparent.so символически связан с этой новой блестящей версией. Приложение, которое использует ваш старый неуклюжий libchild.so (версия 1.0), с радостью будет использовать неуклюжую старую версию libparent.so вместо блестящей новой, которая ломает все.
Похоже, вы не говорите компоновщику, что child.so нужен parent.so, используйте что-то вроде следующего:
g++ -shared -o libparent.so parent.o
g++ -shared -o libchild.so -lparent child.o
Когда вы собираете основную программу, вы должны сообщить компилятору, что он связывается с этими библиотеками; таким образом, при запуске linux загрузит их для него.
Измените их имена на libparent.so и libchild.so.
Затем скомпилируйте что-то вроде этого:
g++ <your files and flags> -L<folder where the .so's are> -lparent -lchild
РЕДАКТИРОВАТЬ:
Возможно, было бы меньшим изменением попытаться загрузить parent.so перед child.so. Вы уже пробовали это?