Різниця між спільними об'єктами (.so), статичними бібліотеками (.a) та DLL (.so)?


272

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

Наскільки я розумію (будь ласка, виправте мене, якщо я помиляюся, і я відредагую свою публікацію пізніше), є два способи використання бібліотек під час створення програми:

  1. Статичні бібліотеки (файли .a): під час посилання копія всієї бібліотеки вводиться в остаточну програму, щоб функції в бібліотеці завжди були доступні для виклику програми
  2. Спільні об'єкти (.so файли): під час посилання об’єкт просто перевіряється щодо його API через відповідний заголовок (.h) файл. Бібліотека насправді не використовується до часу виконання, де це потрібно.

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

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

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

Заздалегідь дякую всім за допомогу.

Оновлення


У контексті, в якому ці терміни були мені надані, фактично помилкові терміни використовували команда розробників Windows, яка мала вивчити Linux. Я намагався їх виправити, але (неправильні) мовні норми застрягли.

  1. Shared Object: Бібліотека, яка автоматично приєднується до програми при запуску програми і існує як окремий файл. Бібліотека включається до списку посилань під час компіляції (тобто LDOPTS+=-lmylibдля файлу бібліотеки з назвою mylib.so). Бібліотека повинна бути присутнім під час компіляції та при запуску програми.
  2. Статична бібліотека: бібліотека, яка об'єднується у фактичну програму сама під час збирання для однієї (більшої) програми, що містить код програми та код бібліотеки, який автоматично приєднується до програми під час створення програми, і кінцевий бінарний файл, що містить обидва основна програма і сама бібліотека існує як єдиний окремий бінарний файл. Бібліотека включається до списку посилань під час компіляції (тобто LDOPTS+=-lmylibдля файлу бібліотеки з назвою mylib.a). Бібліотека повинна бути присутнім під час компіляції.
  3. DLL: По суті такий же, як спільний об'єкт, але замість того, щоб бути включеним у список зв’язків під час компіляції, бібліотека завантажується через dlopen()/ dlsym()команди, так що бібліотеці не потрібно бути присутнім під час збирання програми для компіляції. Крім того, бібліотеці не потрібно бути присутнім (обов'язково) при запуску програми або компіляції програми , оскільки це потрібно лише в момент здійснення dlopen/ dlsymвикликів.
  4. Спільний архів: По суті такий же, як і статична бібліотека, але складається з прапорами "експорт-спільний" та "-fPIC". Бібліотека включається до списку посилань під час компіляції (тобто LDOPTS+=-lmylibSдля файлу бібліотеки з назвою mylibS.a). Відмінність між ними полягає в тому, що цей додатковий прапор необхідний, якщо спільний об'єкт або DLL хочуть статично пов’язати спільний архів у власному коді ТА мати можливість зробити функції спільного об'єкта доступними для інших програм, а не просто використовувати їх внутрішній для DLL. Це корисно в тому випадку, коли хтось надає вам статичну бібліотеку, і ви хочете перепакувати її як SO. Бібліотека повинна бути присутнім під час компіляції.

Додаткове оновлення

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

До того ж, " S" буквальне значення після назви бібліотеки, що стосується "спільних архівів", було лише умовою, що використовується в цій компанії, а не в галузі взагалі.


14
Для .aфайлів "a" насправді означає "archove", і це просто архів файлів об'єктів. Сучасні посилання мають бути досить хорошими, щоб не потрібно включати бібліотеку в той час, як потрібні файли об'єктів в архіві, який потрібен, і навіть можуть просто використовувати розділи коду / даних у файлах об'єктів, на які посилаються.
Якийсь програміст чувак

4
DLL - це просто термінологія Windows. Він не використовується на уніці.
R .. GitHub СТОП ДОПОМОГАЙТЕ



2
@DevNull "арка я " звичайно. :)
Якийсь програміст чувак

Відповіді:


93

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

Вони дійсно пов'язані лише при запуску програми, однак ваше поняття підтвердження щодо файлу заголовка є неправильним. Файл заголовка визначає прототипи, необхідні для складання коду, який використовує бібліотека, але під час посилання лінкер заглядає всередину самої бібліотеки, щоб переконатися, що потрібні їй функції є насправді. Лінкер повинен знайти тіло функцій десь під час посилання, інакше це призведе до помилки. Це також робиться під час виконання, оскільки, як ви правильно зазначаєте, сама бібліотека могла змінитися з часу складання програми. Ось чому стабільність ABI настільки важлива в бібліотеках платформ, оскільки зміна ABI - це те, що розбиває існуючі програми, складені на старих версіях.

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


1
Чому так, що деякі проекти, які я бачу в Linux, повинні використовувати виклик dlopen () для доступу до функцій у файлі ".so", а деякі взагалі не повинні це робити? Дякую, до речі!
Хмара

9
Ті, хто цього не робить, отримують функції, які їм передає завантажувач процесів, тобто завантажувач ельфів Linux. dlopen існує, якщо програма хоче відкрити і використовувати .so або .dll, що не був там при компіляції, або просто додати додаткову функціональність, наприклад плагіни.
rapadura

Але чи не програму взагалі не складатимуть, якщо .so не присутній під час збирання? Чи можливо змусити лінкер просто скласти остаточну програму без .soto взагалі присутній? Дякую.
Хмара

1
Я вважаю, це залежить від того, як ви використовуєте функції від .so, але тут мої знання про це зупиняються: / Хороші запитання.
rapadura

1
Що стосується dlopen () та його сімейства функцій, я розумію, що це використовується для програмного відкриття / закриття dll, щоб його не потрібно було завантажувати в пам'ять протягом усього запуску програми. В іншому випадку, ви повинні сказати лінкеру в аргументах його командного рядка (він же ваш makefile), що ви хочете завантажувати бібліотеку. Він буде завантажений під час виконання і залишатиметься завантаженим у пам'яті, поки програма не вийде. Існує більше речей, які можуть статися на рівні ОС, але це приблизно так, що стосується вашої програми.
Тейлор Прайс

197

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

Загальна бібліотека (.so) це бібліотека , яка пов'язана , але не вбудований в остаточному виконуваний файл, таким чином , будуть завантажені , коли виконуваний файл запускається і повинні бути присутніми в системі , в якій розгорнуто виконуваний файл.

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

DLL можна визначити два типи функцій: експортуються і внутрішні. Експортовані функції призначені для виклику іншими модулями, а також зсередини DLL, де вони визначені. Внутрішні функції, як правило, призначені для виклику тільки в межах DLL, де вони визначені.

SO бібліотека Linux не вимагає спеціального експорту заяви , щоб вказати, що експортуються символи, оскільки всі символи доступні для процесу запитальний.


1
+1 приємне просте пояснення. Якщо функція оголошена "Внутрішня" в DLL, чи означає це, що її не можна викликати за межами бібліотеки?
Майк

23
Не обов'язково правда, що всі символи доступні в бібліотеці SO. Приховані символи можливі та рекомендовані, оскільки немає жодної вагомої причини користувачі бібліотеки бачити всі ваші символи.
Зан Лінкс

3
FYI: g ++ має __attribute__синтаксис для вибіркових символів "експорту":#define DLLEXPORT __attribute__ ((visibility("default"))) #define DLLLOCAL __attribute__ ((visibility("hidden")))
Брайан Хаак

33

Я можу детальніше розглянути деталі DLL-файлів у Windows, щоб допомогти роз’яснити ці таємниці своїм друзям тут у * NIX-land ...

DLL схожа на файл спільного об’єкта. Обидва - зображення, готові до завантаження в пам'ять завантажувачем програм відповідної ОС. Зображення супроводжуються різними бітами метаданих, щоб допомогти лінкерам і завантажувачам зробити необхідні асоціації та використовувати бібліотеку коду.

У 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, він повинен або посилатись на "бібліотеку експорту" (*. адреса вхідної точки по імені через механізми LoadLibrary () та GetProcAddress (). Здебільшого посилання на файл LIB (який просто містить метадані лінкера для експортованих точок входу DLL) - це спосіб використання DLL. Динамічне завантаження зазвичай зарезервоване для реалізації "поліморфізму" або "налаштування часу виконання" в поведінці програми (доступ до додатків або функцій, визначених пізніше, також "плагіни").

Спосіб роботи Windows може часом викликати плутанину; система використовує розширення .LIB для посилання як на звичайні статичні бібліотеки (архіви, такі як файли POSIX * .a), так і на бібліотеки "експорту заглушки", необхідні для прив'язки програми до DLL під час посилання. Отже, завжди слід подивитися, чи має * .LIB-файл однаковий файл * .DLL; якщо ні, то ймовірність, що файл * .LIB - це статичний архів бібліотеки, а не експортує обов'язкові метадані для DLL.


4

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

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


Що може бути одним із прикладів використання dlopen () для більшого контролю завантаження? Якщо SO / DLL автоматично завантажується під час запуску, чи закриє (або) dlopen () повторно відкриває його з різними дозволами чи обмеженнями, наприклад? Дякую.
Хмара

1
Я вважаю, що dlopen призначений для плагінів або подібних функціональних можливостей. Дозволи / обмеження повинні бути такими ж, як і для автоматичного завантаження, і в будь-якому випадку dlopen буде рекурсивно завантажувати залежні бібліотеки.
rapadura

DLL і .soє не зовсім те ж саме. Дивіться цю відповідь
Базиль Старинкевич
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.