1.) Для разделяемых библиотек требуется независимый от позиции код (-fpic или -fPIC для библиотек), а независимый от позиции код требует настройки. Это делает для большего кода; например:
Используя предыдущий пример, realfoo()
может рассматриваться для встраивания в статической сборке, если включена и поддерживается правильная оптимизация. Это связано с тем, что компилятор имеет прямой доступ к объекту в файле архива (libfoo.a). Вы можете рассматривать файл .a как псевдо-каталог, содержащий отдельные объектные файлы.
«Отсутствие необходимости перекомпилировать весь двоичный файл для ошибки в библиотеке» режет оба пути. Если ваш двоичный файл не использует ошибочную ошибку, он, вероятно, был скомпилирован из статического двоичного файла, и замена совместно используемой библиотеки кодом из последней магистрали с исправлением может привести к (множеству) другим, еще не сообщенным ошибкам.
Начальное время запуска. Хотя многие сторонники разделяемых библиотек предполагают, что использование разделяемых библиотек сократит время запуска из-за того, что другие программы уже используют их, и (иногда) меньший размер двоичного файла. На практике это редко так, за исключением некоторых действительно базовых приложений X11. Как ни странно, мое время запуска X сократилось до 1/10 секунды с 5 секунд, когда я переключился на статическую сборку с помощью musl-libc и tinyX11 из общего ресурса glibc + X11. На практике большинство статических двоичных файлов запускаются быстрее, поскольку им не нужно инициализировать все (возможно, неиспользуемые) символы в каждой зависимой библиотеке. Кроме того, последующие вызовы того же двоичного файла получают те же преимущества предварительной загрузки, что и общие библиотеки.
Используйте динамическую библиотеку, когда библиотека плоха для статических сборок. Например, gnu-libc (также известный как glibc), как известно, плохо работает со статическими сборками: базовый мир приветствия весит около 1 МБ, в то время как musl-libc, diet-libc и uclibc создают приветственный мир размером около 10 КБ. Вдобавок к этому glibc пропустит некоторые ключевые (в основном связанные с сетью) функциональные возможности в статических сборках.
Используйте совместно используемую библиотеку, если библиотека использует «плагины» для ключевой функциональности; Например, загрузка значков gtk и некоторые другие функции были встроены с помощью встроенных плагинов, но в течение самого длительного времени, когда они были сломаны, поэтому единственным выходом было использование общих библиотек. Некоторые библиотеки C не поддерживают загрузку произвольных библиотек (например, musl), если они не созданы как общая библиотека, поэтому, если вам нужно загрузить библиотеку «на лету» как «плагин» или «модуль», вам, по крайней мере, может понадобиться библиотека C для совместного использования. Обходной путь для статических сборок - использовать вместо них указатели на функции и лучший, более стабильный инструментарий с графическим интерфейсом для конкретного случая GTK. Если вы создаете расширяемый язык программирования, такой как perl или python, вам потребуются возможности совместно используемой библиотеки для написания оптимизированных плагинов на скомпилированном языке.
Используйте совместно используемую библиотеку, если вам абсолютно необходимо использовать библиотеку с лицензией, несовместимой со статическим построением. (AGPL, GPL, LGPL без предложения статической ссылки) ... и, конечно, если / когда у вас нет исходного кода.
Используйте статические сборки, когда вы хотите более агрессивную оптимизацию. Многие хорошо подготовленные библиотеки, такие как libX11, были написаны, когда cdecl был основным соглашением о вызовах. Следовательно, многие функции X11 принимают загрузочный параметр в том же порядке, что и структура, которой манипулирует функция (а не просто указатель на структуру) ... что имеет смысл с соглашением о вызовах cdecl, поскольку теоретически вы можете просто переместить указатель стека и вызвать функцию. Однако это нарушается, как только вы используете некоторое количество регистров для передачи параметров. При статических сборках некоторые из этих непреднамеренных последствий могут быть смягчены с помощью встраивания и оптимизации времени соединения. Это только один пример. Есть много других оптимизаций, которые возникают при стирании границ функций.
Безопасность памяти может идти в любом направлении. Со статическими двоичными файлами вы не подвержены атакам LD_PRELOAD (статический двоичный файл может иметь только 1 символ - точку входа), но совместно используемый (и статический круговой индикатор, если поддерживается) может иметь рандомизацию адресного пространства, которая доступна только для статических сборок на несколько архитектур, которые поддерживают независимые от позиции исполняемые файлы (хотя большинство распространенных архитектур действительно поддерживают PIE).
Совместно используемые библиотеки могут (иногда) создавать меньшие двоичные файлы, поэтому, если вы используете совместно используемые библиотеки, которые в любом случае будут в системе, вы можете немного уменьшить размер пакета (и, следовательно, нагрузку на сервер). Однако, если вам все равно придется отправлять совместно используемые библиотеки, объединенный размер библиотек и двоичного файла всегда будет больше, чем статического двоичного файла, за исключением каких-то сумасшедших агрессивных вставок. Хорошим компромиссом является использование общих общих системных библиотек (например, libc, X11, zlib, png, glib и gtk / qt / other-default-toolkit) при использовании статических библиотек для необычных зависимостей или библиотек, специфичных для вашего пакета. Браузер Chrome делает это в некоторой степени. Хороший способ определить общее / статическое пороговое значение в целевом дистрибутиве Linux - выполнить итерации по * / bin и * / sbin при установке по умолчанию с помощью ldd или objdump -x и проанализировать выходные данные с помощью sort и uniq, чтобы определить правильное ограничение. Если вы распространяете несколько двоичных файлов, которые используют большинство одних и тех же библиотек, куча статических сборок увеличит раздувание, но вы можете рассмотреть возможность использования двоичного файла multicall (например, в busybox, toybox, mupdf или netpbm)
Используйте статические сборки, если вы хотите избежать "ада DLL" или для перекрестной совместимости с дистрибутивами. Статический бинарный файл, созданный в одном дистрибутиве, должен работать на любом другом дистрибутиве, который достаточно актуален (в основном это версии ядра, чтобы не пытаться использовать неподдерживаемые системные вызовы).
Для получения дополнительной информации о преимуществах статического связывания см .: stali (сокращение от static linux)
О пропаганде совместно используемой библиотеки от бывшего сопровождающего glibc см. Ульриха Дреппера «Статическое связывание считается вредным» Хотя примерно половина проблем со статическим связыванием, о которых он упоминает, являются специфическими для glibc проблемами (диета, у musl и uclibc нет одинаковых проблем).
Если вы считаете, что статические библиотеки недостаточно далеко подходят для полной оптимизации, посмотрите список библиотек с одним файлом Шона Барретта. Их часто можно настроить так, чтобы все функции были статичными, чтобы двоичный файл можно было собрать как единый модуль компиляции. Это позволяет выполнить несколько оптимизаций, которых невозможно достичь с помощью оптимизации времени соединения, но вам лучше иметь IDE, поддерживающую свертывание кода.