8.4 Управление разделяемыми библиотеками (Managing Shared Libraries)¶
Помимо проверки зависимостей программных пакетов, вам также может потребоваться убедиться, что система правильно настроена для доступа к библиотекам, необходимым приложению. В этой части главы вы научитесь это делать. Рассматриваются следующие темы:
- Как работают разделяемые библиотеки
- Управление зависимостями разделяемых библиотек
Начнём с обсуждения принципов работы разделяемых библиотек.
Как работают разделяемые библиотеки (How Shared Libraries Work)¶
В Linux приложения, выполняющиеся в системе, могут совместно использовать элементы кода, называемые разделяемыми библиотеками (shared libraries). Это очень удобно: разделяемые библиотеки позволяют разработчикам не изобретать велосипед каждый раз, когда они пишут новую программу.
Если задуматься, многие функции применяются в самых разных программах. Например, операции открытия файла, сохранения файла и закрытия открытого файла одинаковы вне зависимости от используемого приложения. Без разделяемых библиотек программисты были бы вынуждены включать код для выполнения этих базовых задач в каждое написанное ими приложение — пустая трата времени и ресурсов!
Благодаря разделяемым библиотекам разработчики могут сосредоточиться на тех элементах кода, которые уникальны для конкретного приложения. Для общих элементов, используемых сразу в нескольких приложениях, достаточно просто сослаться на уже готовый код в разделяемой библиотеке и не беспокоиться о его повторном написании.
Совет
Разделяемые библиотеки в Linux работают во многом так же, как динамически подключаемые библиотеки (dynamic link libraries, DLL) в Windows.
Использование разделяемых библиотек даёт множество преимуществ. Очевидно, что это существенно ускоряет разработку. Кроме того, создаваемые программы становятся меньше и компактнее.
В Linux существует два типа разделяемых библиотек:
-
Динамические (Dynamic). Файлы динамических разделяемых библиотек хранятся в файловой системе Linux. Программисты просто вставляют в свой программный код ссылки на функции из этих разделяемых библиотек. Когда программа запускается, функции вызываются из динамических разделяемых библиотек, а не встраиваются в саму программу. В системе имеется конфигурационный файл со списком установленных динамических разделяемых библиотек и их расположения в файловой системе. Использование динамических разделяемых библиотек уменьшает общий размер исполняемого файла после компиляции. Однако они порождают проблему зависимостей: если программа вызывает функцию из динамической разделяемой библиотеки, которая не установлена в системе (или по какой-либо причине стала недоступна), приложение откажет в работе.
-
Статические (Static). В отличие от динамических, статические разделяемые библиотеки подключаются к программе статически при компиляции. По сути, при использовании статических библиотек фактический код вызываемых функций встраивается непосредственно в само приложение. Это, очевидно, увеличивает размер приложения. Зато приложение становится независимым от наличия разделяемых библиотек в системе, где оно выполняется, — в отличие от приложений, использующих динамические библиотеки.
Какой тип предпочтительнее? Это зависит от приложения. Большинство приложений, используемых в повседневной работе, применяют динамические разделяемые библиотеки. Это позволяет предоставить широкую функциональность при относительно небольшом объёме занимаемого места на диске. Тем не менее многие приложения используют статические библиотеки — в особенности те, которые предназначены для восстановления неисправно работающей системы. Вместо ссылок на динамические разделяемые библиотеки (которые в сценарии аварийного восстановления системы могут оказаться недоступны) такие приложения полностью самодостаточны и способны работать в минимальном окружении Linux.
Примечание
Хорошим примером приложения, использующего статические разделяемые библиотеки, служит автономная оболочка Stand-Alone Shell (sash). Она предназначена для восстановления неработающей системы Linux и включает множество встроенных функций. Благодаря этому, если раздел, где хранятся разделяемые библиотеки, недоступен, программа всё равно запустится и позволит выполнить необходимые действия по восстановлению системы.
Файлы разделяемых библиотек используют особый формат имени, позволяющий определить тип библиотеки. Этот синтаксис выглядит следующим образом:
Обратите внимание, что имена всех разделяемых библиотек начинаются с lib, за которым следует имя разделяемой библиотеки. Часть имени type идентифицирует тип разделяемой библиотеки: символы so указывают, что файл является динамической разделяемой библиотекой, а символ a — что файл является статической библиотекой. Часть имени version задаёт номер версии библиотеки. Например, libfreetype.so.6.4.0 — это динамическая разделяемая библиотека.
Разобравшись с этим, перейдём к управлению зависимостями разделяемых библиотек.
Управление зависимостями разделяемых библиотек (Managing Shared Library Dependencies)¶
Как было отмечено ранее, Linux использует конфигурационный файл, сообщающий приложениям, где в системе можно найти файлы динамических разделяемых библиотек. Такой подход обеспечивает разработчикам приложений определённую независимость: им не нужно беспокоиться о том, где будут располагаться разделяемые библиотеки при запуске их программ. Конфигурационный файл сам сообщает программе, где они находятся, в каком бы месте конкретной системы Linux они ни хранились.
Конфигурационный файл динамических разделяемых библиотек — /etc/ld.so.conf. Пример его содержимого:
openSUSE:/etc # cat ld.so.conf
/usr/X11R6/lib64/Xaw3d
/usr/X11R6/lib64
/usr/lib64/Xaw3d
/usr/X11R6/lib/Xaw3d
/usr/X11R6/lib
/usr/lib/Xaw3d
/usr/x86_64-suse-linux/lib
/usr/local/lib
/opt/kde3/lib
/lib64
/lib
/usr/lib64
/usr/lib
/usr/local/lib64
/opt/kde3/lib64
include /etc/ld.so.conf.d/*.conf
Как видно из примера, файл содержит просто список путей в файловой системе, где хранятся файлы разделяемых библиотек. Приложения, ссылающиеся на функции из этих файлов, могут просматривать данные пути для поиска нужных библиотек.
Совет
Каталоги /lib/ и /usr/lib/ всегда считаются содержащими разделяемые библиотеки, поэтому они не указываются в файле /etc/ld.so.conf.
Чтобы просмотреть список всех разделяемых библиотек, доступных в системе Linux, введите ldconfig -p в командной строке. Пример вывода:
openSUSE:~ # ldconfig -p
1423 libs found in cache '/etc/ld.so.cache'
libzypp.so.706 (libc6,x86-64) => /usr/lib64/libzypp.so.706
libzio.so.0 (libc6,x86-64) => /usr/lib64/libzio.so.0
libz.so.1 (libc6,x86-64) => /lib64/libz.so.1
libz.so.1 (libc6) => /lib/libz.so.1
libz.so (libc6,x86-64) => /usr/lib64/libz.so
liby2util.so.4 (libc6,x86-64) => /usr/lib64/liby2util.so.4
liby2.so.2 (libc6,x86-64) => /usr/lib64/liby2.so.2
libyui.so.3 (libc6,x86-64) => /usr/lib64/libyui.so.3
libycpvalues.so.3 (libc6,x86-64) => /usr/lib64/libycpvalues.so.3
...
Примечание
Если вы не вошли в систему как root, необходимо указывать полный путь к ldconfig в команде (/sbin/ldconfig).
Вы также можете просмотреть разделяемые библиотеки, необходимые конкретному приложению, с помощью команды ldd. Синтаксис: ldd -v имя_исполняемого_файла. Например, чтобы узнать, какие разделяемые библиотеки требуются команде ip (используемой для управления сетевыми соединениями), введите ldd -v /sbin/ip в командной строке.
Примечание
При использовании команды ldd необходимо указывать полный путь к исполняемому файлу вместе с его именем.
Пример вывода:
openSUSE:~ # ldd -v /sbin/ip
linux-vdso.so.1 => (0x00007fffe4ab2000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f7c07e7d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f7c07b1d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7c08081000)
Version information:
/sbin/ip:
libdl.so.2 (GLIBC_2.2.5) => /lib64/libdl.so.2
libc.so.6 (GLIBC_2.7) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
/lib64/libdl.so.2:
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
libc.so.6 (GLIBC_PRIVATE) => /lib64/libc.so.6
libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
/lib64/libc.so.6:
ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2
ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
Одно из ключевых применений команды ldd — проверка зависимостей разделяемых библиотек. Она позволяет определить, установлены ли все библиотеки, необходимые данному приложению. Если все библиотеки присутствуют, сообщений об ошибках не будет, как в приведённом выше примере. Если какой-либо файл библиотеки отсутствует, будет выведено сообщение об ошибке. После этого вы можете найти и установить отсутствующую библиотеку, и всё заработает.
Итак, как приложение узнаёт, в каких каталогах искать разделяемую библиотеку? Приложения не обращаются непосредственно к файлу /etc/ld.so.conf. Вместо этого они проверяют кеш библиотек и переменную окружения LD_LIBRARY_PATH. Кеш библиотек — это файл /etc/ld.so.cache. Он содержит список всех системных библиотек и обновляется при первоначальной загрузке системы.
Это принципиально важно. Если вы добавите новый каталог с динамическими библиотеками в файл /etc/ld.so.conf, вас ждёт разочарование при попытке запустить приложения, ссылающиеся на библиотеки из этого каталога. Дело в том, что кеш библиотек ещё не обновлён с учётом новых данных. Чтобы исправить это, есть два варианта:
- Использовать
ldconfig. Командаldconfigслужит для ручного перестроения кеша библиотек. - Задать
LD_LIBRARY_PATH. Можно также добавить путь в переменную окруженияLD_LIBRARY_PATH. Как правило, следует добавить новый путь в конец списка каталогов, которые уже могут содержаться в переменной, поэтому используйте следующие команды:
Как правило, первый вариант предпочтительнее. Он гарантирует, что разделяемые библиотеки всегда будут доступны приложениям, которые в них нуждаются, даже после перезагрузки системы. Значение LD_LIBRARY_PATH обычно задаётся лишь в ситуациях, когда в разных каталогах установлены две версии одной и той же разделяемой библиотеки и нужно использовать одну из них в приоритете над другой.
Упражнение 8-6. Работа с разделяемыми библиотеками
В этом упражнении вы потренируетесь управлять разделяемыми библиотеками. Его можно выполнить на виртуальной машине, прилагаемой к данной книге. Для корректно настроенного окружения запустите снимок 8-3.
VIDEO Посмотрите видеозапись упражнения 8-6, в которой показано, как выполнить это задание.
Выполните следующие шаги:
- Запустив систему, откройте сеанс терминала.
- При необходимости переключитесь на учётную запись суперпользователя
root, введяsu -, а затем пароль пользователяroot. - Просмотрите разделяемые библиотеки, используемые исполняемым файлом
ping, введяldd -v /bin/pingв командной строке. Вы должны увидеть, чтоpingтребует разделяемую библиотекуlibc.so.6. - Найдите расположение файла библиотеки
lib64/libc.so.6в системе, введяfind / -name libc.so.6в командной строке. На 32-разрядной системе файл находится в каталоге/lib, на 64-разрядной — скорее всего в/lib64. - Просмотрите кеш библиотек системы, введя
ldconfig -pв командной строке. - Перестройте кеш библиотек, введя
ldconfig -vв командной строке.
На этом данная глава завершается! Теперь такие понятия, как apt, tarball и rpm, не должны вас пугать — вы знаете, как эффективно управлять программным обеспечением в системе Linux!