Когда использовать динамические и статические библиотеки

При создании библиотеки classов на C ++ вы можете выбирать между динамическими (.dll) и статическими (.lib) библиотеками. В чем разница между ними и когда целесообразно использовать их?

18 Solutions collect form web for “Когда использовать динамические и статические библиотеки”

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

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

Кроме того, динамические библиотеки не обязательно загружаются – они обычно загружаются при первом вызове и могут совместно использоваться среди компонентов, которые используют одну и ту же библиотеку (несколько загрузок данных, одна загрузка кода).

Динамические библиотеки чаще всего считались лучшим подходом, но изначально у них был главный недостаток (google DLL hell), который был полностью устранен более поздними операционными системами Windows (в частности, Windows XP).

Другие адекватно объяснили, что такое статическая библиотека, но я хотел бы указать на некоторые из предостережений об использовании статических библиотек, по крайней мере, в Windows:

  • Синглтоны: если что-то должно быть глобальным / статическим и уникальным, будьте очень осторожны, ставя его в статическую библиотеку. Если несколько DLL связаны с этой статической библиотекой, каждый из них получит свою собственную копию синглтона. Однако, если ваше приложение представляет собой один EXE без пользовательских DLL, это может быть не проблема.

  • Удаление Unreferenced кода: при связывании со статической библиотекой, только части статической библиотеки, на которые ссылается ваша DLL / EXE, будут связаны с вашей DLL / EXE.

    Например, если mylib.lib содержит a.obj и b.obj а ваши DLL / EXE ссылаются только на функции или переменные из a.obj , вся b.obj будет отброшена компоновщиком. Если b.obj содержит глобальные / статические объекты, их конструкторы и деструкторы не будут выполнены. Если эти конструкторы / деструкторы имеют побочные эффекты, вы можете быть разочарованы их отсутствием.

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

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

  • Символы отладки: вам может понадобиться отдельный PDB для каждой статической библиотеки, или вы можете захотеть, чтобы символы отладки помещались в объектные файлы, чтобы они попадали в PDB для библиотеки DLL / EXE. Документация Visual C ++ объясняет необходимые параметры .

  • RTTI: у вас может быть несколько объектов type_info для одного и того же classа, если вы связываете одну статическую библиотеку с несколькими DLL. Если ваша программа предполагает, что type_info является «singleton» данными и использует &typeid() или type_info::before() , вы можете получить нежелательные и неожиданные результаты.

Библиотека представляет собой единицу кода, входящую в исполняемый файл приложения.

Dll – автономная единица исполняемого кода. Он загружается в процессе только тогда, когда в этот код делается вызов. DLL может использоваться несколькими приложениями и загружаться в несколько процессов, но при этом остается только одна копия кода на жестком диске.

Dll pros : может использоваться для повторного использования / совместного использования кода между несколькими продуктами; загружать в память процесса по требованию и могут быть выгружены, если они не нужны; могут быть обновлены независимо от остальной части программы.

Dll минус : влияние загрузки dll и перекоса кода; проблемы с версией (“dll hell”)

Lib pros : отсутствие влияния на производительность, поскольку код всегда загружается в процессе и не переустанавливается; нет проблем с версированием.

Lib cons : исполняемый / процесс «bloat» – весь код находится в вашем исполняемом файле и загружается при запуске процесса; нет повторного использования / совместного использования – каждый продукт имеет свою собственную копию кода.

Помимо технических последствий статических vs динамических библиотек (статические файлы объединяют все в одну большую двоичную и динамическую библиотеки, которые позволяют совместное использование кода между несколькими различными исполняемыми файлами), есть юридические последствия .

Например, если вы используете лицензионный код LGPL и статически связываетесь с библиотекой LGPL (и таким образом создаете один большой двоичный файл), ваш код автоматически становится кодом Open Sourced ( бесплатно, как в свободе) LGPL. Если вы связываетесь с общими объектами, вам нужно только LGPL исправления исправления / исправления, которые вы делаете в самой библиотеке LGPL.

Это становится гораздо более важной проблемой, если вы решаете, как скомпилировать ваши мобильные приложения, например (в Android у вас есть выбор статического и динамического, в iOS вы этого не делаете – он всегда статичен).


Создание статической библиотеки

 $$:~/static [32]> cat foo.c #include void foo() { printf("\nhello world\n"); } $$:~/static [33]> cat foo.h #ifndef _H_FOO_H #define _H_FOO_H void foo(); #endif $$:~/static [34]> cat foo2.c #include void foo2() { printf("\nworld\n"); } $$:~/static [35]> cat foo2.h #ifndef _H_FOO2_H #define _H_FOO2_H void foo2(); #endif $$:~/static [36]> cat hello.c #include #include void main() { foo(); foo2(); } $$:~/static [37]> cat makefile hello: hello.o libtest.a cc -o hello hello.o -L. -ltest hello.o: hello.c cc -c hello.c -I`pwd` libtest.a:foo.o foo2.o ar cr libtest.a foo.o foo2.o foo.o:foo.c cc -c foo.c foo2.o:foo.c cc -c foo2.c clean: rm -f foo.o foo2.o libtest.a hello.o $$:~/static [38]> 

создание динамической библиотеки

 $$:~/dynamic [44]> cat foo.c #include void foo() { printf("\nhello world\n"); } $$:~/dynamic [45]> cat foo.h #ifndef _H_FOO_H #define _H_FOO_H void foo(); #endif $$:~/dynamic [46]> cat foo2.c #include void foo2() { printf("\nworld\n"); } $$:~/dynamic [47]> cat foo2.h #ifndef _H_FOO2_H #define _H_FOO2_H void foo2(); #endif $$:~/dynamic [48]> cat hello.c #include #include void main() { foo(); foo2(); } $$:~/dynamic [49]> cat makefile hello:hello.o libtest.sl cc -o hello hello.o -L`pwd` -ltest hello.o: cc -c -b hello.c -I`pwd` libtest.sl:foo.o foo2.o cc -G -b -o libtest.sl foo.o foo2.o foo.o:foo.c cc -c -b foo.c foo2.o:foo.c cc -c -b foo2.c clean: rm -f libtest.sl foo.o foo 2.o hello.o $$:~/dynamic [50]> 

Вы должны тщательно подумать об изменениях с течением времени, управлении версиями, стабильности, совместимости и т. Д.

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

Или вы хотите изолировать их друг от друга, чтобы вы могли изменить его и быть уверенным, что вы не сломали другого. Затем используйте статический lib.

DLL ад, когда вы, вероятно, ДОЛЖНЫ использовать статическую библиотеку lib, но вместо этого вы использовали dll, и не все exes могут быть с ним совместимы.

Программы на C ++ построены в два этапа

  1. Компиляция – создает объектный код (.obj)
  2. Связывание – создает исполняемый код (.exe или .dll)

Статическая библиотека (.lib) – это просто набор файлов .obj и, следовательно, не является полной программой. Он не прошел вторую (связующую) фазу построения программы. Dlls, с другой стороны, похожи на exe и поэтому являются полными программами.

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

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

Статическая библиотека скомпилируется в клиент. Во время компиляции используется .lib, а содержимое библиотеки становится частью исполняемого файла потребления.

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

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

Вы должны использовать DLL, если хотите изменить функциональность, предоставляемую библиотекой, без необходимости переустановки исполняемого файла (просто замените DLL-файл, не заменяя исполняемый файл).

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

Документ Ульриха Дреппера « Как писать общие библиотеки » также является хорошим ресурсом, в котором подробно описывается, как лучше использовать общие библиотеки или то, что он называет «динамическими общими объектами» (DSO). Он больше посвящен общим библиотекам в двоичном формате ELF , но некоторые обсуждения подходят также и для DLL-файлов Windows.

Для отличного обсуждения этой темы читайте эту статью от Sun.

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

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

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

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

Если библиотека статична, то во время соединения код связан с вашим исполняемым файлом. Это делает ваш исполняемый файл более крупным (чем если бы вы пошли динамическим маршрутом).

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

Если вы можете жить со статической библиотекой, перейдите к статической библиотеке.

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

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

Мы используем много DLL (> 100) в нашем проекте. У этих DLL есть зависимости друг от друга, поэтому мы выбрали настройку динамической компоновки. Однако он имеет следующие недостатки:

  • медленный запуск (> 10 секунд)
  • DLL должен был быть версией, так как windows загружают модули по уникальности имен. Собственные письменные компоненты в противном случае получили бы неправильную версию DLL (т. Е. Уже загруженную, а не ее собственный распределенный набор)
  • оптимизатор может оптимизировать только в пределах DLL. Например, оптимизатор пытается разместить часто используемые данные и код рядом друг с другом, но это не будет работать через границы DLL

Возможно, лучшей настройкой было сделать все статическую библиотеку (и, следовательно, у вас только один исполняемый файл). Это работает только в том случае, если не происходит дублирования кода. Тест, похоже, поддерживает это предположение, но я не смог найти официальную цитату из MSDN. Так, например, выполните 1 exe с:

  • exe использует shared_lib1, shared_lib2
  • shared_lib1 использовать shared_lib2
  • shared_lib2

Код и переменные shared_lib2 должны присутствовать в окончательном объединенном исполняемом файле только один раз. Может ли кто-нибудь поддержать этот вопрос?

Я бы дал общее правило: если у вас большая база кода, все они построены на основе библиотек более низкого уровня (например, Utils или Gui framework), которые вы хотите разбить на более управляемые библиотеки, а затем создать их статические библиотеки. Динамические библиотеки на самом деле ничего не покупают, и меньше сюрпризов – например, один экземпляр синглтонов.

Если у вас есть библиотека, которая полностью отделена от остальной части кодовой базы (например, сторонняя библиотека), тогда подумайте о том, чтобы сделать ее dll. Если в библиотеке есть LGPL, вам может потребоваться использовать dll в любом случае из-за условий лицензирования.

Interesting Posts

Windows 7 не распознает аудиовыход HDMI

Есть ли причина использовать библиотеку support.v4 в Android?

Обеспечение того, чтобы новые файлы в каталоге принадлежали группе

Когда использовать Xamarin.Forms vs Xamarin Native?

ASP MVC в IIS 7 приводит к: Ошибка HTTP 403.14 – Запрещено

Как добавить новые элементы в массив?

Как передать аргументы консоли в приложение в eclipse?

Будет ли рендеринг iframe в режиме quirks?

Почему возникает segmentation fault при записи в строку, инициализированную символом «char * s», но не «char s »?

Полноэкранный режим в Android?

Поддержка Multi Monitor для Windows 7

Настройка параметров прокси-сервера для автоматического обнаружения прокси-сервера с помощью командной строки на Mac OSX

Как пропустить простой объект JavaScript с объектами в качестве членов?

Строковый график в GnuPlot, где цвет линии является третьим столбцом в моем файле данных?

Есть ли способ настроить функцию оснастки Windows 7?

Давайте будем гением компьютера.