Я пытался обновить некоторые программы на старом Linux (Debian 7.5 wheezy). Я хотел бы оставить системные библиотеки по умолчанию нетронутыми и добавить вместе с ними несколько пользовательских сборок. Он отлично работает для большинства библиотек, только OpenSSL доставляет мне трудности (libssl.so + libcrypt.so).
Вот моя строка настройки OpenSSL:
# ./config --prefix=/usr/local --openssldir=/usr/local/openssl no-gost shared zlib no-ssl2 -fPIC
Затем для других программ, например cURL:
# ./configure LDFLAGS="-L/usr/local/ssl/lib -ldl" --with-ssl --enable-shared
Но потом я ошибся версией OpenSSL:
# curl --version
curl 7.44.0 (x86_64-unknown-linux-gnu) libcurl/7.44.0 OpenSSL/1.0.1e
Я знаю, что у libssl.so есть копии в следующих папках в этой системе:
/usr/lib/libssl.so
/usr/lib/x86_64-linux-gnu/libssl.so
/usr/local/lib/libssl.so
/usr/local/ssl/lib/libssl.so
Все они представляют собой одну и ту же скомпилированную версию, кроме /usr/lib/x86_64-linux-gnu/libssl.so это моя системная библиотека по умолчанию (v1.0.5e).
Я хотел бы знать, как я могу проинструктировать скрипты настройки, чтобы не заглядывать внутрь / lib / x86_64-linux-gnu? Могу я просто изменить символическую ссылку /usr/lib/x86_64-linux-gnu/libssl.so и указать ее на свои сборки? Это безопасно?
Спасибо,
Здесь задействованы две разные операции компоновщика: время сборки (используется для поиска библиотек и «символов», выполняется ld
или эквивалент), и время выполнения (в исполнении ld.so
), который загружает библиотеки в память процесса и выполняет переезд.
Когда вы используете -L
во время сборки, ld
только подтверждает, что библиотеки и необходимые символы (обычно функции, составляющие API) доступны. Во время выполнения можно использовать библиотеки с разными путями. LD_LIBRARY_PATH
, LD_PRELOAD
и RPATH (-R
или -rpath
) являются одними из способов управления этим - последний способ указать это во время сборки (так что это свойство двоичного файла и меньше зависит от пользовательской среды).
В любой библиотеке функции, API и ABI могут измениться, что приведет к ошибкам или нестабильности, если компоновщик найдет или загрузит «неправильный» двоичный файл. Несмотря на то, что символы могут совпадать, как ожидалось (или вы получите ошибку перед выполнением), колеса могут оторваться во время выполнения процесса. Есть решения для этого, управление версиями имени файла библиотеки и версиями символов в библиотеке, хотя здесь они не будут иметь большого смысла. (Сложность в том, что SHLIB_MAJOR
/SHLIB_MINOR
во всей серии OpenSSL 1.0.x стоит "1.0.0", поэтому эти библиотеки нельзя будет легко отличить, если вы не взломаете Makefile
.)
Curl сам проверяет наличие такого рода проблем, он сравнивает время сборки libcurl
версия к версии времени выполнения и может выдать:
ВНИМАНИЕ: версии curl и libcurl не совпадают. Это может повлиять на функциональность.
Современный ld
будет делать то же самое во время сборки, когда он отмечает потенциально конфликтующие библиотеки в зависимостях.
Для чистый build, без обмана среды выполнения, вы можете:
libssl.so
ссылки против libcrypto.so
, и установить по указанному путиlibssl.so
/libcrypto.so
Дешевый и неприятный способ решить проблему - использовать usr chrpath
Чтобы изменить ELF RPATH в двоичных файлах после сборки, я не рекомендую это вообще, и определенно не для curl, читайте дальше.
Теперь о сложностях: curl поддерживает множество протоколов, некоторые из этих протоколов предоставляются через другие библиотеки, и там, где протокол поддерживает TLS (или использует криптографические функции), он будет также связываться с libssl.so
и / или libcrypto.so
, например для LDAP и SSH. Что ты не хочу это:
curl ↦ libcurl.so → libldap.so → libssl.so
↦ lib...
↦ libcrypto.so
↳ libssl.so
где curl
сам использовал бы одну версию, но libldap.so
может ожидать загрузки другой версии; это также может дать сбой во время выполнения, если есть несовместимость ABI. Вам может не повезти с символом или порядком загрузки, и вы получите две (или более!) Версии загруженной библиотеки.
Есть три способа обойти это:
.a
библиотеки для статической компоновки. Для curl это не то же самое, что просто использовать --enable-static
. Это может работать, я делал это в далеком прошлом, но может не работать здесь, поэтому я не буду упоминать об этом дальше; и это может вызвать много головных болей, не в последнюю очередь с PIC / PIE.GnuTLS может еще больше замутить воду, хотя одновременное использование обеих библиотек не проблема (по крайней мере, я не видел этого до сих пор); это не относится к другим библиотекам, которые нацелены на совместимость с ABI, например LibreSSL. У Curl действительно есть проблемы с использованием только одной библиотеки SSL в своей сборке (в настоящее время он поддерживает 8, AFAIK), но он не знает, что, например, libssh2
может быть связано с.
Итак, в зависимости от версии, вы можете попробовать собрать OpenSSL и curl соответственно:
# OpenSSL
./config --prefix=/usr/local --openssldir=/usr/local/openssl no-gost \
shared zlib no-ssl2 -fPIC -Wl,-R,/usr/local/openssl
make depend && make && make install_sw
# curl
./configure --with-ssl=/usr/local/openssl --enable-shared \
--enable-ldap=no --without-libssh2 \
CFLAGS=-Wl,-R,/usr/local/openssl/lib
make && make install
(Несмотря на документацию об обратном, --with-ldap=no
и --without-ldap
не имеют полезного эффекта, используйте --enable-ldap=no
. libssh2
(для scp) обычно не включен по умолчанию.)
После установки ldd /usr/local/bin/curl
не должно содержать сюрпризов: ровно одна ссылка на каждый из ожидаемых libssl.so
и libcrypto.so
.
Сборка OpenSSL (не autoconf) установит RPATH
правильно на openssl
двоичный, но он не устанавливает его в библиотеках по умолчанию. Существуют специфические для платформы варианты расположения библиотек (большая часть обработки RPATH в сборке OpenSSL является уловкой: она применяется к платформам, отличным от Linux). Это может не потребоваться для curl, но не вызовет проблем.
Когда вы используете autoconf configure
нет гарантии, что расположение библиотеки, отличное от заданного по умолчанию, приведет к совпадению RPATH в двоичных файлах, CFLAGS
/LDFLAGS
обычно можно это исправить. Однако здесь, в двухэтапном процессе OpenSSL, config
не совсем уживается с такими переменными, как LDFLAGS
, поэтому добавьте в конце config
линия вместо этого, и Configure
правильно обрабатывает это при создании Makefile
.
Вы можете проверить исполняемый файл ELF или путь выполнения библиотеки с помощью:
readelf --dynamic elfbinary | grep PATH
Вы можете отладить загрузку библиотеки с помощью:
LD_DEBUG=files,libs /usr/local/bin/curl ...
(Обратите внимание, что исходный вопрос устарел, и OpenSSL 1.0.x больше не поддерживается официально, хотя дистрибутивы могут отличаться. Приведенные здесь инструкции обычно применимы для создания специальных версий OpenSSL 1.0.x для конкретных целей. stunnel
двоичный код для обратного прокси-сервера старого сетевого устройства, чтобы оно могло работать с современным браузером, является хорошим примером. )
Вы можете найти дальнейшие объяснения и инструкции в моем ответе на этот вопрос: Заставьте ld выбрать правильную библиотеку.
Я попытался сделать то, что вы предлагаете, что привело к ошибке сегментации! Итак, небезопасно!
/usr/lib/i686/cmov$ sudo ln -s /usr/lib/libssl.so.1.0.0 libssl.so.0.9.8
/usr/lib/i686/cmov$ ls -la
total 1684
drwxr-xr-x 2 root root 4096 Jun 16 14:15 .
drwxr-xr-x 3 root root 4096 Oct 22 2012 ..
-rw-r--r-- 1 root root 1393308 Feb 11 2013 libcrypto.so.0.9.8
lrwxrwxrwx 1 root root 24 Jun 16 14:15 libssl.so.0.9.8 -> /usr/lib/libssl.so.1.0.0
-rw-r--r-- 1 root root 310296 Feb 11 2013 libssl.so.0.9.8.bk
:/usr/lib/i686/cmov$ sudo /etc/init.d/nginx restart
Restarting nginx: nginx/usr/sbin/nginx: /usr/lib/i686/cmov/libssl.so.0.9.8: no version information available (required by /usr/sbin/nginx)
Segmentation fault
Я нашел одно решение, которое было помечено как «не лучший способ сделать это», но сработало для меня, - это отредактировать системную переменную LD_LIBRARY_PATH, например, в <user> /.bashrc:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib