Внутреннее устройство Linux
Шрифт:
Библиотеки вступают в игру главным образом во время компоновки, когда программа-компоновщик создает исполняемый файл из объектных файлов. Например, если у вас есть программа, которая использует библиотеку gobject, но вы забыли указать компилятору о связывании с этой библиотекой, то появятся ошибки компоновщика, подобные этой:
badobject.o(.text+0x28): undefined reference to 'g_object_new'
Наиболее важные части этого сообщения выделены жирным шрифтом. Когда компоновщик проверял объектный файл badobject.o, ему не удалось найти функцию, которая выделена жирным шрифтом, и, как следствие, не удалось создать исполняемый файл. В данном частном случае можно
примечание
Неопределенные ссылки не всегда означают, что вы упустили библиотеку. Один из объектных файлов команды может отсутствовать в команде компоновки. Но обычно достаточно легко понять, что отсутствует — библиотечные функции или объектные файлы.
Чтобы исправить эту ошибку, сначала вы должны отыскать библиотеку gobject, а затем использовать параметр компилятора -l, чтобы установить связь с библиотекой. Так же как и включаемые файлы, библиотеки разбросаны по всей системе (по умолчанию используется каталог /usr/lib), хотя большинство из них расположено в подкаталоге lib. В предыдущем примере основным файлом библиотеки gobject является libgobject.a, поэтому имя библиотеки — gobject. Объединяя все это, можно выполнить компоновку команды следующим образом:
$ cc -o badobject badobject.o -lgobject
Вы должны сообщать компоновщику о нестандартном расположении библиотеки; для этого применяется параметр -L. Допустим, что команде badobject необходим файл libcrud.a в каталоге /usr/junk/lib. Чтобы выполнить компиляцию и создать исполняемый файл, используйте команду, подобную этой:
$ cc -o badobject badobject.o -lgobject -L/usr/junk/lib -lcrud
примечание
Если вам необходимо отыскать в библиотеке некоторую функцию, применяйте команду nm. Будьте готовы к обширному отчету. Попробуйте, например, такую команду: nm libgobject.a. Вам может понадобиться команда locate, чтобы отыскать файл libgobject.a; многие версии системы теперь помещают библиотеки в подкаталоги, зависящие от архитектуры, внутри каталога /usr/lib.
15.1.4. Совместно используемые библиотеки
Библиотека, имя файла которой оканчивается на .a (например, libgobject.a), называется статической библиотекой. Когда вы связываете команду со статической библиотекой, компоновщик копирует машинный код из библиотеки в исполняемый файл. Следовательно, для работы окончательного исполняемого файла не требуется наличие исходного файла библиотеки и, более того, поведение исполняемого файла никогда не меняется.
Однако размеры библиотек постоянно возрастают, равно как и количество используемых библиотек; это делает статические библиотеки неэкономными с точки зрения использования дискового пространства и памяти. Кроме того, если впоследствии обнаружится, что статическая библиотека реализована неадекватно или является незащищенной, то нет никакого способа исправить связанный с ней исполняемый файл, кроме повторной компиляции.
Совместно используемые библиотеки избавляют от таких проблем. Когда вы запускаете команду, связанную с такой библиотекой, система загружает код библиотеки в область памяти процесса только тогда, когда это требуется. Несколько процессов могут совместно использовать один и тот же код библиотеки в памяти. Если вам потребуется немного изменить код библиотеки, то обычно это можно выполнить, не компилируя заново другие команды.
У совместно используемых библиотек есть свои
• Как получить список совместно используемых библиотек, необходимых исполняемому файлу.
• Как исполняемый файл отыскивает совместно используемые библиотеки.
• Как связать команду с совместно используемой библиотекой.
• Подводные камни при использовании таких библиотек.
В следующих разделах рассказано о том, как применять и обслуживать совместно используемые библиотеки в вашей системе. Если вам интересно, как устроены эти библиотеки, или вы желаете узнать о компоновщиках в целом, обратитесь к книге Джона Р. Ливайна (John R. Levine) Linkers and Loaders («Компоновщики и загрузчики», Morgan Kaufmann, 1999) или к статье Дэвида М. Бизли (David M. Beazley), Брайана Д. Уарда (Brian D. Ward) и Йена Р. Кука (Ian R. Cooke) The Inside Story on Shared Libraries and Dynamic Loading («Внутренняя история совместно используемых библиотек и динамической загрузки», журнал Computing in Science & Engineering, сентябрь/октябрь 2001), а также к таким онлайн-ресурсам, как Program Library HOWTO . Стоит также прочитать страницу руководства ld.so(8).
Вывод зависимостей совместно используемой библиотеки
Файлы совместно используемой библиотеки обычно размещаются там же, где и статические библиотеки. Двумя стандартными каталогами для библиотек в системе Linux являются /lib и /usr/lib. Каталог /lib не должен содержать статических библиотек.
Имя файла совместно используемой библиотеки содержит суффикс .so (shared object — «совместно используемый объект»), как, например, у файлов libc-2.15.so и libc.so.6. Чтобы увидеть, какие совместно используемые библиотеки применяет команда, запустите команду ldd prog (параметр prog — это имя исполняемого файла). Вот пример для команды оболочки:
$ ldd /bin/bash
linux-gate.so.1 => (0xb7799000)
libtinfo.so.5 => /lib/i386-linux-gnu/libtinfo.so.5 (0xb7765000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb7760000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75b5000)
/lib/ld-linux.so.2 (0xb779a000)
В интересах оптимального быстродействия и гибкости исполняемые файлы обычно не знают о расположении своих совместно используемых библиотек; они знают лишь их названия и, возможно, немного о том, где их искать. Небольшая команда ld.so (динамический компоновщик/загрузчик времени исполнения) отыскивает и загружает совместно используемые библиотеки для команды во время исполнения. В приведенном выше отчете команды ldd имена библиотек показаны слева — именно они известны исполняемому файлу. Правая часть показывает, где команда ld.so ищет данную библиотеку.
Последняя строка приведенного отчета дает актуальное местоположение команды ld.so: ld-linux.so.2.
Как команда ld.so отыскивает совместно используемые библиотеки
Одной распространенной проблемой совместно используемых библиотек является то, что динамический компоновщик не может отыскать библиотеку. Первое местоположение, в котором компоновщику обычно следует искать совместно используемые библиотеки, — это заранее сконфигурированный путь поиска библиотеки времени исполнения (rpath) для исполняемого файла, если такой путь существует. О том, как его определить, вы вскоре узнаете.