Обогативные разные версии статической библиотеки в динамических библиотеках
-
25-09-2019 - |
Вопрос
В моем проекте есть зависимость от статической библиотеки (только что называется libsomething
Отныне) от 3-го вечеринки. Совсем недавно, libsomething
стал доступен в другой версии. Моя задача - обеспечить мое программное обеспечение поддержкой старой и новой версии. Только одна версия libsomething
Используется во время выполнения в любой момент времени, но какая версия должна быть настраиваемой между прогонами программы.
Я использую MSVC2005 на WinXP, вторичная цель состоит в том, чтобы стать готовым переключиться на Linux и GCC.
Так как обе версии libsomething
Используете те же символы, связывая их как в моем исполняемому исполнению, выходит из вопроса, поскольку символы обеих версий собираются столкнуться по всему круглосуточному времени.
Хотя я мог бы создать два исполняемых файла (одна ссылка против старой версии, другой, используя новую версию), я не могу реализовать решение, на котором исполняемовается, чтобы позвонить в окончательной среде развертывания (устаревшие причины).
Я пришел с идеей создания динамической обертки библиотеки для каждой версии libsomething
и связывая их во время выполнения в зависимости от некоторого файла конфигурации. С MSCV, это значит идти по дороге с использованием LoadLibrary()
, GetProcAddress()
, и т. Д., В то время как на Linux мне придется использовать dlopen()
а также dlsym()
.
Я понимаю, что используя libtool
(т.е. libtldl
) обещает эту платформу-зависимость для использования общих библиотек. Это соответствующий путь к следующему? Есть ли лучше (или, по крайней мере, разные) способы? Делать альтернативы libtldl
существуют как открытый источник?
Решение
Это было несколько лет, но я хотел бы упомянуть еще одно решение для полноты. Вместо руководства dlopen
а также dlsym
Вы можете генерировать простые заглушки для всех необходимых функций и на первом вызове (или при запуске программы) решить, какая версия библиотеки требуется, загрузите ее и разрешите адреса.
Вы можете написать сценарий, специально разработанный для вашего проекта или использования Implib.so.so инструмент:
# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so
Imbrib.so - это Linux - только банкомат, но должен легко адаптироваться к Windows.
Другие советы
Я знаю, что вы сказали, что не можете использовать два исполняемых файла из-за решения о том, что для выполнения, но вы не могли exec
Взад и вперед между исполняемыми файлами в зависимости от того, какая версия выбрана при конфигурации?
На Linux вам было бы легче ссылаться на общую библиотеку и использовать SymLinks для исправления версии - IMO намного проще, чем использование dlopen()
+ dlsym()
.
Таким образом, вы создадите общие библиотеки для старых и новых версий вашей библиотеки:
g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive
а также
g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive
Создайте SymLinks:
ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so
Создайте свое приложение, связывая его к старой версии библиотеки. Я полагаю, что обе версии являются двоичными совместимыми (ABI не сломаны), но новый может иметь новые символы.
g++ -o myapp myapp.cpp -L. -lshared
Поскольку общие библиотеки SONAME
является libshared.so.1
Ваше приложение будет зависеть от него и будет искать libshared.so.1
в путях от /etc/ld.so.conf
или LD_LIBRARY_PATH
Прежде чем запустить ваше приложение, вы можете установить libshared.so.1
SymLink указывает на libshared.so.1.2
или libshared.so.1.1
.
Маленькая информация о параметрах линкера, используемых здесь:
- Чолый архив
Для каждого архива, упомянутого в командной строке после опции «Удобрения», включите каждый объектный файл в архиве в ссылке, а не поиск архива для необходимых объектных файлов. Обычно это используется для превращения файла архива в общую библиотеку, принудительно принудительный объект в результате общую библиотеку. Эта опция может использоваться более одного раза.
Два примечания при использовании этой опции от GCC: Во-первых, GCC не знает об этой опции, поэтому вы должны использовать -WL, -WOHOL-Archive. Во-вторых, не забудьте использовать --wl, -no-все-архив после вашего списка архивов, потому что GCC добавит свой список архивов к вашей ссылке, и вы не хотите, чтобы этот флаг также повлиял на них.-soname = name.
При создании общего объекта ELF установите внутреннее поле DT_Soname к указанному имени. Когда исполняемый файл связан с общим объектом, который имеет поле DT_SONAME, то когда исполняемый файл запускается, динамический линкер попытается загрузить общий объект, указанный поле DT_SONAME, а не с помощью имени файла, данного ссылками.