В предыдущей статье мы говорили о статических библиотеках на C и о том, как они работают. В этой статье мы познакомимся с концепцией общих или динамических библиотек и объясним плюсы и минусы обоих типов библиотек.
Зачем нужны библиотеки?
Как упоминалось ранее, библиотеки позволяют нам хранить определения функций, то есть фрагменты кода, которые будут использоваться в нашей исполняемой программе. Это позволяет избежать утомительной задачи по компиляции огромного количества исходных файлов, не правда ли? Библиотеки состоят из объектных файлов с расширением ‘.o’ и могут быть созданы в Linux с помощью компилятора gcc. Затем нам решать, хотим ли мы создать статическую или общую библиотеку.
Как работают библиотеки
После создания библиотеки их можно связать с файлом, содержащим основную функцию или точку входа, с помощью gcc. Затем код функций, используемых в программе, будет связан с исполняемой программой, и она будет готова к запуску!
Как создавать библиотеки (только для Linux)
Давайте возьмем в качестве примера файл «my_file.c». В обоих случаях нам нужно сначала создать объектные файлы. Это делается с помощью следующих команд:
Статический:
$ gcc -c my_file.c
Динамический:
$ gcc -c -fPIC my_file.c
Опция ‘-c’ гарантирует, что процесс компиляции останавливается перед компоновщиком, и создает файл ‘my_file.o’ (см. Мою статью о компиляции).
Мы используем дополнительный флаг для динамических библиотек: «-fPIC» или «-fpic». Это делает код в библиотеке независимым от позиции. PIC — это код, который работает независимо от того, где он находится в памяти. Почему это имеет значение? Поскольку несколько программ могут использовать одну и ту же общую библиотеку, библиотека будет иметь разные адреса в памяти для каждой программы. И мы по-прежнему хотим, чтобы наши программы имели доступ к коду, где бы он ни хранится.
Теперь мы можем создать библиотеку mylib с нашим объектным файлом. Вот как:
Статический:
$ ar rc libmylib.a my_file.o
Динамический:
$ gcc -shared -o libmylib.so my_file.o
В первом случае мы используем команду ar для создания файла ‘.a’ (a означает архив), а во втором случае мы используем gcc с флагами ‘-shared’ и, конечно же, ‘-o’, потому что мы компилируем из объектного файла, чтобы создать ‘.so’ файл (то же самое для общего объекта).
Как использовать библиотеки (только для Linux)
Теперь, когда у нас есть библиотека, мы должны использовать ее для компиляции и создания нашей программы. Допустим, наша точка входа находится в файле «main.c», и мы хотим назвать нашу программу «test». Вот команда для компиляции программы с нашей библиотекой в обоих случаях:
$ gcc -L. main.c -lmylib -o test
Флаг ‘-L’ сообщает компилятору, где ему нужно искать библиотеку, поэтому в этом случае, когда библиотека находится в текущем рабочем каталоге, мы просто используем точку. ‘-lmylib’ указывает компилятору связать код в main.c с кодом в библиотеке my_lib. Наконец, флаг ‘-o’ позволяет нам дать имя исполняемому файлу, в данном случае это будет «test».
Этим динамические библиотеки отличаются от статических. Имея статическую библиотеку, мы можем просто запустить код сейчас. Но с динамической библиотекой это не сработает. Полезный инструмент для демонстрации этого — команда ldd, которая выводит зависимости разделяемых библиотек. В нашем случае вывод «ldd test» будет содержать строку, в которой говорится:
libmylib.so => not found
Это означает, что загрузчик не сможет найти библиотеку во время выполнения, поэтому нам нужно разместить ее в стандартном месте. Это делается путем обновления переменной среды LD_LIBRARY_PATH и добавления нашего рабочего каталога к его существующему значению. Вот простая команда для этого:
$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
Давайте попробуем снова «ldd test», и результат будет следующим:
libmylib.so => ./libmylib.so (0x00007fd4bf2d9000)
В дополнение к ldd для зависимостей мы можем использовать команду ‘nm’, чтобы проверить символы динамической библиотеки. Эти символы включают функции, определенные в библиотеке. Для динамических библиотек мы используем флаг -D, например:
$ nm -D libmylib.so
Хорошо, теперь, когда мы уверены, что динамическая библиотека создана и ее можно использовать, мы можем запустить нашу программу, набрав «./test» в командной строке.
Плюсы и минусы двух типов библиотек
Первое преимущество динамической библиотеки перед статической заключается в том, что она занимает меньше места в памяти, потому что статическая библиотека будет связывать все определения функций в программе, тогда как динамическая библиотека будет смотреть в коде и видеть, какие функции вызываются. , и свяжите с программой только их.
Еще одно преимущество динамической библиотеки перед статической заключается в том, что если мы изменим код в одной из функций, которые она содержит, нам не потребуется перекомпилировать, мы можем просто выполнить программу снова! Это невозможно со статической библиотекой, нам придется перекомпилировать ее (см. Блок-схему в верхней части этой статьи). Кроме того, несколько программ могут использовать динамическую библиотеку.
Статическая библиотека также имеет преимущества перед динамической библиотекой. Один из них заключается в том, что программа, использующая его, работает быстрее во время выполнения. Это потому, что мы связали библиотеку до времени выполнения, тогда как динамические библиотеки фактически подключаются во времени выполнения. Другой заключается в том, что весь код функций находится в исполняемом файле, поэтому проблем совместимости нет.
Заключение
Хотя это, возможно, не самый увлекательный предмет в информатике, люди, которые пишут код на C, должны знать инструменты и методы, о которых мы говорили, для создания библиотек. В зависимости от приложения разработчики могут выбирать статические или динамические библиотеки, которые являются одновременно очень полезными и практичными инструментами для создания программ.
Источники