Библиотеки C: динамические и статические

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

Зачем использовать библиотеки? Переработка кода. Использование библиотеки может сэкономить много времени и энергии. Вместо того, чтобы писать функции снова и снова, вы можете хранить функции в библиотеке для повторного использования позже и несколькими программами. У вас даже есть возможность использовать множество функций, написанных другими людьми. Некоторые распространенные библиотеки для использования: stdio.h (стандартный ввод и вывод) и stdlib.h (стандартная библиотека/динамическая память).

Чтобы иметь доступ к функциям, хранящимся в различных файлах, их прототипы/объявления вместе с любыми определениями макросов необходимо включить в заголовочный файл. Затем файлы компилируются с использованием gcc (Коллекция компиляторов GNU) и специальных флагов либо для статических, либо для динамических библиотек. Я расскажу больше о флагах, которые будут использоваться позже.

Если создается статическая библиотека, процесс компиляции файла прерывается на этапе компоновки. Затем библиотечные функции/объявления и определения макросов связываются вместе с объектным кодом файлов (машинным кодом). Результатом этого является исполняемый файл, который затем можно использовать для запуска программы.

Если создается динамическая библиотека, файлы компилируются, а объектный код и библиотека связываются во время выполнения.

Создание и использование библиотек:

Имя файла для библиотеки обычно имеет префикс lib, и в зависимости от того, является ли библиотека статической или динамической, суффикс может быть .a для «архива» или .so для «общего объекта».

статическая библиотека: libmylib.a

динамическая библиотека: libmylib.so

Статические библиотеки:

Статическая библиотека – это набор объектных файлов, который впоследствии связывается с объектным кодом программы (машинным кодом) на этапе компоновки компиляции. После компиляции у вас будет исполняемый файл, который на самом деле содержит копию кода из вашей библиотеки.

«Статические библиотеки увеличивают размер кода в вашем двоичном файле. Они всегда загружаются, и любая версия кода, которую вы скомпилировали, является версией кода, которая будет работать».

В моем предыдущем посте я объяснил, что такое статическая библиотека, как ее создать и как ее использовать. Щелкните ссылку ниже, чтобы прочитать о статических библиотеках:



Кроме того, вот еще один пост, который я написал о четырех этапах компиляции. Препроцессор, компилятор, ассемблер и компоновщик:



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

Чтобы создать динамическую библиотеку, сначала необходимо создать объектный файл с помощью следующей команды:

gcc -fPIC -c my_file.c

  • Флаг -fPIC, «Код, независимый от позиции», указывает компилятору создавать код, не зависящий от позиции. Этот код может быть загружен в исполняемый файл по любому проверенному адресу памяти. -fPIC — это характеристика, необходимая для разделяемых библиотек.
  • Флаг -c указывает компилятору остановиться на этапе компоновки компиляции.
  • Этот код создаст объектный файл с суффиксом .o:.

my_file.o

Теперь мы можем поместить код в динамическую библиотеку, используя этот код:

gcc -shared -o libmylib.so my_file.o

  • Флаг -shared указывает на необходимость создания общей библиотеки. Он создает общий объект, который впоследствии может быть связан с другими объектами для формирования исполняемого файла.
  • Флаг -o обозначает вывод. Здесь вы можете указать, в каком файле будет храниться наш исполняемый файл.

Как использовать динамическую библиотеку:

Теперь нам нужно связать библиотеки с программами, которые мы будем использовать. Для этого используйте код:

gcc my file.c -L. -lmylib

Как видите, префикс lib и суффикс .so исключены из команды, поскольку они позже разрешаются и повторно вставляются компилятором на этапе компоновки.

  • Флаг -l указывает имя используемой библиотеки.
  • Флаг L указывает путь к библиотеке
  • . указывает, что библиотека находится в текущем каталоге.

Следующим шагом является динамическое совместное использование библиотеки с другими программами во время компоновки. Для этого нам нужно указать переменную среды LD_LIBRARY_PATH, чтобы она указывала на путь к библиотеке.

export LD_LIBRARY_PATH=.$LD_LIBRARY_PATH

  • export — это команда, используемая для добавления библиотеки в путь среды.
  • . указывает операционной системе искать в текущем каталоге

Это сообщает загрузчику времени выполнения, что пути библиотек будут использоваться во время выполнения для разрешения зависимостей.

Чтобы использовать библиотеки в своих программах, просто укажите ссылку на них вверху вашего кода:

#include <libmylib.so>

За и против:

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

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

Если код в статической библиотеке будет обновлен, исполняемые файлы не будут обновляться автоматически. Их необходимо перекомпилировать, чтобы обновить их содержимое на новый код из библиотеки.

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

Подробнее:

Чтобы получить список зависимостей библиотеки, используйте команду ldd:

ldd libmylib.so

linux-vdso.so.1 =>  (0x00007ffcb8bec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff67d18d000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff67d758000)

Если вы получаете сообщение об ошибке после ввода этой команды, убедитесь, что ваша переменная окружения включает путь к вашей библиотеке.

Если вы хотите узнать, какие функции есть в библиотеке, используйте команду nm:

nm libmylib.so

0000000000201030 B __bss_start
0000000000201030 b completed.7553
w __cxa_finalize@@GLIBC_2.2.5
0000000000000590 t deregister_tm_clones
0000000000000620 t __do_global_dtors_aux
0000000000200e08 t __do_global_dtors_aux_fini_array_entry
0000000000201028 d __dso_handle
0000000000200e18 d _DYNAMIC
0000000000201030 D _edata
0000000000201038 B _end
00000000000006b4 T _fini
0000000000000660 t frame_dummy
0000000000200e00 t __frame_dummy_init_array_entry
0000000000000740 r __FRAME_END__
0000000000201000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
0000000000000540 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
0000000000200e10 d __JCR_END__
0000000000200e10 d __JCR_LIST__
w _Jv_RegisterClasses
0000000000000690 T main
00000000000005d0 t register_tm_clones
0000000000201030 d __TMC_END__

Если вы хотите узнать больше о статических библиотеках, прочитайте мой пост: Статические библиотеки

Это пока все!

Ресурсы:

https://www.linkedin.com/pulse/compiling-c-file-gcc-nicole-swanson

https://stackoverflow.com/questions/140061/когда-использовать-динамические-против-статических-библиотек

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

https://en.wikipedia.org/wiki/C_standard_library