Разница между общими объектами (.so), статическими библиотеками (.a) и DLL (.so)? - PullRequest
240 голосов
/ 13 марта 2012

Я участвовал в некоторых дебатах по поводу библиотек в 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. Shared Archive: по сути то же самое, что и статическая библиотека, но компилируется с флагами "export-shared" и "-fPIC".Библиотека включается в список ссылок во время компиляции (то есть: LDOPTS + = - lmylib S для файла библиотеки с именем mylib S .a).Различие между ними заключается в том, что этот дополнительный флаг необходим, если общий объект или DLL хотят статически связать общий архив с собственным кодом и иметь возможность сделать функции в общем объекте доступными для других программ, а не просто использовать их.внутренний в DLL.Это полезно в том случае, когда кто-то предоставляет вам статическую библиотеку, и вы хотите переупаковать ее в виде SO. Библиотека должна присутствовать во время компиляции.

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

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

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

Ответы [ 4 ]

170 голосов
/ 13 марта 2012

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

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

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

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

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

84 голосов
/ 13 марта 2012

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

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

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

29 голосов
/ 19 апреля 2014

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

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

Windows DLL имеют таблицу экспорта. Экспорт может быть по имени или по позиции таблицы (числовой). Последний метод считается «старой школой» и является гораздо более хрупким - перестройка 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.

4 голосов
/ 13 марта 2012

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

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

...