Могу ли я заставить динамическую библиотеку связываться с определенной зависимостью динамической библиотеки? - PullRequest
1 голос
/ 15 мая 2019

Я создаю динамическую библиотеку, libfoo.so, которая зависит от libcrypto.so.

В моем файле autotools Makefile.am есть строка, подобная этой:

libfoo_la_LIBADD += -L${OPENSSL_DIR}/lib -lcrypto

где $OPENSSL_DIR по умолчанию /usr, но может быть переопределено путем передачи --with-openssl-dir=/whatever.

Как я могу убедиться, что исполняемый файл, использующий libfoo.so, использует ${OPENSSL_DIR}/lib/libcrypto.so (только) без человек, который строит или запускает исполняемый файл, должен использовать rpath или использовать скрипту с LD_LIBRARY_PATH?

. Когда все в порядке, я могу собрать libfoo и передать --with-openssl-dir=/usr/local/openssl-special, и он прекрасно работает.Но когда я запускаю ldd libfoo.so, он просто указывает на libcrypto.so в /usr/lib.

Единственное решение, которое я могу придумать, - это статическое соединение libcrypto.a в libfoo.so.Возможен ли другой подход?

1 Ответ

4 голосов
/ 15 мая 2019

Подробности динамического связывания во время выполнения зависят от платформы. Автоинструменты могут в некоторой степени оградить вас от этого, но если вы заботитесь о деталях, которые, очевидно, вам интересны, то, вероятно, этого недостаточно, чтобы автоинструменты могли выбирать для вас.

Однако с учетом сказанного вы, похоже, исключаете примерно все возможности:

  • Самый надежный способ гарантировать, что во время выполнения вы получите конкретную реализацию, с которой вы связались во время сборки, - это статическое связывание. Но вы говорите, что не хотите этого.

  • Если вместо этого вы используете динамические библиотеки, то вы полагаетесь на динамический компоновщик, чтобы связать реализацию библиотеки с исполняемым файлом во время выполнения. В этом случае есть два основных варианта того, как вы можете направить DL к конкретной реализации библиотеки:

    1. Через информацию, хранящуюся в двоичном файле программы / библиотеки . Вы используете терминологию, которая предлагает систему на основе ELF, а для общих объектов ELF это RPATH и / или RUNPATH, которые передают информацию о том, где искать необходимые библиотеки. Нет информации о пути, связанной с индивидуальными требованиями библиотеки; они идентифицированы только по SONAME. Но вы говорите, что не хотите использовать RPATH*, и поэтому я полагаю, что не RUNPATH тоже.

    2. Через статическую или динамическую конфигурацию динамического компоновщика . Вот тут и приходит LD_LIBRARY_PATH, но вы говорите, что не хотите этим пользоваться. Динамический компоновщик обычно также имеет файл конфигурации или файлы, такие как /etc/ld.so.conf. Там вы можете указать каталоги библиотек для поиска и, с некоторой осторожностью, порядок их поиска.

Возможно, тогда вы сможете связать желаемую реализацию библиотеки с вашим приложением, обновив файлы конфигурации динамического компоновщика, чтобы он сначала искал нужный путь. Однако это повлияет на всю систему и будет хрупким.

В качестве альтернативы, в зависимости от деталей характера зависимости, вы можете дать желаемой версии libcrypto отдельный SONAME. По сути, это сделало бы его другим объектом (, например, libdjcrypto) в отношении статических и динамических компоновщиков. Но это рискованно, потому что, если ваша библиотека имеет как прямые, так и косвенные зависимости от libcrypto, или если программа, использующая вашу библиотеку, зависит от libcrypto по другому пути, то вы окажетесь во время выполнения (динамически), связывая обе библиотеки, и, возможно, даже используя функции от обоих, в зависимости от происхождения каждого вызова.

Обратите внимание , что вышеупомянутая проблема должна беспокоить вас, если вы также статически связываете свою библиотеку. Если это оставляет какие-либо косвенные динамические зависимости на libcrypto в вашей библиотеке или какие-либо динамические зависимости от других источников в программах, использующих вашу библиотеку, то в результате вы получите одновременно несколько версий libcrypto.

Итог

Для исполняемого файла наилучшими вариантами являются (1) полностью статическая связь или (2) (для ELF) RPATH / LD_LIBRARY_PATH / RUNPATH, гарантирующие, что все компоненты требуют целевая библиотека через тот же SONAME. Мне нравится предоставлять скрипт-обертку, который устанавливает LD_LIBRARY_PATH, так что его эффект ограничен.

Для многократно используемой библиотеки"не делай этого", вероятно, является лучшей альтернативой. Высокий потенциал одновременного использования программ двумя разными версиями другой библиотеки (в вашем случае libcrypto) делает все доступные опции непривлекательными. Если, конечно, вы не в порядке с несколькими версиями библиотек, которые используются одной и той же программой, в этом случае вашими лучшими доступными альтернативами являются статическая связь и RPATH / RUNPATH (но не LD_LIBRARY_PATH).


* Обратите внимание, что по крайней мере некоторые версии libtool имеют привычку добавлять записи RPATH, независимо от того, просите вы их или нет - что-то, на что следует обратить внимание.Чтобы избежать этого, вам может потребоваться установить исправления для скриптов libtool, установленных в вашем проекте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...