Программирование для Linux. Профессиональный подход - страница 23

стр.

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

Если библиотеки не должны инсталлироваться в каталог >/lib или >/usr/lib, нужно дважды подумать, стоит ли их делать совместно используемыми. (Библиотеки нельзя помещать в указанные каталоги, если предполагается, что программу будут инсталлировать пользователи, не имеющие привилегий системного администратора.) В частности, прием с флагом >-Wl,-rpath не будет работать, поскольку не известно, где именно окажутся библиотеки. А просить пользователей устанавливать переменную >LD_LIBRARY_PATH — не выход из положения, так как это означает для них выполнение дополнительного (для некоторых — не самого тривиального) действия.

Оценивать преимущества и недостатки двух типов библиотек нужно для каждой создаваемой программы отдельно.

2.3.6. Динамическая загрузка и выгрузка

Иногда на этапе выполнения программы требуется загрузить некоторый код без явной компоновки. Рассмотрим приложение, поддерживающее подключаемые модули: Web-броузер. Архитектура броузера позволяет сторонним разработчикам создавать дополнительные модули, расширяющие функциональные возможности броузера. Модуль реализуется в виде совместно используемой библиотеки и размещается в заранее известном каталоге. Броузер автоматически загружает код из этого каталога.

Для этих целей в Linux существует специальная функция >dlopen(). Например, открыть библиотеку >libtest.so можно следующим образом:

>dlopen("libtest.so", RTLD_LAZY)

Второй параметр — это флаг, определяющий способ привязки символических констант в библиотеке. Данная установка подходит в большинстве случаев. Подробнее узнать о ней можно в документации.

Объявление функций работы с динамическими библиотеками находится в файле >. Использующие их программы должны компоноваться с флагом >-ldl, обеспечивающим подключение библиотеки >libdl.

Функция >dlopen() возвращает значение типа >void*, используемое в качестве дескриптора динамической библиотеки. Это значение можно передавать функции >dlsym(), которая возвращает адрес функции, загружаемой из библиотеки. Например, если в библиотеке >libtest.so определена функция >my_function(), то она вызывается следующим образом:

>void* handle = dlopen("libtest.so", RTLD_LAZY);

>void (*test)() = dlsym(handle, "my_function");

>(*test)();

>dlclose(handle);

С помощью функции >dlsym() можно также получить указатель на статическую переменную, содержащуюся в совместно используемой библиотеке.

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

Функция >dlclose() выгружает совместно используемую библиотеку. Строго говоря, функция >dlopen() загружает библиотеку лишь в том случае, если она еще не находится в памяти. В противном случае просто увеличивается число ссылок на файл. Аналогичным образом функция >dlclose() сначала уменьшает счетчик ссылок, и только если он становится равным нулю, выгружает библиотеку.

Когда совместно используемая библиотека пишется на C++, имеет смысл объявлять общедоступные функции со спецификатором >extern "С". Например, если функция >my_function() написана на C++ и находится в совместно используемой библиотеке, а нужно обеспечить доступ к ней с помощью функции >dlsym(), объявите ее следующим образом:

>extern "С" void my_function();

Тем самым компилятору C++ будет запрещено подменять имя функции. При отсутствии спецификатора >extern "С" компилятор подставит вместо имени >my_function совершенно другое имя, в котором закодирована информация о данной функции. Компилятор языка С не заменяет имена; он работает с теми именами, которые назначены пользователем.

Глава 3