Пример статических и динамических библиотек C / C ++ - PullRequest
3 голосов
/ 12 июня 2011

Я изучаю статические и динамические библиотеки. Пока я понимаю, зачем мне нужна динамическая библиотека. Если что-то меняется, лучше подключить более новую версию, и все приложения будут обновляться автоматически, даже не замечая этого.

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

Однако зачем кому-то использовать статическую библиотеку? Я имею в виду, в чем преимущество? У sb есть пример, чтобы я мог его лучше понять? Это сделать продукт проприетарным?

РЕДАКТИРОВАТЬ: Из-за путаницы в комментариях. Я понимаю, что такое статическая библиотека, и я также знаю разницу между динамической библиотекой. Это было просто вне меня, почему кто-то использовал статическую библиотеку вместо самого источника. Я думаю, что сейчас начинаю понимать, что статическая библиотека предлагает следующие преимущества:

а) лучшее обслуживание кода б) более быстрое время компиляции

Ответы [ 7 ]

7 голосов
/ 12 июня 2011

Существует еще одно различие между статическими и динамическими библиотеками, которые могут стать важными в некоторых ситуациях. Я удивлен, что никто не упоминает об этом.

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

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

Это превосходное подробное руководство по динамическим библиотекам в Linux - Как писать общие библиотеки . Это слишком детально для большинства из нас, но даже пролистывание дает много удивительных идей. Например, в нем говорится, что в выпуске 1.0 OpenOffice ему пришлось выполнить более 1,5 миллионов сравнений строк во время запуска!

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

5 голосов
/ 12 июня 2011

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

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

Как упоминалось в другом посте, управление зависимостями со статическими библиотеками имеет тенденцию бытьпроще просто потому что у тебя все под контролем.Вы можете не знать, какая dll / so установлена ​​в системе пользователя.

4 голосов
/ 12 июня 2011

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

Поскольку это просто ZIP объектных файлов, все, что компилятор делает с объектными файлами, также работает со статическими библиотеками, например, удаление мертвого кода и оптимизация всей программы (также называемая Link-Time Code Generation). Компилятор не будет включать биты разделяемой библиотеки в конечную программу, которые не используются, в отличие от динамических библиотек.

В некоторых системах сборки это также упрощает швы ссылок. Например. для MSVC ++ у меня часто будет «производственный» EXE-проект, «тестирующий» EXE-проект, и я помещаю общие вещи в статическую библиотеку. Таким образом, мне не нужно перестраивать все обычные вещи при сборке.

0 голосов
/ 03 ноября 2017

1.) Для разделяемых библиотек требуется независимый от позиции код (-fpic или -fPIC для библиотек), а независимый от позиции код требует настройки. Это делает для большего кода; например:

* Отчасти это связано с неэффективностью компилятора, как обсуждено здесь

long realfoo(long, long);
long foo(long x, long y){
    return realfoo(x,y);
}
//static
foo:
  jmp realfoo #
//shared (-fpic code)
foo:
  pushl %ebx #
  call __x86.get_pc_thunk.bx #
  addl $_GLOBAL_OFFSET_TABLE_, %ebx # tmp87,
  subl $16, %esp #,
  pushl 28(%esp) # y
  pushl 28(%esp) # x
  call realfoo@PLT #
  addl $24, %esp #,
  popl %ebx #
  ret
__x86.get_pc_thunk.bx:
  movl (%esp), %ebx #,
  ret
  1. Используя предыдущий пример, realfoo() может рассматриваться для встраивания в статической сборке, если включена и поддерживается правильная оптимизация. Это связано с тем, что компилятор имеет прямой доступ к объекту в файле архива (libfoo.a). Вы можете рассматривать файл .a как псевдо-каталог, содержащий отдельные объектные файлы.

  2. «Отсутствие необходимости перекомпилировать весь двоичный файл для ошибки в библиотеке» режет оба пути. Если ваш двоичный файл не использует ошибочную ошибку, он, вероятно, был скомпилирован из статического двоичного файла, и замена совместно используемой библиотеки кодом из последней магистрали с исправлением может привести к (множеству) другим, еще не сообщенным ошибкам.

  3. Начальное время запуска. Хотя многие сторонники разделяемых библиотек предполагают, что использование разделяемых библиотек сократит время запуска из-за того, что другие программы уже используют их, и (иногда) меньший размер двоичного файла. На практике это редко так, за исключением некоторых действительно базовых приложений X11. Как ни странно, мое время запуска X сократилось до 1/10 секунды с 5 секунд, когда я переключился на статическую сборку с помощью musl-libc и tinyX11 из общего ресурса glibc + X11. На практике большинство статических двоичных файлов запускаются быстрее, поскольку им не нужно инициализировать все (возможно, неиспользуемые) символы в каждой зависимой библиотеке. Кроме того, последующие вызовы того же двоичного файла получают те же преимущества предварительной загрузки, что и общие библиотеки.

  4. Используйте динамическую библиотеку, когда библиотека плоха для статических сборок. Например, gnu-libc (также известный как glibc), как известно, плохо работает со статическими сборками: базовый мир приветствия весит около 1 МБ, в то время как musl-libc, diet-libc и uclibc создают приветственный мир размером около 10 КБ. Вдобавок к этому glibc пропустит некоторые ключевые (в основном связанные с сетью) функциональные возможности в статических сборках.

  5. Используйте совместно используемую библиотеку, если библиотека использует «плагины» для ключевой функциональности; Например, загрузка значков gtk и некоторые другие функции были встроены с помощью встроенных плагинов, но в течение самого длительного времени, когда они были сломаны, поэтому единственным выходом было использование общих библиотек. Некоторые библиотеки C не поддерживают загрузку произвольных библиотек (например, musl), если они не созданы как общая библиотека, поэтому, если вам нужно загрузить библиотеку «на лету» как «плагин» или «модуль», вам, по крайней мере, может понадобиться библиотека C для совместного использования. Обходной путь для статических сборок - использовать вместо них указатели на функции и лучший, более стабильный инструментарий с графическим интерфейсом для конкретного случая GTK. Если вы создаете расширяемый язык программирования, такой как perl или python, вам потребуются возможности совместно используемой библиотеки для написания оптимизированных плагинов на скомпилированном языке.

  6. Используйте совместно используемую библиотеку, если вам абсолютно необходимо использовать библиотеку с лицензией, несовместимой со статическим построением. (AGPL, GPL, LGPL без предложения статической ссылки) ... и, конечно, если / когда у вас нет исходного кода.

  7. Используйте статические сборки, когда вы хотите более агрессивную оптимизацию. Многие хорошо подготовленные библиотеки, такие как libX11, были написаны, когда cdecl был основным соглашением о вызовах. Следовательно, многие функции X11 принимают загрузочный параметр в том же порядке, что и структура, которой манипулирует функция (а не просто указатель на структуру) ... что имеет смысл с соглашением о вызовах cdecl, поскольку теоретически вы можете просто переместить указатель стека и вызвать функцию. Однако это нарушается, как только вы используете некоторое количество регистров для передачи параметров. При статических сборках некоторые из этих непреднамеренных последствий могут быть смягчены с помощью встраивания и оптимизации времени соединения. Это только один пример. Есть много других оптимизаций, которые возникают при стирании границ функций.

  8. Безопасность памяти может идти в любом направлении. Со статическими двоичными файлами вы не подвержены атакам LD_PRELOAD (статический двоичный файл может иметь только 1 символ - точку входа), но совместно используемый (и статический круговой индикатор, если поддерживается) может иметь рандомизацию адресного пространства, которая доступна только для статических сборок на несколько архитектур, которые поддерживают независимые от позиции исполняемые файлы (хотя большинство распространенных архитектур действительно поддерживают PIE).

  9. Совместно используемые библиотеки могут (иногда) создавать меньшие двоичные файлы, поэтому, если вы используете совместно используемые библиотеки, которые в любом случае будут в системе, вы можете немного уменьшить размер пакета (и, следовательно, нагрузку на сервер). Однако, если вам все равно придется отправлять совместно используемые библиотеки, объединенный размер библиотек и двоичного файла всегда будет больше, чем статического двоичного файла, за исключением каких-то сумасшедших агрессивных вставок. Хорошим компромиссом является использование общих общих системных библиотек (например, libc, X11, zlib, png, glib и gtk / qt / other-default-toolkit) при использовании статических библиотек для необычных зависимостей или библиотек, специфичных для вашего пакета. Браузер Chrome делает это в некоторой степени. Хороший способ определить общее / статическое пороговое значение в целевом дистрибутиве Linux - выполнить итерации по * / bin и * / sbin при установке по умолчанию с помощью ldd или objdump -x и проанализировать выходные данные с помощью sort и uniq, чтобы определить правильное ограничение. Если вы распространяете несколько двоичных файлов, которые используют большинство одних и тех же библиотек, куча статических сборок увеличит раздувание, но вы можете рассмотреть возможность использования двоичного файла multicall (например, в busybox, toybox, mupdf или netpbm)

  10. Используйте статические сборки, если вы хотите избежать "ада DLL" или для перекрестной совместимости с дистрибутивами. Статический бинарный файл, созданный в одном дистрибутиве, должен работать на любом другом дистрибутиве, который достаточно актуален (в основном это версии ядра, чтобы не пытаться использовать неподдерживаемые системные вызовы).

Для получения дополнительной информации о преимуществах статического связывания см .: stali (сокращение от static linux)

О пропаганде совместно используемой библиотеки от бывшего сопровождающего glibc см. Ульриха Дреппера «Статическое связывание считается вредным» Хотя примерно половина проблем со статическим связыванием, о которых он упоминает, являются специфическими для glibc проблемами (диета, у musl и uclibc нет одинаковых проблем).

Если вы считаете, что статические библиотеки недостаточно далеко подходят для полной оптимизации, посмотрите список библиотек с одним файлом Шона Барретта. Их часто можно настроить так, чтобы все функции были статичными, чтобы двоичный файл можно было собрать как единый модуль компиляции. Это позволяет выполнить несколько оптимизаций, которых невозможно достичь с помощью оптимизации времени соединения, но вам лучше иметь IDE, поддерживающую свертывание кода.

0 голосов
/ 12 июня 2011

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

Например, в системе Solaris команды, которые могут вам понадобиться в случае, если некоторые разделы могут отсутствовать, хранятся в / sbin. sbin - это сокращение от статических двоичных файлов. Если раздел недоступен, эти приложения будут работать.

0 голосов
/ 12 июня 2011

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

0 голосов
/ 12 июня 2011

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

Но в качестве недостатка вы можете заметить некоторое увеличение размера двоичного файла.

Статические библиотеки в WIKI

...