Для устранения недочетов статических библиотек были придуманы динамические (разделяемые).
Их ключевая идея состоит в том, что объектные модули не копируются в исполняемый файл: вместо этого единый экземпляр библиотеки загружается в память при запуске первой, от нее зависящей, программы. Если позже будут запущены другие приложения, которым нужна эта библиотека, они обратятся к уже загруженной копии. В результате такой концепции исполняемые файлы требуют меньше места на диске и в виртуальной памяти.
Разделяемые библиотеки обладают следующими преимуществами:
1. Общий размер программ уменьшается, в связи с чем они могут быстрее загружаться в память и, как следствие, запускаться. Это относится только к большим разделяемым библиотекам, которые уже используются другими процессами. На самом деле, программа, которая первой начинает использовать библиотеку, запускается дольше остальных, т.к. с ее инициализацией происходит поиск библиотеки и выгрузка ее в память.
2. Объектные модули не копируются в исполняемые файлы, поэтому можно изменять исходный код библиотеки без необходимости выполнения повторной компоновки. Полностью осознать данное преимущество поможет вымышленный пример, где стандартная библиотека C (libc) является статической. Если кто-нибудь найдёт и исправит баг в printf, то каждая программа должна будет заново пройти компоновку для того, чтобы заполучить исправленный код.
Использование динамических библиотек действительно полезно в случае, когда они являются необходимыми для большинства программ и имеют внушительный размер (QT/GTK).
Однако за эти дополнительные возможности приходится платить:
1. Динамические библиотеки более сложные по сравнению со статическими - как с точки зрения самой концепции, так и в плане создания и компоновки внутри программ.
2. Излишняя зависимость: если в библиотеку было внесено изменение, нарушающее ее совместимость с приложением, запуск будет невозможен. Со статически собранным вариантом такой проблемы не наблюдается, т.к. в нем все необходимые объектные файлы хранятся в виде копий.
3. Перемещение символов должно выполняться во время работы программы: этот процесс требует дополнительных работ, в том числе, выгрузки ядром разделяемой библиотеки динамического линковщика ld-linux.so для связывания на этапе выполнения. Все это приводит к затратам по времени, поэтому программа может работать немного медленнее статически скомпонованного аналога.
Для сборки динамической версии библиотеки необходимо выполнить:
/* -Wall - выводит предупреждения, вызванные потенциальными ошибками в коде, не препятствующими компиляции программы, но способными привести, по мнению компилятора, к тем или иным проблемам на этапе выполнения. */
// -fPIC - завставляет компилятор сгенерировать адресно-независимый код.
$ gcc -c -fPIC -Wall module1.c module2.c module3.c
/* -shared - указывает gcc, что в результате должен быть собран не исполняемый файл, а разделяемый объект - динамическая библиотека. */
$ gcc -shared -o libdemo.so module1.o module2.o module3.o