Multiarch paths and toolchain implications
Binary files in packages are usually platform-specific, that is they work only on the architecture they were built for. Therefore, the packaging system provides platform-specific versions for them. Currently, these versions will install platform-specific files to the same file system locations, which implies that only one of them can be installed into a system at the same time.
The goal of the «multiarch» effort is to lift this limitation, and allow multiple platform-specific versions of the same package to be installed into the same file system at the same time. In addition, each package should install to the same file system locations no matter on which host architecture the installation is performed (that is, no rewriting of path names during installation).
- Systems able to run binaries of more than one ISA natively.
- Support for multiple incompatible ABI variants on the same ISA.
- Support for processor-optimized ABI-compatible library variants.
- NFS file system images exported to hosts of different architectures.
- Target file systems for ISA emulators etc.
- Development packages for cross-compilation.
In order to support this, platform-specific versions of a multiarch package must have the property that for each file, it is either 100% identical across platforms, or else it must be installed to separate locations in the file system.
The latter is the case at least for executable files, shared libraries, static libraries and object files, and to some extent maybe header files. This means that in a multiarch world, such files must move to different locations in the file system than they are now. This causes a variety of issues to be solved; in particular, most of the existing locations are defined by the FHS and/or are assumed to have well-known values by various system tools.
In the following two sections, I’ll provide details on file system paths are currently handled in these two areas. In the final section, I’ll discuss suggestions how to extend the current behavior to support multiarch paths.
Loading/running an executable
- native ELF executable
- ELF exectuable for a secondary native ISA (32-bit on 64-bit)
- #! scripts
- user-defined execution handlers (via binfmt_misc)
The binary itself is passed via full (or relative) pathname to the execve call; the kernel does not make file system hierarchy assumptions. By convention, callers of execve usually search well-known path locations (via the PATH environment variable) when locating executables. How to adapt these conventions for multiarch is beyond the scope of this document.
With #! scripts and binfmt_misc handlers, the kernel will involve a user-space helper to start execution. The location of these handlers themselves and secondary files they in turn may require is provided by user space (e.g. in the #! line, or in the parameters installed into the binfmt_misc file system). Again, adapting these path names is beyond the scope of this document.
ELF interpreter
For native ELF executables, there are two additional classes of files involved in the initial load process: the ELF interpreter (dynamic loader), and shared libraries required by the executable.
The ELF interpreter name is provided in the PT_INTERP program header of the ELF executable to be loaded; the kernel makes no file name assumptions here. This program header is generated by the linker when performing final link of a dynamically linked executable; it uses the file name passed via the -dynamic-linker argument. (Note that while the linker will fall back to some hard-coded path if that argument is missing, on many Linux platforms this default is in fact incorrect and does not correspond to a ELF interpreter actually installed in the file system in current distributions. Passing a correct -dynamic-linker argument is therefore mandatory.)
In normal builds, the -dynamic-linker switch is passed to the linker by the GCC compiler driver. This in turn gets the proper argument to be used on the target platform from the specs file; the (correct) default value is hard-coded into the GCC platform back-end sources. On bi-arch platforms, GCC will automatically choose the correct variant depending on compile options like -m32 or -m64. Again, the logic to do so is hard-coded into the back-end. Unfortunately, various bi-arch platforms use different schemes today:
Понимание общих библиотек в Linux
В программировании библиотека представляет собой набор предварительно скомпилированных фрагментов кода, которые можно повторно использовать в программе. Библиотеки упрощают жизнь программистам, поскольку они предоставляют повторно используемые функции, подпрограммы, классы, структуры данных и т. д. (написанные другим программистом), которые они могут использовать в своих программах.
Например, если вы создаете приложение, которое должно выполнять математические операции, вам не нужно создавать для этого новую математическую функцию, вы можете просто использовать существующие функции в библиотеках для этого языка программирования.
Примеры библиотек в Linux включают libc (стандартная библиотека C) или Glibc (GNU-версия стандартной библиотеки C), libcurl (многопротокольный файл библиотека передачи), libcrypt (библиотека, используемая для шифрования, хеширования и кодирования в C) и многие другие.
Linux поддерживает два класса библиотек, а именно:
- Статические библиотеки — привязываются к программе статически во время компиляции.
- Динамические или общие библиотеки — загружаются при запуске программы и загружаются в память, а привязка происходит во время выполнения.
Динамические или разделяемые библиотеки можно разделить на следующие категории:
- Динамически подключаемые библиотеки — здесь программа компонуется с общей библиотекой, и ядро загружает библиотеку (если ее нет в памяти) при выполнении.
- Динамически загружаемые библиотеки — программа получает полный контроль, вызывая функции с библиотекой.
Соглашения об именах общих библиотек
Общие библиотеки имеют два имени: имя библиотеки (также известное как soname) и \имя файла (абсолютный путь к файлу, в котором хранится код библиотеки).
Например, soname для libc — libc.so.6: где lib — префикс, libc.so.6 >c — описательное имя, то есть общий объект, а 6 — версия. Имя файла: /lib64/libc.so.6. Обратите внимание, что soname на самом деле является символической ссылкой на имя файла.
Поиск общих библиотек в Linux
Общие библиотеки загружаются с помощью ld.so (или ld.so.x) и ld-linux.so (или ld- linux.so.x), где x — версия. В Linux /lib/ld-linux.so.x ищет и загружает все общие библиотеки, используемые программой.
Программа может вызвать библиотеку, используя ее имя библиотеки или имя файла, а путь к библиотеке хранит каталоги, в которых библиотеки могут быть найдены в файловой системе. По умолчанию библиотеки расположены в /usr/local/lib, /usr/local/lib64, /usr/lib и /usr/lib64; системные библиотеки запуска находятся в /lib и /lib64. Однако программисты могут устанавливать библиотеки в произвольных местах.
Путь к библиотеке можно указать в файле /etc/ld.so.conf, который можно редактировать с помощью редактора командной строки.
Строки в этом файле указывают ядру загрузить файл в /etc/ld.so.conf.d. Таким образом, сопровождающие пакетов или программисты могут добавлять каталоги своих пользовательских библиотек в список поиска.
Если вы посмотрите в каталог /etc/ld.so.conf.d, вы увидите файлы .conf для некоторых распространенных пакетов (kernel, mysql и postgresql в Это дело):
# ls /etc/ld.so.conf.d kernel-2.6.32-358.18.1.el6.x86_64.conf kernel-2.6.32-696.1.1.el6.x86_64.conf mariadb-x86_64.conf kernel-2.6.32-642.6.2.el6.x86_64.conf kernel-2.6.32-696.6.3.el6.x86_64.conf postgresql-pgdg-libs.conf
Если вы посмотрите на mariadb-x86_64.conf, вы увидите абсолютный путь к библиотекам пакетов.
# cat mariadb-x86_64.conf /usr/lib64/mysql
Приведенный выше метод устанавливает путь к библиотеке на постоянной основе. Чтобы установить его временно, используйте переменную среды LD_LIBRARY_PATH в командной строке. Если вы хотите сохранить изменения постоянными, добавьте эту строку в файл инициализации оболочки /etc/profile (глобальный) или ~/.profile (зависит от пользователя).
# export LD_LIBRARY_PATH=/path/to/library/file
Управление общими библиотеками в Linux
Давайте теперь посмотрим, как работать с разделяемыми библиотеками. Чтобы получить список всех зависимостей общей библиотеки для двоичного файла, вы можете использовать утилиту ldd. Вывод ldd имеет вид:
library name => filename (some hexadecimal value) OR filename (some hexadecimal value) #this is shown when library name can’t be read
Эта команда показывает все зависимости общих библиотек для команды ls.
# ldd /usr/bin/ls OR # ldd /bin/ls
Пример вывода
linux-vdso.so.1 => (0x00007ffebf9c2000) libselinux.so.1 => /lib64/libselinux.so.1 (0x0000003b71e00000) librt.so.1 => /lib64/librt.so.1 (0x0000003b71600000) libcap.so.2 => /lib64/libcap.so.2 (0x0000003b76a00000) libacl.so.1 => /lib64/libacl.so.1 (0x0000003b75e00000) libc.so.6 => /lib64/libc.so.6 (0x0000003b70600000) libdl.so.2 => /lib64/libdl.so.2 (0x0000003b70a00000) /lib64/ld-linux-x86-64.so.2 (0x0000561abfc09000) libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003b70e00000) libattr.so.1 => /lib64/libattr.so.1 (0x0000003b75600000)
Поскольку разделяемые библиотеки могут находиться во многих разных каталогах, поиск по всем этим каталогам при запуске программы будет крайне неэффективным: это один из вероятных недостатков динамических библиотек. Поэтому используется механизм кэширования, выполняемый программой ldconfig.
По умолчанию ldconfig считывает содержимое /etc/ld.so.conf, создает соответствующие символические ссылки в каталогах динамических ссылок, а затем записывает кэш в >/etc/ld.so.cache, который затем легко используется другими программами.
Это очень важно, особенно если вы только что установили новые разделяемые библиотеки или создали свои собственные или создали новые каталоги библиотек. Вам нужно запустить команду ldconfig, чтобы изменения вступили в силу.
# ldconfig OR # ldconfig -v #shows files and directories it works with
После создания общей библиотеки ее необходимо установить. Вы можете переместить его в любой из стандартных каталогов, упомянутых выше, и выполнить команду ldconfig.
Или выполните следующую команду, чтобы создать символические ссылки из soname в имя файла:
# ldconfig -n /path/to/your/shared/libraries
Чтобы приступить к созданию собственных библиотек, ознакомьтесь с этим руководством из Проекта документации Linux (TLDP).
Это пока все! В этой статье мы познакомили вас с библиотеками, объяснили общие библиотеки и способы управления ими в Linux. Если у вас есть какие-либо вопросы или дополнительные идеи, которыми вы хотите поделиться, используйте форму комментариев ниже.