Этот блог создан для всех, кто ищет ответы на вопросы об общих и динамических библиотеках. Поскольку поначалу эта тема может показаться немного запутанной, моя цель — как можно проще объяснить все, что с ней связано. Может быть, было бы правильно начать этот блог с представления того, что мы будем освещать. Это: что такое статическая библиотека, что такое динамическая библиотека, как они работают, почему они важны, как их создавать и использовать среди пользователей Linux, чем они отличаются и, наконец, каковы их преимущества и недостатки.

Прежде чем начать, я думаю, важно указать, на каком этапе учитываются эти библиотеки. Каждый файл .c для выполнения должен быть сначала скомпилирован; этот процесс компиляции состоит из 4 этапов перед созданием исполняемого файла. Наш интерес проявляется на последнем шаге под названием «Связывание». Здесь он берет общее количество сгенерированных объектных файлов и создает один исполняемый файл, во время этого процесса он берет каждый объектный файл и добавляет некоторые инструкции, которые можно найти в библиотеке, и делает вашу функцию, надеюсь, делать, если нет ошибки, что он должен делать. Вот почему это важно, так как C — небольшой язык, для его работы крайне необходимы библиотеки. Этот этап, как мне нравится, придает жизни вашему коду, потому что дает ему цель и причину что-то делать.

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

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

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

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

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

Чтобы создать статическую библиотеку, необходимо сначала запустить эту команду (Linux):

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

Здесь мы компилируем все файлы .c, используя некоторые флаги, которые в основном указывают вам на ошибки разных типов.

Существует программа, используемая для создания статических библиотек, называемая «ar», что означает «архиватор»; по инструкции эта программа создает, модифицирует и извлекает из архивов. Для его создания мы используем следующую команду:

$ ar -rc libname.a

Флаг r означает, что любые старые объекты в библиотеке будут заменены самыми новыми созданными. С другой стороны, флаг c означает, что архив будет создан.

Когда вы это сделаете, вы должны создать индекс для библиотеки с помощью команды «ranlib». Эта программа создает в библиотеке заголовок с символами содержимого объектного файла. Вы должны запустить эту команду после:

$ ranlib libname.a

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

$ gcc main.c -L. -libname.a -o executablename

Флаг -L сообщает компоновщику, что библиотеки можно найти в рабочем каталоге. Флаг -l выполняет поиск в указанной библиотеке, чтобы ее можно было принять во внимание. Параметр -o определяет имя исполняемого файла, в данном случае «exe». После этого просто запустите исполняемый файл с ./executablename.

Чтобы создать динамическую библиотеку, можно выполнить следующую команду (Linux):

$ gcc -fPIC -c *.c

Как указано в руководстве, опция fPIC: Если поддерживается для целевой машины, выдает позиционно-независимый код, подходящий для динамической компоновки и позволяющий избежать каких-либо ограничений на размер глобальной таблицы смещений. Этот параметр имеет значение для AArch64, m68k, PowerPC и SPARC. Позиционно-независимый код требует специальной поддержки и поэтому работает только на определенных машинах. Когда этот флаг установлен, макросы «__pic__» и «__PIC__» определяются как 2.И параметр -c компилирует файлы, но не связывает их с библиотеками.

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

gcc -shared -o libshared.so *.o

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

ПРИМЕЧАНИЕ. Префикс «lib» необходим для имени библиотеки, иначе он будет интерпретирован неправильно.

Здесь вы уже создали библиотеку, но поскольку вам нужно, чтобы ее можно было связать во время работы вашей программы, вы должны сохранить ее в переменной окружения с именем «LD_LIBRARY_PATH», поэтому выполните следующую команду, чтобы прибить ее:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

Теперь вам просто нужно скомпилировать файл .c следующим образом:

gcc -L. -lshared main.c

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

И это довольно много! Этот блог был сделан как задание для Holberton School, школы кодирования, и я был очень рад этому. Я действительно надеюсь, что это поможет всем тем людям, которые, как и я, любят программировать и хотят быть в этом лучшими. Большое спасибо, что нашли время, чтобы прочитать его, я очень ценю это.