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

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

Хорошо, в библиотеке все хорошо, но как библиотека встраивается в наш проект?

Давайте разберемся с процессом, лежащим в основе исходного кода C до работающей программы:

  1. Предварительная обработка: на этом этапе обрабатываются все директивы препроцессора. По сути, любая строка, начинающаяся с #, например #define и #include. (т. е.) замена макроса, удаление комментариев, затем расширение включенных файлов.
  2. Компиляция: это этап, на котором компилятор создает промежуточный скомпилированный вывод, который включает инструкции уровня сборки.
  3. Сборка: на этом этапе файл .c превращается в файл .o (объект), который содержит инструкции машинного уровня существующего кода (вызовы функций, присутствующие в библиотеке, еще не разрешены).
  4. Связывание: Здесь все объектные файлы и любые библиотеки (статические или общие) связываются вместе, чтобы сделать вашу окончательную программу.
  5. Загрузка: этот этап происходит при запуске вашей программы. Ваша программа сканируется на наличие ссылок на разделяемые библиотеки. Любые найденные ссылки разрешаются, и библиотеки сопоставляются с вашей программой.

Существует три типа программных библиотек: статические библиотеки, разделяемые библиотеки и динамически загружаемые (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

Дальше больше читать..