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

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


person Morten Christiansen    schedule 26.09.2008    source источник
comment
Следует отметить, что есть еще кое-что, что называется Проверка библиотеки импорта stackoverflow.com/questions/3573475/   -  person Wakan Tanka    schedule 09.09.2016


Ответы (18)


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

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

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

В большинстве случаев динамические библиотеки считались лучшим подходом, но изначально у них был серьезный недостаток (ад Google DLL), который был почти устранен более поздними ОС Windows (в частности, Windows XP).

person Orion Adrian    schedule 26.09.2008
comment
В Windows / Mac (без диспетчера пакетов) действительно нет веских причин использовать динамические библиотеки вместо статических. Поскольку библиотеки DLL Windows не могут быть перемещены, совместное использование кода часто не работает (и обычно каждое приложение в любом случае поставляется и использует свои собственные версии библиотеки). Единственное реальное преимущество состоит в том, что библиотеку легче обновлять. - person Zifre; 12.05.2009
comment
Что конкретно вы имеете в виду под «перемещаемым»? - person Orion Adrian; 12.05.2009
comment
на Mac я использую много динамических библиотек. например, в mac os x есть встраивание sqlite3. Я создал программу с функцией базы данных sqlite3 для сохранения производительности. однако, поскольку оно редко используется, динамическое связывание экономит время компиляции, упрощает / ускоряет тестирование, однако, если бы я создавал релизную версию, я думаю, что всегда использовал бы статическую библиотеку только в случае проблем с совместимостью - person ReachConnection; 16.10.2009
comment
@Zifre: relocatable = может быть загружен по другому виртуальному адресу. DLL, безусловно, поддерживает это. - person dma_k; 02.10.2010
comment
@dma_k: библиотеки DLL Windows могут быть загружены по разным адресам, но только потому, что компоновщик копирует весь код и изменяет номера адресов. В случае общих объектов все адресные ссылки являются относительными, поэтому несколько процессов могут совместно использовать одну и ту же память для общего объекта. Другими словами, в Windows 1 МБ DLL, используемая 3 программами, = 3 МБ. В Linux размер SO, используемый 3 программами, равен 1 МБ. - person Zifre; 17.10.2010
comment
И в Windows, и в Linux есть концепция перемещения разделяемых библиотек по времени eli.thegreenplace.net/2011/08/25/ Самое главное, что позволяло позиционно-независимый код, не было чем-то особенным для Linux, а скорее относительной адресацией RIP, добавленной с набором инструкций x64; как Windows, так и Linux могут использовать относительную адресацию RIP, уменьшая количество исправлений при перемещении библиотек. - person clemahieu; 03.08.2013
comment
Статические библиотеки хуже взаимодействуют и их труднее использовать, например, в средах .NET. - person Colin; 16.10.2015
comment
Стоит упомянуть, что иногда из-за лицензионных ограничений вам необходимо динамически связывать свои приложения с библиотеками, если вы хотите, чтобы ваша база кода была закрытой, например, Qt с LGPL. - person Jämes; 04.05.2017
comment
Будет ли разница в производительности между StaticLib и SharedLib после полной загрузки кода в процессе? - person baye; 21.12.2020

Другие адекватно объяснили, что такое статическая библиотека, но я хотел бы указать на некоторые предостережения при использовании статических библиотек, по крайней мере, в 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 C ++ объясняет необходимые параметры.

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

person bk1e    schedule 26.09.2008
comment
Что касается синглтонов, не забывайте, что DLL может загружаться несколько раз (одна и та же версия или несколько версий), и до сих пор нет гарантии синглтона. - person Orion Adrian; 19.03.2010
comment
Дополнительный момент об удалении кода, на который нет ссылки: для вызовов DLL также требуется фактический вызов, чтобы принудительно загрузить указанную DLL. Если добавить его в качестве ссылки, но затем исключить какой-либо вызов, который ссылается на него, вы все равно получите тот же результат, что и статическая библиотека, которая ничего не вызывает. Единственная разница в том, что на самом деле отправляется. В обоих случаях статические конструкторы и деструкторы не срабатывают. - person Orion Adrian; 10.11.2010
comment
@ bk1e Этого не должно быть. .a всегда будет содержать все символы, с которыми он был построен. Когда он статически связан с вашим приложением, да, будут связаны только те символы, которые используются. - person Miles Rout; 29.08.2013

Библиотека - это единица кода, связанная с исполняемым файлом вашего приложения.

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

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

Минусы dll: влияние загрузки dll и изменения кода на производительность; проблемы с версией ("ад dll")

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

Минусы библиотеки: "раздувание" исполняемого файла / процесса - весь код находится в вашем исполняемом файле и загружается при запуске процесса; нет повторного использования / обмена - у каждого продукта есть собственная копия кода.

person Franci Penov    schedule 26.09.2008
comment
Перебазирование также можно выполнить во время сборки с помощью rebase.exe или путем передачи параметра / BASE в link.exe. Эффективность этого метода зависит от того, возникнут ли какие-либо неожиданные конфликты адресного пространства во время выполнения. - person bk1e; 26.09.2008

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

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

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

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

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

person tcb    schedule 08.08.2014
comment
Это для меня новость. Какие ограничения есть у кросс-компиляторов при использовании DLL? Сборка программиста без использования той же инструментальной цепочки кажется огромным плюсом для DLL. - person Dan; 18.04.2018
comment
Это информативный ответ. Добавление небольшого предупреждения: consumers of your static library will have to use the same compiler that you used, если статическая библиотека использует библиотеку C ++, например #include <iostream>. - person eigenfield; 29.03.2020
comment
нельзя использовать c ++ dll, если не используется тот же компилятор (поскольку нет стандартного c ++ abi, символы искажаются по-разному). И dll, и клиентский модуль должны использовать один и тот же компилятор и одинаковые настройки сборки. - person kcris; 24.05.2020

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

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

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

person rburhum    schedule 16.10.2009


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

$$:~/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]>
person Vijay    schedule 14.12.2009

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

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

person Jordan Parmer    schedule 26.09.2008

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

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

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

DLL, черт возьми, это когда вам, вероятно, СЛЕДУЕТ использовать статическую библиотеку, но вместо нее вы использовали dll, и не все exes совместимы с ней.

person Corey Trager    schedule 26.09.2008

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

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

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

person spotcatbug    schedule 26.09.2008
comment
Вы также можете использовать DLL, когда несколько других приложений используют ту же функциональность - это может уменьшить занимаемую площадь. - person Tim; 27.04.2010
comment
Кроме того, расширение вашей первоначальной концепции, архитектуры подключаемых модулей, в которой вы хотите разрешить добавленные / неизвестные функции позже, без необходимости перестраивать или перевыпускать, может быть выполнено только с помощью динамических библиотек. - person Tim; 27.04.2010

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

person Void    schedule 11.05.2009

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

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

person Rob Wells    schedule 26.09.2008

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

person pfranza    schedule 26.09.2008

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

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

person Dima    schedule 26.09.2008

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

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

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

person Seb Rose    schedule 26.09.2008

В нашем проекте мы используем много 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 должны присутствовать в окончательном объединенном исполняемом файле только один раз. Кто-нибудь может поддержать этот вопрос?

person gast128    schedule 02.10.2013
comment
Разве вы не собирались каким-то образом использовать некоторые предварительные директивы компилятора, чтобы избежать дублирования кода? - person Paceman; 24.11.2013
comment
Предварительная компиляция Afaiac работает только для отдельных модулей (exe / dll / lib). Предварительная компиляция в первую очередь предназначена для ускорения компиляции, хотя она также предотвращает множественные включения в единицу компиляции. Однако включить охранников - лучший способ добиться этого эффекта. - person gast128; 26.06.2015

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

person Terence Simpson    schedule 26.09.2008

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

person Robert Gould    schedule 26.09.2008

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

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

person the_mandrill    schedule 02.10.2013