Теория: библиотеки, SONAME, ldconfig и pkgconfig
На этой странице
Разделяемые библиотеки и SONAME
Что такое .so-файл
Когда вы компилируете C-программу, она может использовать код из библиотеки.
Библиотека бывает статической (.a — код копируется внутрь программы при компиляции)
и разделяемой (.so — shared object — код загружается в память при запуске программы).
Разделяемая библиотека экономит место на диске и в памяти: один файл libyaml.so
используется всеми программами, которым нужен YAML.
Версионирование: три файла на одну библиотеку
После сборки libyaml вы увидите в /usr/lib64/ три файла:
/usr/lib64/libyaml-0.so.2.0.9 ← настоящий файл с кодом (реальная библиотека)
/usr/lib64/libyaml-0.so.2 ← символическая ссылка → libyaml-0.so.2.0.9
/usr/lib64/libyaml.so ← символическая ссылка → libyaml-0.so.2
Зачем три файла? У каждого своя роль:
| Файл | Назначение | Кто использует |
|---|---|---|
libyaml-0.so.2.0.9 | Реальный бинарный файл с кодом библиотеки | Система |
libyaml-0.so.2 | SONAME — стабильное имя для бинарной совместимости | Загрузчик (ld.so) при запуске программ |
libyaml.so | Ссылка для компилятора (линковки) | Компилятор при gcc -lyaml |
Что такое SONAME
SONAME (Shared Object Name) — это имя, «зашитое» внутрь самой библиотеки.
Когда вы компилируете программу с -lyaml, линковщик смотрит SONAME
библиотеки и записывает его в вашу программу. Потом при запуске загрузчик
ищет файл именно с этим именем.
Пример: SONAME у libyaml — libyaml-0.so.2. Это означает:
- Если вышла libyaml 0.2.6 с тем же ABI, файл станет
libyaml-0.so.2.0.10, но ссылкаlibyaml-0.so.2будет указывать на него — и все старые программы продолжат работать без перекомпиляции. - Если ABI сломается, SONAME станет
libyaml-0.so.3— старые программы продолжат использоватьlibyaml-0.so.2, а новые —libyaml-0.so.3.
Проверить SONAME можно командой:
readelf -d /usr/lib64/libyaml-0.so.2 | grep SONAME
Ожидаемый вывод:
0x000000000000000e (SONAME) Library soname: [libyaml-0.so.2]
Зачем разделять на основной пакет и -devel
Представьте: на компьютере пользователя стоит программа, которая использует libyaml.
Пользователю нужен только файл libyaml-0.so.2 (и реальный файл, на который
он ссылается). Заголовочные файлы (yaml.h), ссылка для компилятора (libyaml.so)
и pkgconfig — всё это нужно только разработчику, который пишет новую программу.
Поэтому пакет разделяется:
-
libyaml(основной) — то, что нужно для запуска программ:/usr/lib64/libyaml-0.so.2.0.9(реальный файл)/usr/lib64/libyaml-0.so.2(SONAME-ссылка)- Лицензия и документация
-
libyaml-devel— то, что нужно для разработки (компиляции новых программ):/usr/lib64/libyaml.so(ссылка для линковщика)/usr/include/yaml.h(заголовочный файл)/usr/lib64/pkgconfig/yaml-0.1.pc(для pkg-config)- Зависимость
Requires: libyaml(чтобы при установке -devel автоматически ставился основной пакет)
Полная карта файлов
Основной пакет (libyaml):
/usr/lib64/libyaml-0.so.2.0.9 ← реальный бинарный файл
/usr/lib64/libyaml-0.so.2 ← SONAME-ссылка (создаётся ldconfig)
/usr/share/doc/libyaml/README ← документация
/usr/share/licenses/libyaml/LICENSE ← лицензия
Подпакет -devel (libyaml-devel):
/usr/lib64/libyaml.so ← ссылка для компилятора
/usr/include/yaml.h ← заголовочный файл
/usr/lib64/pkgconfig/yaml-0.1.pc ← файл pkg-config
ldconfig
Что делает ldconfig
ldconfig — системная утилита, которая:
- Сканирует директории с библиотеками (
/usr/lib64/,/usr/lib/и др.) - Создаёт SONAME-ссылки (например,
libyaml-0.so.2 → libyaml-0.so.2.0.9) - Обновляет кэш
/etc/ld.so.cache, чтобы загрузчик быстро находил библиотеки
Что будет без ldconfig
Если не вызвать ldconfig после установки пакета, программы получат ошибку:
error while loading shared libraries: libyaml-0.so.2: cannot open shared object file: No such file or directory
Это одна из самых частых ошибок новичков. Программа установлена, библиотека лежит на диске, но загрузчик не знает о ней, потому что кэш не обновлён.
Как прописать ldconfig в SPEC
В SPEC-файле используются скриптлеты %post и %postun:
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
Это означает: «после установки пакета запусти /sbin/ldconfig» и
«после удаления пакета запусти /sbin/ldconfig». Флаг -p говорит,
что /sbin/ldconfig — это сама программа, а не shell-скрипт.
pkgconfig
Что такое .pc-файл
Файл yaml-0.1.pc — это текстовый файл, который описывает, где лежат
заголовки и библиотеки, какие флаги нужны компилятору. Пример содержимого:
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib64
includedir=${prefix}/include
Name: yaml-0.1
Description: YAML parser and emitter library
Version: 0.2.5
Libs: -L${libdir} -lyaml
Cflags: -I${includedir}
Как разработчики используют pkgconfig
Вместо того чтобы вручную писать пути, разработчик пишет:
# Узнать флаги для компилятора:
pkg-config --cflags yaml-0.1
# Вывод: -I/usr/include
# Узнать флаги для линковщика:
pkg-config --libs yaml-0.1
# Вывод: -L/usr/lib64 -lyaml
# Компиляция программы одной командой:
gcc myprogram.c $(pkg-config --cflags --libs yaml-0.1) -o myprogram
Именно поэтому .pc-файл должен быть в -devel — он нужен только при разработке.
.la-файлы (libtool archives)
При сборке через Autotools (configure/make) часто создаются файлы .la —
это libtool archives. Они были нужны в старые времена для отслеживания
зависимостей между статическими библиотеками. В современных дистрибутивах
они бесполезны и вредны:
- Содержат захардкоженные пути, которые ломаются при мультилиб-системах
- Вызывают предупреждения rpmlint
- Могут конфликтовать с pkgconfig
Правило: всегда удаляйте .la-файлы в секции %install:
find %{buildroot} -name '*.la' -delete