Вопрос или проблема
У меня есть исполняемый app
, который зависит от библиотеки libbar.so
и загружает ее через RPATH
с помощью $ORIGIN
следующим образом:
$ readelf -d app
Секция динамической информации по смещению 0xe08 содержит 26 записей:
Тег Тип Имя/Значение
0x0000000000000001 (NEEDED) Общая библиотека: [libbar.so]
0x0000000000000001 (NEEDED) Общая библиотека: [libc.so.6]
0x000000000000000f (RPATH) Путь к библиотеке rpath: [$ORIGIN/lib/]
Было бы неплохо запустить его в соответствующей структуре каталогов, созданной с помощью символических ссылок на исполняемый файл и libbar.so
:
$ ls -R
.:
app@ lib/
./lib:
libbar.so@
— но линковщик следует за символическими ссылками на оригинальный файл исполняемого файла, устанавливает $ORIGIN
на директорию исполняемого файла и решает пути зависимостей оттуда. Можно ли заставить его не делать этого? Так, чтобы в плане каталогов, при поиске файлов библиотек, символические ссылки рассматривались как реальные файлы файловой системы (“конечные точки” поиска).
Также некоторые размышления по этой проблеме:
-
Удобно иметь бинарники, настроенные на поиск зависимостей в нескольких связанных директориях, например, в
$ORIGIN/
самого бинарника, а также в$ORIGIN/appname_dependencies/
(так что можно просто скопировать бинарник и его зависимости в одну директорию и запустить его, но также иметь резервный вариант для более сложной настройки с несколькими версиями одного и того же бинарника в системе). -
Из-за требования нескольких путей поиска зависимостей,
RPATH
является методом поиска, который нужно использовать: “разделенное” имя зависимости (NEEDED Shared library: [./libbar.so]
) устанавливает только 1 путь поиска. Также, для простоты пути разрешения зависимостей должны находиться в самом бинарнике. -
Приятно иметь возможность объединить все бинарники (приложение и все его зависимости) в полный граф зависимостей с ссылками, вместо копирования файлов. А символические ссылки более устойчивы, чем жесткие ссылки: они связывают между файловыми системами. На самом деле, у меня есть эта проблема в одной академической среде Linux-кластера, где нельзя создать жесткую ссылку на родительский каталог:
$ ln ../afile ln: создание жесткой ссылки `./afile' => `../afile': Недопустимая перекрестная ссылка между устройствами
Если вы действительно хотите смешивать символические ссылки таким образом, вы можете построить конфигурацию следующего типа:
- переместите ваш исполняемый файл в его собственный каталог
- создайте символическую ссылку из “нормального” местоположения на перемещенный исполняемый файл
- создайте символические ссылки в каталоге исполняемого файла на общие библиотеки, которые вы хотите разрешить
Ответ или решение
Для решения проблемы, связанной с тем, что $ORIGIN
в RPATH
следует символьным ссылкам на исполняемый файл, необходимо учитывать, что система динамической линковки в Linux обрабатывает символические ссылки, что влияет на путь поиска библиотек. К сожалению, стандартными средствами вы не можете изменить это поведение напрямую, так как оно является частью спецификации ELF и динамического линковщика, но есть несколько обходных путей для достижения желаемого результата.
Возможные решения:
- Создание специальной структуры каталогов:
Чтобы обойти проблему, вы можете создать специализированную структуру каталогов. Например:- Переместите исполняемый файл
app
в отдельный каталог. - Создайте символическую ссылку на этот исполняемый файл в нужном месте.
- В каталоге, где будет находиться исполняемый файл, создайте символические ссылки на необходимые библиотеки, такие как
libbar.so
.
- Переместите исполняемый файл
Пример структуры каталогов:
/path/to/your/app_directory/
├── app (исполнимый файл)
├── lib/
│ └── libbar.so (символическая ссылка)
-
Использование
RPATH
с фиксированным путем:
Вместо использования$ORIGIN
, вы можете жестко прописать полный путь к библиотекам вRPATH
. Хотя это решение снижает гибкость переносимости вашего приложения, оно полностью исключает возможность следования символьным ссылкам. -
Использование
RUNPATH
вместоRPATH
:
Если ваша система поддерживаетRUNPATH
, вы могли бы попробовать использовать его, так как он имеет более высокий приоритет и предоставляет больше контроля над порядком поиска. Однако, это не гарантирует полное исключение следования символьным ссылкам, и может работать не во всех случаях. -
Использование
chrpath
илиpatchelf
для измененияRPATH
:
Вы можете изменитьRPATH
после компиляции с помощью утилитchrpath
илиpatchelf
, чтобы указать более специфичные пути для библиотек. Вы можете добавить относительные пути без использования$ORIGIN
, однако это решение требует дальнейшего анализа и тестирования.
Заключение:
К сожалению, полностью контролировать поведение динамической линковки и запретить следование символьным ссылкам для $ORIGIN
невозможно в рамках стандартного функционала. Наилучший способ – использовать структуру каталогов с физическими копиями библиотек или жестко прописанные пути для RPATH
. Выбор подхода зависит от ваших требований к переносимости и удобству установки приложения.