При создании библиотеки классов в C++ вы можете выбирать между динамическими (.dll
, .so
) и статическими (.lib
, .a
) библиотеками. В чем разница между ними и когда уместно использовать какие?
Когда использовать динамические и статические библиотеки
Ответ 1
Статические библиотеки увеличивают размер кода в двоичном формате. Они всегда загружаются, и любая версия кода, скомпилированного вами, - это версия запускаемого кода.
Динамические библиотеки хранятся и версируются отдельно. Возможно, что загружена версия динамической библиотеки, которая не была оригинальной, поставляемой с вашим кодом , если, обновление считается бинарным, совместимым с исходной версией.
Кроме того, динамические библиотеки необязательно загружаются - они обычно загружаются при первом вызове и могут совместно использоваться среди компонентов, которые используют одну и ту же библиотеку (несколько загрузок данных, одна загрузка кода).
Динамические библиотеки чаще всего считались лучшим подходом, но изначально у них был большой недостаток (аддон google DLL), который полностью устранен более поздними операционными системами Windows (в частности, Windows XP).
Ответ 2
Другие адекватно объяснили, что такое статическая библиотека, но я хотел бы указать некоторые из предостережений об использовании статических библиотек, по крайней мере, в Windows:
-
Синглтоны: Если что-то должно быть глобальным/статическим и уникальным, будьте очень осторожны, ставя его в статическую библиотеку. Если несколько DLL связаны с этой статической библиотекой, каждый из них получит свою собственную копию синглтона. Однако, если ваше приложение представляет собой один EXE без пользовательских DLL, это может быть не проблема.
-
Удаление непринятого кода: При связывании со статической библиотекой только те части статической библиотеки, на которые ссылается ваша DLL/EXE, будут связаны с вашей DLL/EXE.
Например, если
mylib.lib
содержитa.obj
иb.obj
, а ваши DLL/EXE ссылаются только на функции или переменные изa.obj
, то целая частьb.obj
будет отбрасываться компоновщиком. Еслиb.obj
содержит глобальные/статические объекты, их конструкторы и деструкторы не будут выполнены. Если эти конструкторы/деструкторы имеют побочные эффекты, вы можете быть разочарованы их отсутствием.Аналогично, если статическая библиотека содержит специальные точки входа, вам может потребоваться, чтобы они были включены. Примером этого во встроенном программировании (хорошо, а не в Windows) был бы обработчик прерываний, помеченный как определенный адрес. Вы также должны пометить обработчик прерываний как точку входа, чтобы убедиться, что он не отбрасывается.
Другим следствием этого является то, что статическая библиотека может содержать объектные файлы, которые полностью непригодны из-за неразрешенных ссылок, но это не вызовет ошибки компоновщика, пока вы не свяжете функцию или переменную с этими объектными файлами. Это может произойти задолго после написания библиотеки.
-
Отладочные символы:. Вы можете захотеть отдельный PDB для каждой статической библиотеки, или вы можете захотеть, чтобы символы отладки помещались в объектные файлы, чтобы они попадали в PDB для DLL/EXE. Документация Visual С++ объясняет необходимые параметры.
-
RTTI: Вы можете получить несколько объектов
type_info
для одного и того же класса, если вы связываете одну статическую библиотеку с несколькими DLL. Если ваша программа предполагает, чтоtype_info
является "одиночным" данным и использует&typeid()
илиtype_info::before()
, вы можете получить нежелательные и неожиданные результаты.
Ответ 3
Lib - это единица кода, которая входит в исполняемый файл приложения.
dll - автономная единица исполняемого кода. Он загружается в процессе только тогда, когда в этот код делается вызов. DLL может использоваться несколькими приложениями и загружаться в несколько процессов, но при этом остается только одна копия кода на жестком диске.
Dll pros: может использоваться для повторного использования/совместного использования кода между несколькими продуктами; загружать в память процесса по требованию и могут быть выгружены, если они не нужны; могут быть обновлены независимо от остальной части программы.
Dll cons: влияние производительности загрузки dll и перезагрузки кода; проблемы с версией ( "dll hell" )
Lib pros: отсутствие влияния на производительность, поскольку код всегда загружается в процессе и не переустанавливается; нет проблем с версированием.
Lib cons: исполняемый/процесс "bloat" - весь код находится в вашем исполняемом файле и загружается при запуске процесса; нет повторного использования/совместного использования - каждый продукт имеет свою собственную копию кода.
Ответ 4
Помимо технических последствий статических vs динамических библиотек (статические файлы объединяют все в одну большую двоичную и динамическую библиотеки, которые позволяют совместное использование кода между несколькими различными исполняемыми файлами), есть юридические последствия.
Например, если вы используете лицензионный код LGPL и статически ставите против библиотеки LGPL (и тем самым создаете один большой двоичный файл), ваш код автоматически становится Open Sourced (бесплатно, как в свободе) Код LGPL. Если вы связываетесь с общими объектами, вам нужно только LGPL исправления исправления/исправления, которые вы делаете в самой библиотеке LGPL.
Это становится гораздо более важной проблемой, если вы решаете, как скомпилировать ваши мобильные приложения, например (в Android у вас есть выбор статического и динамического, в iOS у вас нет - он всегда статичен).
Ответ 5
Создание статической библиотеки
$$:~/static [32]> cat foo.c
#include<stdio.h>
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<stdio.h>
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<foo.h>
#include<foo2.h>
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<stdio.h>
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<stdio.h>
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<foo.h>
#include<foo2.h>
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]>
Ответ 6
Программы на С++ построены в две фазы
- Компиляция - создает код объекта (.obj)
- Связывание - создает исполняемый код (.exe или .dll)
Статическая библиотека (.lib) - это просто набор файлов .obj и, следовательно, не является полной программой. Он не прошел вторую (связующую) фазу построения программы. Dlls, с другой стороны, похожи на exe и поэтому являются полными программами.
Если вы создаете статическую библиотеку, она еще не связана, поэтому потребители вашей статической библиотеки должны будут использовать тот же самый компилятор, который вы использовали (если вы использовали g++, им нужно будет использовать g++).
Если вместо этого вы построили dll (и построили его правильно), вы создали полную программу, которую могут использовать все потребители, независимо от того, которые они используют. Однако существует несколько ограничений при экспорте из dll, если требуется совместимость кросс-компилятора.
Ответ 7
Вы должны тщательно подумать об изменениях с течением времени, о версии, стабильности, совместимости и т.д.
Если есть два приложения, которые используют общий код, вы хотите, чтобы эти приложения менялись вместе, если они должны быть совместимы друг с другом? Затем используйте dll. Все exe будут использовать один и тот же код.
Или вы хотите изолировать их друг от друга, чтобы вы могли изменить его и быть уверенным, что вы не сломали другого. Затем используйте статический lib.
DLL hell - это когда вы, вероятно, ДОЛЖНЫ использовать статическую библиотеку lib, но вместо этого вы использовали dll, и не все exes могут быть с ней совместимы.
Ответ 8
Статическая библиотека скомпилируется в клиенте. Во время компиляции используется .lib, а содержимое библиотеки становится частью исполняемого файла-потребителя.
Динамическая библиотека загружается во время выполнения и не компилируется в исполняемый файл клиента. Динамические библиотеки более гибкие, так как несколько исполняемых файлов клиента могут загружать DLL и использовать ее функциональные возможности. Это также минимизирует общий размер и удобство обслуживания вашего клиентского кода.
Ответ 9
Статическая библиотека должна быть связана с окончательным исполняемым файлом; он становится частью исполняемого файла и следует за ним, куда бы он ни пошел. Динамическая библиотека загружается каждый раз, когда исполняемый файл выполняется и остается отдельным от исполняемого файла в виде файла DLL.
Вы должны использовать DLL, если хотите изменить функциональность, предоставляемую библиотекой, без необходимости переустановки исполняемого файла (просто замените DLL файл, не заменяя исполняемый файл).
Вы использовали бы статическую библиотеку всякий раз, когда у вас нет причин использовать динамическую библиотеку.
Ответ 10
Документ Ульриха Дреппера " Как писать общие библиотеки" - также хороший ресурс, в котором подробно описывается, как лучше использовать общие библиотеки или что он называется "Динамические общие объекты" (DSO). Он больше фокусируется на общих библиотеках в двоичном формате
Ответ 11
Для отличного обсуждения этой темы читайте эту статью от Sun.
Он охватывает все преимущества, включая возможность вставки промежуточных библиотек. Более подробно о interposing можно найти в этой статье здесь.
Ответ 12
Действительно, компромисс, который вы делаете (в большом проекте), находится в начальной загрузке, библиотеки собираются получить связь в одно и то же время, решение, которое должно быть принято, - это соединение займет достаточно много времени, компилятор должен укусить пулю и сделать это спереди, или динамический компоновщик сделает это во время загрузки.
Ответ 13
Если ваша библиотека будет совместно использоваться несколькими исполняемыми файлами, часто имеет смысл сделать ее динамической, чтобы уменьшить размер исполняемых файлов. В противном случае определенно сделайте его статическим.
Существует несколько недостатков использования dll. Для погрузки и разгрузки есть дополнительные накладные расходы. Существует также дополнительная зависимость. Если вы измените dll, чтобы сделать его несовместимым с вашими исполнителями, они перестанут работать. С другой стороны, если вы измените статическую библиотеку, ваши скомпилированные исполняемые файлы, использующие старую версию, не будут затронуты.
Ответ 14
Если библиотека статична, то во время соединения код связан с вашим исполняемым файлом. Это делает ваш исполняемый файл более крупным (чем если бы вы пошли динамическим маршрутом).
Если библиотека является динамической, то в момент ссылки ссылки на необходимые методы встроены в ваш исполняемый файл. Это означает, что вам необходимо отправить исполняемый файл и динамическую библиотеку. Вы также должны учитывать, является ли общий доступ к коду в библиотеке безопасным, предпочтительным адресом загрузки среди других вещей.
Если вы можете жить со статической библиотекой, перейдите к статической библиотеке.
Ответ 15
Статические библиотеки представляют собой архивы, которые содержат объектный код для библиотеки, при подключении к приложению, который компилируется в исполняемый файл. Общие библиотеки отличаются тем, что они не скомпилированы в исполняемый файл. Вместо этого динамический компоновщик ищет в некоторых каталогах нужные библиотеки, а затем загружает их в память. Одновременно один исполняемый файл может использовать одну и ту же разделяемую библиотеку, тем самым уменьшая объем использования памяти и размер исполняемого файла. Тем не менее, есть еще больше файлов для распространения с исполняемым файлом. Вы должны убедиться, что библиотека установлена на систему использования где-нибудь, где компоновщик может ее найти, статическая привязка устраняет эту проблему, но приводит к большему исполняемому файлу.
Ответ 16
Если вы работаете со встроенными проектами или специализированными платформами, то статические библиотеки - это единственный способ пойти, а также много раз меньше проблем с компиляцией в ваше приложение. Также наличие проектов и make файлов, которые включают в себя все, делает жизнь более счастливой.
Ответ 17
В нашем проекте мы используем много DLL ( > 100). У этих DLL есть зависимости друг от друга, поэтому мы выбрали настройку динамической компоновки. Однако он имеет следующие недостатки:
- медленный запуск ( > 10 секунд)
- DLL должна была быть версией, так как окна загружают модули по уникальности имен. Собственные письменные компоненты в противном случае получили бы неправильную версию DLL (т.е. Уже загруженную вместо своего собственного распределенного набора) Оптимизатор
- может оптимизировать только в пределах DLL. Например, оптимизатор пытается разместить часто используемые данные и код рядом друг с другом, но это не будет работать через границы DLL.
Возможно, лучшей настройкой было сделать все статическую библиотеку (и, следовательно, у вас только один исполняемый файл). Это работает только в том случае, если не происходит дублирования кода. Тест, похоже, поддерживает это предположение, но я не смог найти официальную цитату из MSDN. Так, например, сделайте 1 exe с:
- exe использует shared_lib1, shared_lib2
- shared_lib1 использовать shared_lib2
- shared_lib2
Код и переменные shared_lib2 должны присутствовать в окончательном объединенном исполняемом файле только один раз. Может ли кто-нибудь поддержать этот вопрос?
Ответ 18
Я бы дал общее правило: если у вас есть большая база кода, все они построены на основе библиотек более низкого уровня (например, Utils или Gui framework), которые вы хотите разбить на более управляемые библиотеки, затем сделайте их статичными библиотеки. Динамические библиотеки на самом деле ничего не покупают, и меньше сюрпризов - например, один экземпляр синглтонов.
Если у вас есть библиотека, которая полностью разделена на остальную часть базы кода (например, стороннюю библиотеку), тогда рассмотрите возможность создания dll. Если библиотека LGPL, вам может потребоваться использовать dll в любом случае из-за условий лицензирования.