Зв'язок з динамічною бібліотекою із залежностями


79

Розглянемо такий сценарій:

  • Спільна бібліотека libA.so, без залежностей.
  • Спільна бібліотека libB.so, залежно від libA.so.

Я хочу скомпілювати двійковий файл, який зв'язується з libB. Чи слід пов'язувати двійковий файл лише з libB або з libA?

Чи є спосіб зв’язати лише прямі залежності, дозволяючи розв’язання невирішених символів із залежностей на час виконання?

Мене турбує той факт, що реалізація бібліотеки libB може змінитися в майбутньому, вводячи інші залежності (наприклад, libC, libD, libE). У мене будуть проблеми з цим?

Іншими словами:

  • Файли libA: a.cpp ах
  • Файли libB: b.cpp bh
  • основні програмні файли: main.cpp

Звичайно, b.cpp включає ah, а main.cpp - bh

Команди компіляції:

Який із наведених нижче варіантів слід використовувати?

або

Я не міг використати перший варіант. Лінкер скаржиться на невирішені символи з бібліотеки libA. Але мені це звучить трохи дивно.

Дуже дякую.

- Оновлені коментарі:

Коли я зв'язую двійковий файл, компонувальник намагатиметься вирішити всі символи з основного та libB. Однак libB має невизначені символи з libA. Тому лінкер скаржиться на це.

Ось чому мені також потрібно пов’язати з libA. Однак я знайшов спосіб ігнорувати невирішені символи із спільних бібліотек. Схоже, для цього слід використати такий командний рядок:

Схоже, все ще можна використовувати -rpath опцією. Однак мені потрібно це зрозуміти трохи краще.

Хтось знає можливі підводні камені при використанні -Wl,-unresolved-symbols=ignore-in-shared-libsопції?

- Оновлені коментарі 2:

-rpathне слід використовувати для цієї мети. Корисно змусити бібліотеку знаходитись у даному каталозі. -unresolved-symbolПідхід виглядає набагато краще.

Знову дякую.


Ось мінімальний приклад для тих, хто хоче перевірити подібні речі: github.com/cirosantilli/cpp-cheat/tree/…
Ciro Santilli 法轮功 ro 病 六四 事件 法轮功

Відповіді:


42

Схоже, ви вже пройшли більшу частину шляху. Молодці з вашим розслідуванням. Давайте подивимось, чи можу я допомогти прояснити "чому", що стоїть за цим?

Ось що робить компонувальник. Коли ви пов'язуєте свій виконуваний файл ("основний" вище), він містить деякі символи (функції та інші речі), які не вирішені. Він перегляне список бібліотек, що слідують, намагаючись вирішити невирішені символи. Попутно він виявляє, що деякі символи надаються libB.so, тому зазначає, що тепер їх вирішує ця бібліотека.

Однак він також виявляє, що деякі з цих символів використовують інші символи, які ще не вирішені у вашому виконуваному файлі, тому тепер потрібно вирішити і ці. Без посилання на libA.so ваша заявка буде неповною. Як тільки він зв'язується з libA.so, всі символи вирішуються, і зв'язування завершено.

Як ви бачили, використання -unresolved-symbols-in-shared-libs, не вирішує проблему. Він просто відкладає це так, що ці символи вирішуються під час виконання. Ось що-rpath : вказати бібліотеки для пошуку під час виконання. Якщо тоді ці символи неможливо вирішити, програма не зможе запуститися.

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

Тут є ще один опис цього процесу: чому порядок, у якому пов’язані бібліотеки, іноді спричиняє помилки в GCC?


2
Я знаю, що це було дуже давно, я забув позначити це як вирішене. Велике спасибі за вашу відповідь.]
Маркус,

Дякую, хлопці, за дивовижне питання та відповідну відповідь! У мене майже точно такий же сценарій. Я намагаюся обернути спільні об'єкти openCV у власний спільний об'єкт. припустимо, C.so - це мій звичай, а CV.so - це деякий openCV. Я успішно зв’язав C.so проти CV.so, і я хочу зв’язати main.cpp (ви отримуєте!) Проти C.so, але справа полягає лише в використанні об’єктів з C.so, main.cpp використовує об'єкт 'cv :: Mat', який визначено в CV.so .. У цьому випадку для запуску main.cpp мені потрібно зв'язати як C.so, так і CV.so ?? Я б дуже хотів, якщо хтось проллє це світло. Дякую! :)
Ленні Лінус,

2
Чому компоновщик не вирішує всі необхідні символи libA.so при створенні libB.so? Основна програма не повинна мати посилання на libA, оскільки вона повинна бути прозорою, наприклад, опосередковано захищеною libB?
Вільсон

Це неправильно. Linker не використовує libA.so, окрім як повідомляти користувача про неповний ланцюжок залежностей. Без надання libA.so, але замість цього, передаючи -unresolved-symbols = ignore-in-shared-libs, ви отримаєте такий самий виконуваний файл.
лістеррег

21

Для динамічного зв’язування лише з прямими залежностями ви можете використовувати -Wl,--as-neededдодавання бібліотек після -Wl,--as-needed :

Для перевірки прямих залежностей вам слід використовувати readelf замість ldd, оскільки ldd також показує непрямі залежності.

ldd також показує непрямі залежності:

Якщо ви використовуєте cmake , ви можете додати наступні рядки, щоб включити лише прямі залежності:


Вибачте, я зробив ваш приклад як програму c замість c ++. Тому я використав компілятор gcc. Але це також працює з g ++.
user1047271

1
Це справді корисна інформація. Я не знав про використання readelf замість ldd. Дуже дякую.
Маркус

1

Інший варіант - використання libtool

Якщо ви зміните g++виклик libtool --mode=compile g++для компіляції вихідного коду , а потім libtool --mode=link g++для створення програми з libB, потім libAбудете пов'язані автоматично.


0

Це цікавий допис - я теж цим бився головою, але я думаю, ви тут пропустили момент ..

Ідея така, правда?

Давайте далі розглянемо, що ..

  • У a.cpp (і лише там) ви визначаєте клас / змінну, назвемо це "symA"
  • У b.cpp (і лише там) ви визначаєте клас / змінну, назвемо її "symB".
  • symB використовує symA
  • main.cpp використовує symB

Тепер libB.so та libA.so були скомпільовані, як ви описали вище. Після цього ваш перший варіант повинен запрацювати, тобто:

Я думаю, ваша проблема походить від того, що

у main.cpp ви також посилаєтесь на symA

Я прав?

Якщо ви використовуєте символ у своєму коді, тоді цей символ потрібно знайти у файлі .so

Вся ідея взаємозв’язку спільних бібліотек (тобто створення API) полягає в тому, що символи в глибоких шарах приховані (подумайте про лущення цибулі) і не використовуються. .. тобто не посилайтеся на symA у вашому main.cpp, а лише на symB (і нехай symB посилається лише на symA).


1
Ви це неправильно зрозуміли. Очевидно, вам потрібно вирішити негайно необхідні символи. Проблема пов’язана із символами, які можуть знадобитися вашим залежностям. Часто при розробці бібліотек, які будуть використовуватися сторонніми розробниками, користувач бібліотеки повинен забезпечувати реалізацію функціональних можливостей, які використовує ваша бібліотека. Ви розробляєте, використовуючи заглушку, взагалі без залежностей, і інтегратор розробить lib для заміни заглушки, а потім зв’яже все між собою. Завантажувачу доведеться вирішити всі залежності. Однак ваші сценарії компіляції (і ваші користувачі) повинні це враховувати.
Маркус,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.