C-динамические (разделяемые) библиотеки

Мы говорили о статических библиотеках несколько дней назад здесь:



Я рекомендую вам прочитать этот пост, чтобы понять этот.

Почему вы должны использовать библиотеки?

Больше причин!

Библиотеки используют дизайн программного обеспечения, также известный как «общие компоненты» или «архивные библиотеки», который объединяет несколько скомпилированных файлов объектного кода в один файл, известный как библиотека. Обычно функции C/классы и методы C++, которые могут совместно использоваться более чем одним приложением, выделяются из исходного кода приложения, компилируются и объединяются в библиотеку. Стандартные библиотеки C и C++ STL являются примерами общих компонентов, которые можно связать с вашим кодом. Преимущество заключается в том, что каждый объектный файл не нужно указывать при компоновке, поскольку разработчик может ссылаться на коллектив библиотеки. Это упрощает многократное использование и совместное использование программных компонентов между приложениями. Это также позволяет поставщикам приложений просто выпускать API для взаимодействия с приложением. Большие компоненты могут быть созданы для динамического использования, поэтому библиотека может оставаться отдельной от исполняемого файла, уменьшая ее размер, и, таким образом, для приложения используется меньше места на диске. Затем компоненты библиотеки вызываются различными приложениями для использования по мере необходимости.

Статические и динамические библиотеки

- Процедура сборки:

Динамика: полная.

  • Компиляция: Да
  • Связывание: Да

Статика: неполная.

  • Компиляция: Да
  • Связывание: нет (связывание происходит при сборке исполняемого файла клиента с использованием статической библиотеки)

- Файл, необходимый после сборки исполняемого файла:

Динамический: Да

  • Динамическая библиотека должна быть упакована с исполняемым файлом и должна быть доступна, когда исполняемый файл запускается (точнее, вызывает функцию, предоставляемую динамической библиотекой).

Статический: Нет

  • Статическая библиотека нужна только во время сборки исполняемого файла (на этапе компоновки). Нет необходимости запускать исполняемый файл, потому что код библиотеки встроен в приложение.

- Эффективность дискового пространства:

Динамический: высокий

  • Одна и та же динамическая библиотека может совместно использоваться несколькими исполняемыми файлами на диске.

Статический: Низкий

  • Каждый исполняемый файл должен будет связать свою отдельную копию статической библиотеки. Это может вызвать раздувание двоичных файлов на диске и особенно на мобильных устройствах с ограниченными ресурсами. Однако, если каждое приложение использует только небольшую часть всей статической библиотеки, эффективность использования дискового пространства все равно может быть конкурентоспособной по сравнению с одной большой библиотекой DLL.

- Эффективность памяти

Динамический: высокий

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

Статический: Низкий

  • Если сетевой стек Http находится в статической библиотеке, каждое приложение, которому требуется эта функциональность, будет загружать свою копию сетевого стека и влиять на оперативную память в целом.

- Проблемы с версиями:

Динамический: возможен

  • Вы можете столкнуться с проблемами, когда версия динамической библиотеки, используемая вашим приложением, конфликтует с более старой/новой версией библиотеки, присутствующей в операционной системе.

Статический: Не существует

  • Поскольку все функции библиотеки связаны с приложением, не имеет значения, используют ли другие приложения в системе другую версию статической библиотеки.

- Пригодность во время разработки

Динамика: Хорошо

  • Перекомпилировать нужно только функциональность динамической библиотеки.

Статичный: громоздкий

  • Все приложение нужно будет перекомпилировать. Для большого приложения, такого как игра AAA или что-то столь же большое, как Office, может потребоваться несколько часов, если все функции связаны статически, а не в отдельных библиотеках DLL.

Как они работают?

Как вы знаете, при компиляции исходного файла вы получаете объектный файл. В зависимости от вашей платформы его расширение может быть .o . Статическая библиотека — это набор объектных файлов. компоновщик при попытке создать исполняемый файл пытается разрешить символы, на которые ссылаются, т. е. найти, в каком объектном файле (в библиотеке или где-то еще) они определены, и связать их вместе. Таким образом, статическая библиотека может также содержать индекс определенных символов, чтобы облегчить это. Точная реализация зависит от конкретного компоновщика и формата файла библиотеки, но базовая архитектура такая, как уже упоминалось.

Теперь давайте создадим динамическую (общую) библиотеку.

Нам нужно:

  • Функции C(8–24_hours.c)
  • Основной (main.c)
  • Заголовочный файл (holberton.h)

1: компилировать

Нам нужно скомпилировать с флагом -fpic, но что это такое?

  • -fpic — это директива компилятора для вывода независимого от позиции кода, что требуется для общих библиотек.
  • -fpic скомпилировать исходный код нашей библиотеки в позиционно-независимый код (PIC)
  • PIC — это код, который работает независимо от того, где в памяти он находится. Поскольку несколько разных программ могут использовать один экземпляр вашей общей библиотеки.

Мы можем выполнить компиляцию, используя эту строку:

gcc -Wall -Werror -Wextra -pedantic -fpic -c *.c

2: Сделать библиотеку из объектных файлов

мы можем использовать эту строку:

gcc -shared -o libmedium.so *.o

Но что означает флаг -shared?

  • -shared: создание общего объекта, который затем может быть связан с другими объектами для формирования исполняемого файла. Не все системы поддерживают эту опцию.

3: Связывание с общей библиотекой

Мы можем использовать эту строку:

gcc -Wall -pedantic -Werror -Wextra -L. main.c -lmedium -o medium_24_hours

что такое -L. флаг?

  • Мы сообщаем компоновщику, что библиотека находится в заданном каталоге («.», текущий каталог), в дополнение к стандартным расположениям, в которых компилятор ищет системные библиотеки.

А как насчет флага -lmedium?

  • Опция lmedium ищет не libmedium.o, а libmedium.so. GCC предполагает, что все библиотеки начинаются с lib и заканчиваются на .so или .a (.so — для общих объектов или общих библиотек, а .a — для архивов или статически связанных библиотек).

4: добавьте текущий каталог в LIBRARY_PATH

Если мы попытаемся запустить нашу программу (medium_24_hours) сейчас, то получим ошибку.

Почему:

GCC сначала ищет библиотеки в /usr/local/lib, затем в /usr/lib. После этого он ищет библиотеки в каталогах, указанных в переменной LD_LIBRARY_PATH. (сейчас он понятия не имеет, где находится)

Мы можем использовать эту строку, чтобы решить проблему:

экспорт LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

«.» означает текущий каталог. Итак, мы добавляем текущий каталог в переменную среды LD_LIBRARY_PATH.

Теперь мы можем запустить программу

Но… что, если мы хотим увидеть зависимости библиотеки?

Для этого у нас есть команда ldd

ldd:

печатает общие объекты (общие библиотеки), требуемые каждой программой или общим объектом, указанным в командной строке

мы можем использовать его так:ldd medium_24_hours