При работе над большими проектами компилировать множество файлов вместе может быть неприятно. Это еще большая проблема при обмене файлами с другими. Библиотеки позволяют нам организовывать и использовать функции без необходимости копировать исходный код в каждое место.
Если вы когда-нибудь программировали на C, вы, вероятно, начали свой файл с чего-то вроде
include <stdlib.h>
Когда вы делаете это, вы вызываете функцию заголовка для стандартной библиотеки. Каждый из файлов в стандартной библиотеке существует как исходный код, но вам не нужно компилировать их в свой файл, поскольку компилятор уже имеет доступ к библиотеке. Вы можете создать свою собственную библиотеку, чтобы работать аналогично.
Есть два разных типа библиотек, статические и динамические. Статическая библиотека, также известная как архив, представляет собой индексированную библиотеку, на которую компилятор ссылается только один раз. Компоновщик копирует код библиотеки при создании исполняемого файла. Статические библиотеки занимают больше памяти, но могут ускорить время выполнения.
Динамическая библиотека, также известная как разделяемая библиотека, связывает код во время выполнения исполняемого файла, а не во время компиляции. Вместо копирования кода компилятор просто проверяет наличие всех объектных файлов на этапе компоновки. Затем динамический загрузчик загружает общие файлы в память перед запуском исполняемого файла. Динамические библиотеки выгодны тем, что они не требуют от пользователя повторной компиляции основного файла каждый раз, когда в библиотеке происходит обновление. Однако они могут повредить скорости исполняемого файла.
Создание библиотек
Чтобы создать библиотеку, сначала создайте заголовочный файл, содержащий все прототипы, которые вы собираетесь включить. Затем вам нужно скомпилировать код.
$ gcc -c *.c
Флаг -c предписывает компилятору проходить файлы через все этапы компиляции, кроме компоновщика. Если вы создаете динамическую библиотеку, вам также потребуется использовать флаг -fPIC. Это создает независимый от позиции код, это означает, что он будет выполняться правильно, независимо от того, где он находится в памяти.
Создание статических библиотек
Для создания статической библиотеки используйте команду архиватора:
$ ar rc libfoo.a *.o
Флаг r предписывает архиватору заменить старые версии файлов новыми, а флаг c предписывает создать новый архив, если он еще не существует. Все статические библиотеки заканчиваются на .a для archive.
Статические библиотеки должны быть проиндексированы после создания. Это упорядочивает символы библиотеки, упрощая и ускоряя доступ к ним.
$ ranlib newlibrary.a
Создание динамических библиотек
$ gcc -shared -o libfoo.so *.o
Флаг -shared создает общую библиотеку. Все динамические библиотеки заканчиваются на .soдля общего объекта.
Давайте воспользуемся командой ldd для вывода зависимостей наших общих объектов.
myvm:~/library_practice $ gcc -L. main.c libholberton.so -o check myvm:~/library_practice$ ldd check linux-vdso.so.1 => (0x00007fff27372000) libfoo.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 => (0x00007fc349e7c000) /lib64/ld-linux-x86-64.so.2 (0x00007fc34a245000)
Наконец, экспортируйте путь к библиотеке, чтобы дочерние процессы могли получить к нему доступ с помощью переменной среды.
Подробнее о дочерних процессах читайте в этой статье, в которой я разбираю оболочку.
$ export LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH
Когда мы снова проверим это с помощью ldd, мы увидим, что общие зависимости были обновлены.
myvm:~/library_practice $ gcc -L. main.c libholberton.so -o check myvm:~/library_practice$ ldd check linux-vdso.so.1 => (0x00007fff27372000) libfoo.so => /home/vagrant/library_practice/libfoo.so (0x00007fd7b2e79000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 => (0x00007fc349e7c000) /lib64/ld-linux-x86-64.so.2 (0x00007fc34a245000)
После создания вы можете использовать команду nm для отображения списка символов в вашей библиотеке.
myvm:~/library_practice $ nm liball.so 0000000000000f89 T _abs 0000000000000af7 T _atoi 0000000000202040 B __bss_start 0000000000202040 b completed.6982 w __cxa_finalize@@GLIBC_2.2.5 0000000000000900 t deregister_tm_clones 0000000000000970 t __do_global_dtors_aux 0000000000201e08 t __do_global_dtors_aux_fini_array_entry 0000000000202038 d __dso_handle 0000000000201e18 d _DYNAMIC 0000000000202040 D _edata 0000000000202048 B _end 000000000000103c T _fini 00000000000009b0 t frame_dummy 0000000000201e00 t __frame_dummy_init_array_entry 0000000000001398 r __FRAME_END__ 0000000000202000 d _GLOBAL_OFFSET_TABLE_ w __gmon_start__ 0000000000000890 T _init 0000000000000de6 T _isalpha 0000000000000b01 T _isdigit 0000000000000c81 T _islower 00000000000009e5 T _isupper w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable 0000000000201e10 d __JCR_END__ 0000000000201e10 d __JCR_LIST__ w _Jv_RegisterClasses 0000000000000b22 T _memcpy 0000000000000a06 T _memset 0000000000001016 T _putchar 0000000000000ca7 T _puts 0000000000000930 t register_tm_clones 0000000000000a41 T _strcat 0000000000000b65 T _strchr 0000000000000ce2 T _strcmp 0000000000000faf T _strcpy 0000000000000baf T _strlen 0000000000000bd9 T _strncpy 0000000000000e1a T _strpbrk 0000000000000d57 T _strspn 0000000000000ee6 T _strstr 0000000000202040 d __TMC_END__ U write@@GLIBC_2.2.5
Использование библиотек в системе Linux
По словам Артура, «развлекаться несложно, когда у тебя есть читательский билет!»
Теперь, когда вы создали свою библиотеку, пришло время ее использовать. Независимо от того, какой тип библиотеки вы используете, следует помнить о нескольких вещах. Во-первых, поскольку компилятор не будет использовать библиотеку до этапа компоновки, все команды, связанные с библиотекой, должны идти после файла. Во-вторых, флаг -l даст компилятору имя библиотеки для ссылки.
Использование статической библиотеки
Статические библиотеки компилируются вместе с файлами, необходимыми для программы.
$ gcc main.c -L. -lfoo.a -o executablename
При работе со статическими библиотеками параметр -L. флаг сообщает компилятору, где искать библиотеку.
Использование динамической библиотеки
В динамических библиотеках дополнительные флаги не нужны. Вы можете использовать библиотеку, скомпилировав ее со своими файлами.
$ gcc main.c -lfoo -o executablename
Поскольку мы уже обновили путь к библиотеке, нам не нужно ничего указывать с помощью -L.
Но не забывайте, что динамические библиотеки также называются разделяемыми библиотеками. Так что же произойдет, если мы захотим, чтобы другие люди могли их использовать? Во-первых, поместите библиотеку в общую зону и обновите разрешения. Затем используйте команду ldconfig, чтобы обновить кеш и создать ссылку на общую библиотеку.
Как только вы освоите эти шаги, вы будете готовы создавать свои собственные библиотеки. Украсьте закладку временем, которое вы сэкономите на своем следующем проекте!