102.3 Урок 1
Сертифікат: |
LPIC-1 |
---|---|
Версія: |
5.0 |
Розділ: |
102 Установка Linux та керування пакунками |
Тема: |
102.3 Керування спільними бібліотеками |
Урок: |
1 з 1 |
Вступ
У цьому уроці ми будемо обговорювати спільні бібліотеки, також відомі як спільні об’єкти: частини скомпільованого, багаторазового коду, такі як функції чи класи, які періодично використовуються різними програмами.
Для початку ми пояснимо, що таке спільні бібліотеки, як їх ідентифікувати та де вони знаходяться. Далі ми розглянемо, як налаштувати місця їх зберігання. Нарешті, ми покажемо, як шукати спільні бібліотеки, від яких залежить конкретна програма.
Концепція спільних бібліотек
Подібно до своїх фізичних аналогів, бібліотеки програмного забезпечення — це колекції коду, які призначені для використання багатьма різними програмами; так само, як фізичні бібліотеки зберігають книги та інші ресурси для використання багатьма різними людьми.
Щоб створити виконуваний файл із вихідного коду програми, необхідно виконати два важливі кроки. По-перше, компілятор перетворює вихідний код у машинний код, який зберігається в так званих об’єктних файлах. По-друге, компонувальник об’єднує об’єктні файли та рзв’язує їх з бібліотеками, щоб створити кінцевий виконуваний файл. Це зв’язування можна зробити статично або динамічно. Залежно від того, який метод ми використовуємо, ми будемо говорити про статичні бібліотеки або, у разі динамічного зв’язування, про спільні бібліотеки. Пояснимо їх відмінності.
- Статичні бібліотеки
-
Статична бібліотека об’єднується з програмою під час зв’язування. Копія коду бібліотеки вбудовується в програму і стає її частиною. Таким чином, програма не має залежностей від бібліотеки під час виконання, оскільки програма вже містить код бібліотеки. Відсутність залежностей можна розглядати як перевагу, оскільки вам не доведеться турбуватися про те, щоб використані бібліотеки завжди були доступні. З іншого боку, статично пов’язані програми важчі.
- Спільні (або динамічні) бібліотеки
-
У разі спільних бібліотек компонувальник просто подбає про те, щоб програма посилалася на бібліотеки правильно. Проте компонувальник не копіює жодного бібліотечного коду до програмного файлу. Однак під час виконання спільна бібліотека має бути доступною, щоб забезпечити залежності програми. Це економічний підхід до керування системними ресурсами, оскільки він допомагає зменшити розмір програмних файлів, а до пам’яті завантажується лише одна копія бібліотеки, навіть якщо вона використовується кількома програмами.
Умови іменування файлів спільного доступу
Ім’я спільної бібліотеки, також відоме як sonname, відповідає шаблону, який складається з трьох елементів:
-
Назва бібліотеки (зазвичай з префіксом
lib
). -
so
, що означає “спільний об’єкт” (shared object). -
Номер версії бібліотеки.
Наприклад: libpthread.so.0
Натомість, імена статичних бібліотек закінчуються на .a
, наприклад, libpthread.a
.
Note
|
Оскільки файли, що містять спільні бібліотеки, повинні бути доступні під час виконання програми, більшість систем Linux містять спільні бібліотеки. Оскільки статичні бібліотеки потрібні лише у конкретному файлі, коли програма зібрана, вони можуть не бути присутніми в системі кінцевого користувача. |
glibc
(бібліотека GNU C) є хорошим прикладом спільної бібліотеки. У системі Debian GNU/Linux 9.9 її файл називається libc.so.6
. Такі досить загальні імена файлів, як правило, є символічними посиланнями, які вказують на фактичний файл, що містить бібліотеку, ім’я якої містить точний номер версії. У випадку glibc
це символічне посилання виглядає так:
$ ls -l /lib/x86_64-linux-gnu/libc.so.6 lrwxrwxrwx 1 root root 12 feb 6 22:17 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.24.so
Ця модель посилань на файли спільної бібліотеки, названі відповідною версією за більш загальними іменами файлів, є звичайною практикою.
Інші приклади спільних бібліотек включають libreadline
(яка дозволяє користувачам редагувати командні рядки під час їх введення та включає підтримку режимів редагування Emacs і vi), libcrypt
(яка містить функції, пов’язані з шифруванням, хешуванням та кодуванням) або libcurl
(яка є багатопротокольною бібліотекою передачі файлів).
Поширені місця розташування спільних бібліотек у системі Linux:
-
/lib
-
/lib32
-
/lib64
-
/usr/lib
-
/usr/local/lib
Note
|
Концепція спільних бібліотек не є виключною для Linux. У Windows, наприклад, вони називаються DLL, що означає динамічно приєднувані бібліотеки (Dynamic Linked Libraries). |
Конфігурація шляхів спільної бібліотеки
Посилання, що містяться в динамічно пов’язаних програмах, розв’язуються динамічним компонувальником (ld.so
або ld-linux.so
) під час запуску програми. Динамічний компонувальник шукає бібліотеки в кількох каталогах. Ці каталоги визначаються шляхом до бібліотеки. Шлях до бібліотеки налаштовується в каталозі /etc
, а саме у файлі /etc/ld.so.conf
і, що більш поширено в наш час, у файлах, які знаходяться в каталозі /etc/ld.so.conf.d
. Зазвичай перший містить лише один рядок include
для файлів *.conf
в останньому:
$ cat /etc/ld.so.conf include /etc/ld.so.conf.d/*.conf
Каталог /etc/ld.so.conf.d
містить файли *.conf
:
$ ls /etc/ld.so.conf.d/ libc.conf x86_64-linux-gnu.conf
Ці файли *.conf
повинні містити абсолютні шляхи до каталогів спільної бібліотеки:
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu
Команда ldconfig
займається читанням цих файлів конфігурації, створюючи вищезгаданий набір символьних посилань, які допомагають знайти окремі бібліотеки, і, нарешті, оновлювати файл кешу /etc/ld.so.cache
. Таким чином, ldconfig
необхідно запускати щоразу, коли файли конфігурації додаються або оновлюються.
Корисними параметрами для ldconfig
є:
-v
,--verbose
-
Відображає номери версій бібліотеки, назву кожного каталогу та створені посилання:
$ sudo ldconfig -v /usr/local/lib: /lib/x86_64-linux-gnu: libnss_myhostname.so.2 -> libnss_myhostname.so.2 libfuse.so.2 -> libfuse.so.2.9.7 libidn.so.11 -> libidn.so.11.6.16 libnss_mdns4.so.2 -> libnss_mdns4.so.2 libparted.so.2 -> libparted.so.2.0.1 (...)
Таким чином, ми можемо побачити, наприклад, як
libfuse.so.2
пов’язано з фактичним спільним об’єктним файломlibfuse.so.2.9.7
. -p
,--print-cache
-
Виводить списки каталогів і бібліотек-кандидатів, що зберігаються в поточному кеші:
$ sudo ldconfig -p 1094 libs found in the cache `/etc/ld.so.cache' libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0 libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5 libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0 (...)
Зверніть увагу на те, як кеш використовує повні soname-імена посилань:
$ sudo ldconfig -p |grep libfuse libfuse.so.2 (libc6,x86-64) => /lib/x86_64-linux-gnu/libfuse.so.2
Якщо ми переглянемо /lib/x86_64-linux-gnu/libfuse.so.2
, ми знайдемо посилання на фактичний спільний об’єктний файл libfuse.so.2.9.7
, який зберігається в тому самому каталозі:
$ ls -l /lib/x86_64-linux-gnu/libfuse.so.2 lrwxrwxrwx 1 root root 16 Aug 21 2018 /lib/x86_64-linux-gnu/libfuse.so.2 -> libfuse.so.2.9.7
Note
|
Оскільки для цього потрібен доступ для запису до |
На додаток до файлів конфігурації, описаних вище, змінну середовища LD_LIBRARY_PATH можна використовувати для тимчасового додавання нових шляхів до спільних бібліотек. Вона складається з набору каталогів, відокремлених двокрапкою (:
), де здійснюється пошук бібліотек. Щоб додати, наприклад, /usr/local/mylib
до шляху бібліотеки в поточному сеансі оболонки, ви можете ввести:
$ LD_LIBRARY_PATH=/usr/local/mylib
Тепер ви можете перевірити його значення:
$ echo $LD_LIBRARY_PATH /usr/local/mylib
Щоб додати /usr/local/mylib
до шляху бібліотеки в поточному сеансі оболонки та експортувати його до всіх дочірніх процесів, створених із цієї оболонки, ви повинні ввести:
$ export LD_LIBRARY_PATH=/usr/local/mylib
Щоб видалити змінну середовища LD_LIBRARY_PATH
, просто введіть:
$ unset LD_LIBRARY_PATH
Щоб зробити зміни постійними, ви можете написати рядок
export LD_LIBRARY_PATH=/usr/local/mylib
в одному зі сценаріїв ініціалізації Bash, наприклад /etc/bash.bashrc
або ~/.bashrc
.
Note
|
|
Пошук залежностей певного виконуваного файлу
Щоб знайти спільні бібліотеки, необхідні для певної програми, використовуйте команду ldd
, за якою слідує абсолютний шлях до програми. Вихідні дані показують шлях до файлу спільної бібліотеки, а також шістнадцяткову адресу пам’яті, за якою він завантажується:
$ ldd /usr/bin/git linux-vdso.so.1 => (0x00007ffcbb310000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f18241eb000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1823fd1000) libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f1823db6000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1823b99000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1823991000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f18235c7000) /lib64/ld-linux-x86-64.so.2 (0x00007f182445b000)
Аналогічно ми використовуємо ldd
для пошуку залежностей спільного об’єкта:
$ ldd /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 (0x00007fbfed578000) linux-vdso.so.1 (0x00007fffb7bf5000)
За допомогою параметра -u
(або --unused
) параметр ldd
виводить невикористані прямі залежності (якщо вони існують):
$ ldd -u /usr/bin/git Unused direct dependencies: /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1
Причина невикористаних залежностей пов’язана з параметрами, які використовує компонувальник під час побудови двійкового файлу. Хоча програмі не потрібна невикористана бібліотека, вона все ще була пов’язана та позначена як NEEDED
в інформації про об’єктний файл. Ви можете дослідити це за допомогою таких команд, як readelf
або objdump
, які ви незабаром використовуватимете в дослідницькій вправі.
Вправи до посібника
-
Розділіть такі назви спільних бібліотек на частини:
Повне ім’я файлу Назва бібліотеки so суфікс Номер версії linux-vdso.so.1
libprocps.so.6
libdl.so.2
libc.so.6
libsystemd.so.0
ld-linux-x86-64.so.2
-
Ви розробили програмне забезпечення і хочете додати до своєї системи новий каталог спільної бібліотеки (
/opt/lib/mylib
). Ви пишете його абсолютний шлях у файл під назвоюmylib.conf
.-
До якого каталогу потрібно помістити цей файл?
-
Яку команду потрібно запустити, щоб зміни були повністю ефективними?
-
-
Яку команду ви б використали, щоб вивести спільні бібліотеки, необхідні для
kill
?
Дослідницькі вправи
-
objdump
- це утиліта командного рядку, яка відображає інформацію з об’єктних файлів. Перевірте, чи вона встановлена у вашій системі за допомогоюwhich objdump
. Якщо це не так, будь ласка, встановіть її.-
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб вивести залежностіglibc
: -
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб вивести ім’я soname дляglibc
: -
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб надрукувати залежності Bash:
-
Підсумки
На цьому уроці ви дізналися:
-
Що таке спільна (або динамічна) бібліотека.
-
Відмінності між спільними та статичними бібліотеками.
-
Назви спільних бібліотек (sonames).
-
Бажані розташування для спільних бібліотек у системі Linux, таких як
/lib
або/usr/lib
. -
Призначення динамічного компонувальника
ld.so
(абоld-linux.so
). -
Як налаштувати шляхи спільної бібліотеки за допомогою файлів у
/etc/
, такі якld.so.conf
або файлів у каталозіld.so.conf.d
. -
Як налаштувати шляхи спільної бібліотеки за допомогою змінної середовища
LD_LIBRARY_PATH
. -
Як шукати залежності виконуваного файлу та спільної бібліотеки.
Команди, використані в цьому уроці:
ls
-
Виводить вміст каталогу.
cat
-
Об’єднує файли та виводить їх на стандартному виводі.
sudo
-
Дозволяє суперкористувачу виконувати команду з правами адміністратора.
ldconfig
-
Налаштовує прив’язки під час виконання динамічного компонувальника.
echo
-
Відображає значення змінної середовища.
export
-
Експортує значення змінної середовища в дочірні оболонки.
unset
-
Видаляє змінну середовища.
ldd
-
Виведення залежностей спільних об’єктів програми.
readelf
-
Відображення інформації про файли ELF (ELF означає executable and linkable format — формат виконання та зв’язування).
objdump
-
Виведення інформації з об’єктних файлів.
Відповіді на вправи до посібника
-
Розділіть такі назви спільних бібліотек на частини:
Повне ім’я файлу Назва бібліотеки so суфікс Номер версії linux-vdso.so.1
linux-vdso
so
1
libprocps.so.6
libprocps
so
6
libdl.so.2
libdl
so
2
libc.so.6
libc
so
6
libsystemd.so.0
libsystemd
so
0
ld-linux-x86-64.so.2
ld-linux-x86-64
so
2
-
Ви розробили програмне забезпечення і хочете додати до своєї системи новий каталог спільної бібліотеки (
/opt/lib/mylib
). Ви пишете його абсолютний шлях у файл під назвоюmylib.conf
.-
До якого каталогу потрібно помістити цей файл?
/etc/ld.so.conf.d
-
Яку команду потрібно запустити, щоб зміни були повністю ефективними?
ldconfig
-
-
Яку команду ви б використали, щоб вивести спільні бібліотеки, необхідні для
kill
?ldd /bin/kill
Відповіді до дослідницьких вправ
-
objdump
- це утиліта командного рядку, яка відображає інформацію з об’єктних файлів. Перевірте, чи вона встановлена у вашій системі за допомогоюwhich objdump
. Якщо це не так, будь ласка, встановіть її.-
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб вивести залежностіglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED
-
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб вивести ім’я soname дляglibc
:objdump -p /lib/x86_64-linux-gnu/libc.so.6 | grep SONAME
-
Використовуйте
objdump
з параметром-p
(або--private-headers
) іgrep
, щоб надрукувати залежності Bash:objdump -p /bin/bash | grep NEEDED
-