it-swarm.com.ru

Разница между общими объектами (.so), статическими библиотеками (.a) и DLL (.so)?

Я участвовал в некоторых дебатах по поводу библиотек в Linux и хотел бы подтвердить некоторые вещи.

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

  1. Статические библиотеки (файлы .a): во время компоновки копия всей библиотеки помещается в конечное приложение, чтобы функции внутри библиотеки всегда были доступны вызывающему приложению
  2. Общие объекты (файлы .so). Во время соединения объект просто проверяется на соответствие его API через соответствующий файл заголовка (.h). Библиотека фактически не используется до времени выполнения, где это необходимо.

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

Я слышал, что некоторые люди делают различие между общими объектами и динамически связанными библиотеками (DLL), хотя они оба являются файлами ".so". Есть ли какое-либо различие между общими объектами и библиотеками DLL, когда речь заходит о разработке C/C++ для Linux или любой другой POSIX-совместимой ОС (например, MINIX, UNIX, QNX и т.д.)? Мне говорят, что одно ключевое отличие (пока) заключается в том, что общие объекты просто используются во время выполнения, в то время как библиотеки DLL сначала должны открываться с помощью вызова dlopen () в приложении.

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

Спасибо всем заранее за вашу помощь.

Обновление


В контексте, в котором эти термины были предоставлены мне, это были фактически ошибочные термины, используемые командой разработчиков Windows, которые должны были изучать Linux. Я пытался их исправить, но (неправильные) языковые нормы застряли.

  1. Общий объект: библиотека, которая автоматически связывается с программой при запуске и существует в виде отдельного файла. Библиотека включается в список ссылок во время компиляции (то есть: LDOPTS+=-lmylib для файла библиотеки с именем mylib.so). Библиотека должна присутствовать во время компиляции и при запуске приложения.
  2. Статическая библиотека: библиотека, которая объединяется с самой программой во время сборки для одного (большего) приложения, содержащего код приложения и код библиотеки, который автоматически связывается с программой при сборке программы, и конечный двоичный файл, содержащий оба основная программа и сама библиотека существуют в виде отдельного двоичного файла. Библиотека включается в список ссылок во время компиляции (то есть: LDOPTS+=-lmylib для файла библиотеки с именем mylib.a). Библиотека должна присутствовать во время компиляции.
  3. DLL: по сути то же самое, что и общий объект, но вместо того, чтобы быть включенным в список ссылок во время компиляции, библиотека загружается с помощью команд dlopen()/dlsym(), так что библиотека не должна присутствовать во время сборки для компиляции программы , Кроме того, библиотека не обязательно должна присутствовать (обязательно) при запуске приложения или во время компиляции, поскольку она необходима только в момент, когда выполняются вызовы dlopen/dlsym.
  4. Общий архив: по сути, такой же, как статическая библиотека, но компилируется с флагами "export-shared" и "-fPIC". Библиотека включается в список ссылок во время компиляции (то есть: LDOPTS + = - lmylibS для файла библиотеки с именем mylibS. A). Различие между ними заключается в том, что этот дополнительный флаг необходим, если совместно используемый объект или DLL хочет статически связать общий архив в свой собственный код И иметь возможность сделать функции в общем объекте доступными для других программ. вместо того, чтобы просто использовать их внутри DLL. Это полезно в том случае, когда кто-то предоставляет вам статическую библиотеку, и вы хотите переупаковать ее в виде SO. Библиотека должна присутствовать во время компиляции.

Дополнительное обновление

Различие между "DLL" и "shared library" было просто (ленивым, неточным) коллоквиализмом в компании, в которой я работал в то время (разработчики Windows были вынуждены перейти на разработку Linux, и термин застрял), придерживаясь описанных замечаний выше.

Кроме того, конечный литерал "S" после имени библиотеки в случае "общих архивов" был просто соглашением, используемым в этой компании, а не в отрасли в целом.

237
DevNull

Я всегда думал, что библиотеки DLL и общие объекты - это просто разные термины для одного и того же - Windows называет их библиотеками DLL, в то время как в системах UNIX они являются общими объектами с общим термином - динамически связанной библиотекой - охватывающим оба понятия (даже функцию открыть .so в UNIX называется dlopen() после "динамической библиотеки").

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

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

83
Matthew Walton

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

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

библиотека динамической компоновки в windows (.dll) похожа на общую библиотеку (.so) в linux, но между двумя реализациями, которые связаны с ОС (Windows vs Linux), есть некоторые различия:

A DLL может определять два вида функций: экспортируемые и внутренние. Экспортируемые функции предназначены для вызова другими модулями, а также из DLL, где они определены. Внутренние функции обычно предназначены для вызова только из DLL, где они определены.

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

168
aleroot

Я могу подробнее рассказать о библиотеках DLL в Windows, чтобы помочь разъяснить эти загадки моим друзьям здесь, в * NIX-стране ...

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

Windows DLL имеют таблицу экспорта. Экспорт может быть по имени или по позиции таблицы (числовой). Последний метод считается "старой школой" и является гораздо более хрупким - перестройка DLL и ​​изменение положения функции в таблице приведут к катастрофе, тогда как при связывании записи нет реальной проблемы Очки по имени. Так что забудьте об этом как о проблеме, но имейте в виду, что она есть, если вы работаете с кодом "динозавров", таким как сторонние библиотеки.

Библиотеки Windows создаются путем компиляции и компоновки, как если бы вы работали с EXE (исполняемым приложением), но DLL предназначено не как отдельный, как SO предназначено для использоваться приложением либо через динамическую загрузку, либо с помощью привязки по времени соединения (ссылка на SO встроена в метаданные двоичного файла приложения, и загрузчик программы ОС автоматически загрузит ссылочные SO) , DLL могут ссылаться на другие DLL так же, как SO могут ссылаться на другие SO.

В Windows библиотеки DLL сделают доступными только определенные точки входа. Это называется "экспорт". Разработчик может либо использовать специальное ключевое слово компилятора, чтобы сделать символ видимым извне (для других компоновщиков и динамического загрузчика), либо экспорт может быть указан в файле определения модуля, который используется во время компоновки, когда DLL сама создается. Современная практика заключается в украшении определения функции ключевым словом для экспорта имени символа. Также возможно создать заголовочные файлы с ключевыми словами, которые будут объявлять этот символ как импортируемый из DLL вне текущего модуля компиляции. Найдите ключевые слова __declspec (dllexport) и __declspec (dllimport) для получения дополнительной информации.

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

Когда разработчик хочет использовать уже созданную DLL, он должен либо ссылаться на "экспортную библиотеку" (* .LIB), созданную разработчиком DLL, когда она создала DLL, либо он должен явно загрузить DLL во время выполнения и запросите адрес точки входа по имени с помощью механизмов LoadLibrary () и GetProcAddress (). В большинстве случаев связывание с файлом LIB (который просто содержит метаданные компоновщика для экспортированных точек входа DLL) - это способ использования библиотек DLL. Динамическая загрузка обычно зарезервирована для реализации "полиморфизма" или "конфигурируемости во время выполнения" в поведении программы (доступ к надстройкам или определенным позднее функциям, также называемым "плагинами").

Порядок действий в Windows иногда может вызвать некоторую путаницу; система использует расширение .LIB для ссылки как на обычные статические библиотеки (архивы, такие как файлы POSIX * .a), так и на библиотеки "экспортной заглушки", необходимые для привязки приложения к DLL во время соединения. Таким образом, следует всегда проверять, имеет ли файл * .LIB файл с таким же именем * .DLL; в противном случае велика вероятность, что файл * .LIB является статическим архивом библиотеки, а не экспортирует метаданные привязки для DLL.

29
JoGusto

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

Вызов dlopen предназначен не только для общих объектов, если приложение желает сделать это во время выполнения от своего имени, в противном случае общие объекты загружаются автоматически при запуске приложения. DLLS и .so - это одно и то же. dlopen существует, чтобы добавить еще более тонкие возможности динамической загрузки для процессов. Вам не нужно использовать dlopen для открытия/использования библиотек DLL, что также происходит при запуске приложения.

4
rapadura