Библиотека играет очень важную роль в продвижении прогресса знаний, будь то публичная библиотека или цифровая.
В компьютерном мире библиотеки — это уже существующий код, который скомпилирован и готов к использованию. В каждом программном проекте, когда у вас есть повторно используемый или логически отдельный набор функций, полезно создать из него библиотеку. Это позволяет избежать создания какого-либо избыточного и большого кода, а также, когда вам нужно обновить часть логики, это можно сделать в одном месте (нет необходимости изменять в нескольких местах), что делает код более модульным. После того, как библиотека протестирована, мы можем безопасно использовать ее снова и снова, что избавляет нас от необходимости каждый раз пересобирать проект.
Хорошо, в библиотеке все хорошо, но как библиотека встраивается в наш проект?
Давайте разберемся с процессом, лежащим в основе исходного кода C до работающей программы:
- Предварительная обработка: на этом этапе обрабатываются все директивы препроцессора. По сути, любая строка, начинающаяся с #, например #define и #include. (т. е.) замена макроса, удаление комментариев, затем расширение включенных файлов.
- Компиляция: это этап, на котором компилятор создает промежуточный скомпилированный вывод, который включает инструкции уровня сборки.
- Сборка: на этом этапе файл .c превращается в файл .o (объект), который содержит инструкции машинного уровня существующего кода (вызовы функций, присутствующие в библиотеке, еще не разрешены).
- Связывание: Здесь все объектные файлы и любые библиотеки (статические или общие) связываются вместе, чтобы сделать вашу окончательную программу.
- Загрузка: этот этап происходит при запуске вашей программы. Ваша программа сканируется на наличие ссылок на разделяемые библиотеки. Любые найденные ссылки разрешаются, и библиотеки сопоставляются с вашей программой.
Существует три типа программных библиотек: статические библиотеки, разделяемые библиотеки и динамически загружаемые (DL) библиотеки. Некоторые люди используют термин динамически подключаемые библиотеки (DLL) для обозначения общих библиотек, некоторые используют термин DLL для обозначения любой библиотеки, которая используется в качестве библиотеки DL.
Здесь мы обсудим только статическую и динамическую (разделяемую) библиотеки.
Статическая библиотека
- Код, присутствующий в библиотеке, включается в окончательный исполняемый файл.
- Позволяет пользователям ссылаться на программы без перекомпиляции их кода, что экономит время перекомпиляции. Но его нужно перекомпилировать при каждом обновлении кода в статической библиотеке.
- статические библиотеки заканчиваются суффиксом «.a»
Создание статической библиотеки:
Давайте создадим нашу собственную статическую библиотеку строк
$ls *.c _strchr.c _strcmp.c _strcpy.c _strlen.c _strncpy.c
ongcc -c *.c получаем объектные файлы
$ls *.o *.c _strchr.c _strcmp.c _strcpy.c _strlen.c _strncpy.c _strchr.o _strcmp.o _strcpy.o _strlen.o _strncpy.o
с помощью программы ar (archiver) создаем статическую библиотеку из объектных файлов
$ar rc libstatic.a *.o $ls libstatic.a _strchr.o _strcmp.o _strcpy.o _strlen.o _strncpy.o _strchr.c _strcmp.c _strcpy.c _strlen.c _strncpy.c
используйте ranlib, который создает индекс содержимого архива и сохраняет его в архиве. В указателе перечислены все символы, определенные членом архива, который является перемещаемым объектным файлом.
$ranlib libstatic.a
используйте ar -t для просмотра таблицы содержимого архива.
$ar -t libstatic.a _strchr.o _strcmp.o _strcpy.o _strlen.o _strncpy.o
Динамическая библиотека
- Код не встраивается в окончательный исполняемый файл, а только ссылка на адрес памяти используемых функций.
- Нет необходимости перекомпилировать каждый раз, когда библиотека обновляется, поскольку в исполняемом файле присутствует только ссылка. (Но мы должны убедиться, что библиотека установлена правильно, иначе программа не будет работать)
- Динамические библиотеки заканчиваются суффиксом «.so».
Создание динамической библиотеки:
Давайте создадим собственную динамическую библиотеку libdynamic.so, содержащую все перечисленные ниже функции:
int _putchar(char c);
int _islower(int c);
int _isalpha(int c);
int _abs(int n);
int _isupper(int c);
int _isdigit(int c);
int _strlen(char *s);
void _puts(char *s);
char *_strcpy(char *dest, char *src);
int _atoi(char *s);
char *_strcat(char *dest, char *src);
char *_strncat(char *dest, char *src, int n);
char *_strncpy(char *dest, char *src, int n);
int _strcmp(char *s1, char *s2);
char *_memset(char *s, char b, unsigned int n);
char *_memcpy(char *dest, char *src, unsigned int n);
char *_strchr(char *s, char c);
unsigned int _strspn(char *s, char *accept);
char *_strpbrk(char *s, char *accept);
char *_strstr(char *haystack, char *needle);
создать заголовочный файл со списком всех вышеперечисленных функций
$ls *.c _abs.c _islower.c operations.c _strchr.c _strncat.c _strstr.c _atoi.c _isupper.c _putchar.c _strcmp.c _strncpy.c _isalpha.c _memcpy.c _puts.c _strcpy.c _strpbrk.c _isdigit.c _memset.c _strcat.c _strlen.c _strspn.c
Нам нужно скомпилировать исходный код нашей библиотеки в позиционно-независимый код (PIC).
$gcc -c -Wall -Werror -fPIC *.c
Затем мы можем создать общую библиотеку из всех сгенерированных объектных файлов.
$gcc -shared -o libdynamic.so *.o $ls -la lib* -rwxrwxr-x 1 hybridivy hybridivy 13513 Jun 7 19:57 libdynamic.so
с помощью nm мы можем перечислить все символы, присутствующие в библиотеке.
$nm -D libdynamic.so 0000000000000b75 T _abs 0000000000000d4c T add 0000000000000b8e T _atoi 0000000000202060 B __bss_start w __cxa_finalize 0000000000000d89 T div 0000000000202060 D _edata 0000000000202068 B _end 0000000000001230 T _fini w __gmon_start__ 00000000000009e0 T _init 0000000000000c38 T _isalpha 0000000000000c59 T _isdigit 0000000000000c7a T _islower 0000000000000c9b T _isupper w _ITM_deregisterTMCloneTable w _ITM_registerTMCloneTable w _Jv_RegisterClasses 0000000000001166 T _memcmp 0000000000000cbc T _memcpy 0000000000000d0d T _memset 0000000000000d9c T mod 0000000000000d76 T mul 0000000000000db1 T _putchar 0000000000000dd6 T _puts 0000000000000e14 T _strcat 0000000000000e93 T _strchr 0000000000000ece T _strcmp 0000000000000f1d T _strcpy 0000000000000f86 T _strlen 0000000000000fb4 T _strncat 000000000000103e T _strncpy 00000000000010c0 T _strpbrk 0000000000001114 T _strspn 00000000000011d1 T _strstr 0000000000000d60 T sub U write
Рассмотрите возможность использования _strlen для вычисления длины строки.
$cat main.c #include “holberton.h” #include <stdio.h> /** * main — check the code for Holberton School students. * * Return: Always EXIT_SUCCESS. */ int main(void) { printf(“%d\n”, _strlen(“Holberton”)); return (EXIT_SUCCESS); }
Использование созданной библиотеки - Связывание с общей библиотекой
$gcc -Wall -pedantic -Werror -Wextra -L. main.c -ldynamic -o out
Где -L. указывает компоновщику искать в текущем каталоге библиотеку -libdynamic.so и использовать код библиотеки при компиляции файла main.c и вывода связанных функций в файл out '
Чтобы перечислить зависимости:
ldd out
$ldd out linux-vdso.so.1 => (0x00007ffdbd38c000) libdynamic.so => not found libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f66e2549000) /lib64/ld-linux-x86–64.so.2 (0x0000561029add000)
Делаем библиотеку доступной во время выполнения
мы видим, что библиотека не связана во время выполнения, чтобы решить эту проблему, добавьте путь к библиотеке в переменную среды:
$export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH $ldd out linux-vdso.so.1 => (0x00007ffd5197a000) libdynamic.so => ./libdynamic.so (0x00007fac05fd5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fac05bf8000) /lib64/ld-linux-x86-64.so.2 (0x000055df2d6e2000)
Затем мы можем запустить программу
$./out 9
Дальше больше читать..