Использование библиотеки so linux
Как уже неоднократно упоминалось в предыдущей главе, библиотека — это набор скомпонованных особым образом объектных файлов. Библиотеки подключаются к основной программе во время линковки. По способу компоновки библиотеки подразделяют на архивы (статические библиотеки, static libraries) и совместно используемые (динамические библиотеки, shared libraries). В Linux, кроме того, есть механизмы динамической подгрузки библиотек. Суть динамической подгрузки состоит в том, что запущенная программа может по собственному усмотрению подключить к себе какую-либо библиотеку. Благодаря этой возможности создаются программы с подключаемыми плагинами, такие как XMMS. В этой главе мы не будем рассматривать динамическую подгрузку, а остановимся на классическом использовании статических и динамических библиотек.
С точки зрения модели КИС, библиотека — это сервер. Библиотеки несут в себе одну важную мысль: возможность использовать одни и те же механизмы в разных программах. В Linux библиотеки используются повсеместно, поскольку это очень удобный способ «не изобретать велосипеды». Даже ядро Linux в каком-то смысле представляет собой библиотеку механизмов, называемых системными вызовами.
Статическая библиотека — это просто архив объектных файлов, который подключается к программе во время линковки. Эффект такой же, как если бы вы подключали каждый из файлов отдельно.
В отличие от статических библиотек, код совместно используемых (динамических) библиотек не включается в бинарник. Вместо этого в бинарник включается только ссылка на библиотеку.
Рассмотрим преимущества и недостатки статических и совместно используемых библиотек. Статические библиотеки делают программу более автономной: программа, скомпонованная со статической библиотекой может запускаться на любом компьютере, не требуя наличия этой библиотеки (она уже «внутри» бинарника). Программа, скомпонованная с динамической библиотекой, требует наличия этой библиотеки на том компьютере, где она запускается, поскольку в бинарнике не код, а ссылка на код библиотеки. Не смотря на такую зависимость, динамические библиотеки обладают двумя существенными преимуществами. Во-первых, бинарник, скомпонованный с совместно используемой библиотекой меньше размером, чем такой же бинарник, с подключенной к нему статической библиотекой (статически скомпонованный бинарник). Во-вторых, любая модернизация динамической библиотеки, отражается на всех программах, использующих ее. Таким образом, если некоторую библиотеку foo используют 10 программ, то исправление какой-нибудь ошибки в foo или любое другое улучшение библиотеки автоматически улучшает все программы, которые используют эту библиотеку. Именно поэтому динамические библиотеки называют совместно используемыми. Чтобы применить изменения, внесенные в статическую библиотеку, нужно пересобрать все 10 программ.
В Linux статические библиотеки обычно имеют расширение .a (Archive), а совместно используемые библиотеки имеют расширение .so (Shared Object). Хранятся библиотеки, как правило, в каталогах /lib и /usr/lib. В случае иного расположения (относится только к совместно используемым библиотекам), приходится немного «подшаманить», чтобы программа запустилась.
3.2. Пример статической библиотеки
Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями: h_world() и g_world(), которые выводят на экран «Hello World» и «Goodbye World» соответственно. Начнем со статической библиотеки.
Начнем с интерфейса. Создадим файл world.h: Здесь просто объявлены функции, которые будут использоваться.
Теперь надо реализовать серверы. Создадим файл h_world.c: Теперь создадим файл g_world.c, содержащий реализацию функции g_world(): Можно было бы с таким же успехом уместить обе функции в одном файле (hello.c, например), однако для наглядности мы разнесли код на два файла.
Теперь создадим файл main.c. Это клиент, который будет пользоваться услугами сервера:
Теперь напишем сценарий для make. Для этого создаем Makefile: Не забывайте ставить табуляции перед каждым правилом в целевых связках.
Осталось только проверить, работает ли программа и разобраться, что же мы такое сделали:
Итак, в приведенном примере появились три новые вещи: опции -l и -L компилятора, а также команда ar. Начнем с последней. Как вы уже догадались, команда ar создает статическую библиотеку (архив). В нашем случае два объектных файла объединяются в один файл libworld.a. В Linux практически все библиотеки имеют префикс lib.
Как уже говорилось, компилятор gcc сам вызывает линковщик, когда это нужно. Опция -l, переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарнику библиотеку. Как вы уже заметили, у имени библиотеки «обрублены» префикс и суффикс. Это делается для того, чтобы создать «видимое безразличие» между статическими и динамическими библиотеками. Но об этом речь пойдет в других главах книги. Сейчас важно знать лишь то, что и библиотека libfoo.so и библиотека libfoo.a подключаются к проекту опцией -lfoo. В нашем случае libworld.a «урезалось» до -lworld.
Опция -L указывает линковщику, где ему искать библиотеку. В случае, если библиотека располагается в каталоге /lib или /usr/lib, то вопрос отпадает сам собой и опция -L не требуется. В нашем случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает текущий каталог) необходима.
3.3. Пример совместно используемой библиотеки
Для того, чтобы создать и использовать динамическую (совместно используемую) библиотеку, достаточно переделать в нашем проекте Makefile.
Внешне ничего не изменилось: программа компилируется, запускается и выполняет те же самые действия, что и в предыдущем случае. Изменилась внутренняя суть, которая играет для программиста первоочередную роль. Рассмотрим все по порядку.
Правило для сборки binary теперь содержит пугающую опцию -Wl,-rpath,. Ничего страшного тут нет. Как уже неоднократно говорилось, компилятор gcc сам вызывает линковщик ld, когда это надо и передает ему нужные параметры сборки, избавляя нас от ненужной платформенно-зависимой волокиты. Но иногда мы все-таки должны вмешаться в этот процесс и передать линковщику «свою» опцию. Для этого используется опция компилятора -Wl,option,optargs. Расшифровываю: передать линковщику (-Wl) опцию option с аргументами optargs. В нашем случае мы передаем линковщику опцию -rpath с аргументом . (точка, текущий каталог). Возникает вопрос: что означает опция -rpath? Как уже говорилось, линковщик ищет библиотеки в определенных местах; обычно это каталоги /lib и /usr/lib, иногда /usr/local/lib. Опция -rpath просто добавляет к этому списку еще один каталог. В нашем случае это текущий каталог. Без указания опции -rpath, линковщик «молча» соберет программу, но при запуске нас будет ждать сюрприз: программа не запустится из-за отсутствия библиотеки. Попробуйте убрать опцию -Wl,-rpath,. из Makefile и пересоберите проект. При попытке запуска программа binary завершится с кодом возврата 127 (о кодах возврата будет рассказано в последующих главах). То же самое произойдет, если вызвать программу из другого каталога. Верните обратно -Wl,-rpath. пересоберите проект, поднимитесь на уровень выше командой cd .. и попробуйте запустить бинарник командой world/binary. Ничего не получится, поскольку в новом текущем каталоге библиотеки нет.
Есть один способ не передавать линковщику дополнительных опций при помощи -Wl — это использование переменной окружения LD_LIBRARY_PATH. В последующих главах мы будем подробно касаться темы окружения (environment). Сейчас лишь скажу, что у каждого пользователя есть так называемое окружение (environment) представляющее собой набор пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, используемых программами. Чтобы посмотреть окружение, достаточно набрать команду env. Чтобы добавить в окружение переменную, достаточно набрать export ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, а чтобы удалить переменную из окружения, надо набрать export -n ПЕРЕМЕННАЯ. Будьте внимательны: export — это внутреннаяя команда оболочки BASH; в других оболочках (csh, ksh, . ) используются другие команды для работы с окружением. Переменная окружения LD_LIBRARY_PATH содержит список дополнительных «мест», разделенных двоеточиеями, где линковщих должен искать библиотеку.
Не смотря на наличие двух механизмов передачи информации о нестандартном расположении библиотек, лучше помещать библиотеки в конечных проектах в /lib и в /usr/lib. Допускается расположение библиотек в подкаталоги /usr/lib и в /usr/local/lib (с указанем -Wl,-rpath). Но заставлять конечного пользователя устанавливать LD_LIBRARY_PATH почти всегда является плохим стилем программирования.
Следующая немаловажная деталь — это процесс создания самой библиотеки. Статические библиотеки создаются при помощи архиватора ar, а совместно используемые — при помощи gcc с опцией -shared. В данном случае gcc опять же вызывает линковщик, но не для сборки бинарника, а для создания динамической библиотеки.
Источник
Библиотеки с расширениями so, la, a — какую использовать?
И еще вопрос как использовать объектные файлы, сделанные другим компилятором?
Вопрос: что подразумевается под «использовать»?
Статически a
Динамически so
Использовать систему сборки.
.a от слова Archive, это архив с .o файлами .so от слова Shared Objects, объекты общего пользования
Я почему спросил. Потому что мог заблуждаться. Допустим
т.е. никакой роли для ликовки so-библиотек файл a не играет?
Библиотеки с расширениями so, la, a — какую использовать?
Иди в винду и «используй» dll
И еще вопрос как использовать объектные файлы, сделанные другим компилятором?
учитывая C++ в тегах, есть вероятность, что никак. но бывают исключения.
Ты видимо слишком любишь m$ 🙂
В винде, lib файлы используются при линковке dll, что бы линкер мог построить таблицу импорта, и содержат в принципе заглушки функций из dll, которые ссылаются на реальные функции из dll. Как разрешаются там ссылки на данные, я если честно не в курсе.
В so файлах вся необходимая для линковщика инфа уже есть.
Как заметил анонимус, a файлы это архивы обьектников, называть их библиотеками, конечно можно, но по сути это просто удобный способ переносить кучу обьектников в одном файле, и тут процесс линковки ничем особо не отличается от линковки самих обьектов, архив распаковывается, обьектники линкуются к целевому бинарнику.
Всегда, когда требовалось линковаться с SO, если не было la или a, то приходилось явно указывать файл, например LIBS+= -l /usr/lib/x86_64-linux-gnu/libXext.so.6
4.2 даже в условиях qmake. Линкер ищет либу при использовании флага -l по шаблону lib .
Линкер ищет либу при использовании флага -l по шаблону lib .
Ясно. Как много я не знаю про эту Вселенную. А ведь это просто GCC, даже не qmake-специфичная вещь. Хотя не раз наблюдал что некоторые so файлы требовали указания не только so он и их версии после so.1.2.3 Видимо что-то не так было настроено или указано, хз.
Соль как раз в том, что линкер не ищет чего то после суффиксов a|so. А всё это именование с версией в имени файла, костыль вместо майкрософтовских манифестов, которые позволяют в либу ряд стандартных, и много (х3 какой лимит) кастомных пар ключ/значение записать для хранения метаинформации. В юникс подобных, почему то такой подход не возник, и все кому надо, делают сиё вручную, через функции аля get_lib_version.
Никогда не видел, чтобы кто-то линковал так so’шки. Вот так нужно:
LIBS += -L/usr/lib/x86_64-linux-gnu/ -lXext
А вот a’шки можно и тупо:
и содержат в принципе заглушки функций из dll, которые ссылаются на реальные функции из dll
Я такое и с a’шками видел. Вместо нормальных объектников там были заглушки, а рядом so’шка. С какой целью не в курсе.
Самое убогое, что там ещё и порядок линковки надо соблюдать.
Интересно, мне не попадалось. А где?
Библиотеки с расширениями .so , .la , .a — какую использовать?
А как поступать в ситуации, когда в системе gcc 4.4, а для сборки либы нужно 4.8, я думал, что могу собрать либу на другой системе и использовать у себя?
В каких-то проприетарных SDK к каким-то карманным девайсам. Уже не вспомню, давно сталкивался.
Ну и как пример тебе такого решения, это библиотеки MinGW:
Ну библиотеки mingw подчиняются тем же законам, что и все остальные виндовые библиотеки, по определению. По крайней мере, пока они свой загрузчик для винды не сделают.
Вроде как эти lib и dll.a/a отличаются. Хотя я в ту степь особо не копал.
Скорее всего не получится так.
Если ABI не поломан и зависимостей от конкретной libc нет, может и взлететь. Но не факт.
Если ABI не поломан и зависимостей от конкретной libc нет, может и взлететь. Но не факт.
когда ты собираешь крестокод новым G++ — он прибивается гвоздями к новым кишкам libstdc++, которые не будут найдены при линковке более старым тулчейном.
совместимость ABI не спасет.
конкретно для glibc есть костыли, чтобы это порешать, для C++ решения не знаю.
edit: а кишки нового libstdc++, в свою очередь, скорее всего будут требовать более нового glibc, кстати.
Если ABI не поломан и зависимостей от конкретной libc нет, может и взлететь. Но не факт.
Есть еще хаки, чтоб собирать новыми версиями и не требовать новых символов:
конкретно для glibc есть костыли, чтобы это порешать, для C++ решения не знаю.
Да точно такие же костыли есть, я собираю новым gcc, а релиз требует libstdc++ >= 4.8. Понятно, что новое из C++17, например, так не прикрутить, но для С++11/14 вполне хватает.
so — это разделяемая библиотека. Существуюет в единственном экземпляре, и может использоваться сразу многими приложениями
a — это статическая библиотека, по сути это просто архив с набором объектных файлов которые прилинковываются к каждому приложению которое использует библиотеку.
.a желательно избегать, поскольку они раздувают бинарники, их неудобно линковать (все зависимости библиотеки с которой ты линкуешься нужно указывать явно, в случае .so же они обработаются автоматически; также нужно следить за порядком линковки) и они препятствуют обновлениию third party кода (т.е. если .so можно обновить на новую версию где была исправлена уязвимость, с .a придётся только пересобирать всех потребителей). Плюсов у них только чуть меньший оверхед на вызовы.
.la это вообще не библиотека, а костыль от костыля libtool, который решает описанную проблему с зависимостями. Т.е. если линковаться через libtool она может сама вытащить зависимости из .la файлов. От libtool лучше тоже держаться подальше, ибо это устаревший набор костылей.
Источник