Обертывание разных версий статической библиотеки в динамические библиотеки - PullRequest
4 голосов
/ 10 мая 2010

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

Я использую MSVC2005 на WinXP, вторичная цель - подготовиться к переходу на Linux и GCC.

Поскольку обе версии libsomething используют одни и те же символы, связать их обе в мой исполняемый файл не может быть и речи, так как символы обеих версий будут конфликтовать во время соединения.

Хотя я мог создать два исполняемых файла (один ссылается на старую версию, другой - на новую), я не могу реализовать решение, какой исполняемый файл вызывать в окончательной среде развертывания (устаревшие причины).

Мне пришла в голову идея создать динамическую библиотечную оболочку для каждой версии libsomething и связать их во время выполнения в зависимости от некоторого файла конфигурации. С MSCV это означало бы пойти по пути использования LoadLibrary(), GetProcAddress() и т. Д., В то время как в Linux мне пришлось бы использовать dlopen() и dlsym().

Я понимаю, что использование libtool (т.е. libtldl) оборачивает эту зависимость от платформы для использования разделяемых библиотек. Это подходящий путь для подражания? Есть ли лучшие (или, по крайней мере, разные) способы? Существуют ли альтернативы для libtldl с открытым исходным кодом?

Ответы [ 3 ]

2 голосов
/ 12 мая 2010

В Linux вам будет проще связываться с разделяемой библиотекой и использовать символические ссылки для исправления версии - 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

Создание символических ссылок:

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, указав libshared.so.1.2 или libshared.so.1.1.


Немного информации об опциях компоновщика, используемых здесь:

- весь-архив
Для каждого архива, упомянутого в командной строке после параметра --whole-archive, включите каждый объектный файл в архив в ссылка, а не поиск в архиве нужных объектных файлов. Это обычно используется, чтобы превратить архивный файл в общий библиотека, заставляя каждый объект быть включенным в результирующую общую библиотеку. Эта опция может быть использована более одного раза.
Два замечания при использовании этой опции от gcc: во-первых, gcc не знает об этой опции, поэтому вы должны использовать -Wl, -whole-archive. Во-вторых, не забудьте использовать -Wl, -no-whole-archive после вашего списка архивов, потому что gcc добавит свой собственный список архивов в ваш список. ссылку, и вы можете не захотеть, чтобы этот флаг также влиял на них.

-soname = имя
При создании общего объекта ELF установите для внутреннего поля DT_SONAME указанное имя. Когда исполняемый файл связан с общий объект с полем DT_SONAME, тогда при запуске исполняемого файла динамический компоновщик попытается загрузить общий объект определяется полем DT_SONAME, а не использованием имени файла, данного компоновщику.

2 голосов
/ 10 мая 2010

Я знаю, что вы сказали, что не можете использовать два исполняемых файла из-за решения о том, какой из них выполнять, но вы не могли exec переходить между исполняемыми файлами в зависимости от того, какая версия выбрана в конфигурации?

0 голосов
/ 07 декабря 2017

Прошло несколько лет, но я бы хотел упомянуть другое решение для полноты. Вместо ручных dlopen и dlsym вы можете создать простые заглушки для всех необходимых функций и при первом вызове (или при запуске программы) решить, какая версия библиотеки требуется, загрузить ее и разрешить адреса.

Вы можете написать скрипт, специально предназначенный для вашего проекта, или использовать Implib.so tool:

# 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

Implib.so является банкоматом только для Linux, но должен легко адаптироваться к Windows.

...