1) В Ubuntu 10.04 с OpenSSL 0.9.8:

1) В Ubuntu 10.04 с OpenSSL 0.9.8:

Я пытаюсь скомпилировать программу progи связать ее с OpenSSL 1.0.2 beta, собранной из исходников и установленной в /usr/local/ssl-1.0.2. На старой системе с 0.9.8 это работает без особых проблем. На более новой системе с установленной 1.0.1 это требует немного больше работы. Интересно, почему.

1) В Ubuntu 10.04 с OpenSSL 0.9.8:

Вот шаги, которые я выполняю для компиляции и линковки с версией 1.0.2.

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

=> Отображаются только файлы 0.9.8, поэтому я добавляю путь к файлам 1.0.2...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0008000000008000) => /lib/i686/cmov/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0004000000000000) => /lib/i586/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6, hwcap: 0x0002000000000000) => /lib/i486/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /lib/libcrypto.so.0.9.8
 libcrypto.so.0.9.8 (libc6) => /usr/lib/libcrypto.so.0.9.8
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

И поэтому я могу скомпилировать prog...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0x0083b000)

... и он правильно связан с 1.0.2.

2) В Debian Wheezy с OpenSSL 1.0.1:

Те же шаги, другой результат.

$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0

Аналогично добавляю путь к 1.0.2...

$ ldconfig /usr/local/ssl-1.0.2/lib
$ ldconfig -p | grep libcrypto

=>

 libcrypto.so.1.0.0 (libc6, hwcap: 0x0008000000008000) => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6, hwcap: 0x0004000000000000) => /usr/lib/i386-linux-gnu/i586/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0
 libcrypto.so.1.0.0 (libc6) => /usr/lib/i386-linux-gnu/libcrypto.so.1.0.0
 libcrypto.so (libc6) => /usr/local/ssl-1.0.2/lib/libcrypto.so

Затем я пытаюсь скомпилировать...

$ gcc -o prog ... -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/lib/i386-linux-gnu/i686/cmov/libcrypto.so.1.0.0 (0xb7591000)

Но здесь он не связан с 1.0.2. Путь к библиотеке времени компиляции правильный (указанный с -L, gccв противном случае не сработает, так как некоторые функции, используемые в , progспецифичны для 1.0.2), но не путь времени выполнения.

3) Как заставить это работать на Wheezy

С запуском или без ldconfig /usr/local/ssl-1.0.2/lib:

$ gcc -o prog ... -Wl,--rpath=/usr/local/ssl-1.0.2/lib -L/usr/local/ssl-1.0.2/lib -lcrypto
$ ldd prog

=>

    libcrypto.so.1.0.0 => /usr/local/ssl-1.0.2/lib/libcrypto.so.1.0.0 (0xb7592000)

Либо запустите export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/libперед запуском gcc.

Что я хотел бы знать

Используя LD_DEBUG=libs ./progподсказку mr.spuratic, я обнаружил, что пути просматриваются в /etc/ld.so.cache. Я открыл этот файл и обнаружил, что порядок, в котором просматриваются .so, соответствует выводу ldconfig -p.

Итак, фактический вопрос:

  • Почему файл 1.0.2 оказывается наверху списка ldconfig в 1), но не в 2)? Чистая случайность? Путаница из-за того, что файлы 1.0.1 и 1.0.2 имеют одинаковый суффикс? ("1.0.0")

Или, говоря по-другому,

  • Почему флаги, добавленные в 3), не нужны в 1)?

решение1

При компиляции/линковке с пакетом, не являющимся пакетом по умолчанию, необходимо учитывать три момента:

  • заголовки (обычно CFLAGS)
  • путь к библиотеке времени компиляции (обычно LDFLAGS)
  • путь к библиотеке времени выполнения (rpathчерез LDFLAGS, LD_RUN_PATH, LD_LIBRARY_PATHили ld.so.conf)

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

На этапе компоновки важен порядок путей к библиотекам. Если вы используете набор инструментов GNU (gcc и binutils), вы, вероятно, можете увидеть, что происходит, установив CFLAGSзаранее configure(или, возможно, Makefileнепосредственно в файле):

export CFLAGS="-Wl,-t"

Это передает -tопцию трассировки компоновщику. Вам может потребоваться добавить V=1или VERBOSE=1к команде make, если вы получаете только краткие строки "CC" и "LD" на выходе во время make.)

Во время выполнения вы можете увидеть, что ld.soпытается сделать, тщательно настроив LD_DEBUG, например

LD_DEBUG=libs ./myprog

(или попробуйте значения filesили symbolsдля более подробной информации)

Чтобы правильно указать все три параметра во время сборки, вы должны иметь возможность сделать следующее:

  • export CFLAGS="-I/usr/local/ssl-1.0.2/include"
  • export LDFLAGS="-L/usr/local/ssl-1.0.2/lib -R/usr/local/ssl-1.0.2/lib"

затем перенастройте/перекомпилируйте.

Вы используете --openssldirвместо более традиционного --prefix(я рекомендую последний вариант, а также используйте его только make install_swесли вам не нужны 1000 или около того страниц руководства и символических ссылок, которые дает вам установка по умолчанию). Это может быть частью проблемы. По какой-то причине библиотеки .so, которые вы показываете, как известно, ld.soне имеют суффикса версии (например, .so.1.0.2), правильный " make install" должен был настроить это для вас (через link-sharedцель в main Makefile).

Опция -Rуказывает компоновщику встроить RPATH в исполняемый файл вывода для конкретной библиотеки OpenSSL, чтобы ему не приходилось полагаться на значение по умолчанию, которое ld.soобычно предоставляет компоновщик времени выполнения ( ). Вы можете изменить существующие двоичные файлы с помощьюchrpathвместо.

Это более или менее эквивалентно экспорту LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib. Подробнее о RPATH и связанном с ним RUNPATH можно прочитать здесь:http://blog.tremily.us/posts/rpath/

В крайнем случае вы можете собрать OpenSSL без «shared» или с «noshared», это даст вам статические библиотеки, у которых не будет этой проблемы (но могут быть другие проблемы, например, при использовании в ELF .so, что приведет к проблемам PIC/PIE)


На основе обновленных данных я полагаю, что проблема в том, что 1.0.1 и 1.0.2beta обе устанавливают суффикс версии .so (SONAME) на 1.0.0. В первой системе только с 0.9.8 это не вызывает проблем; во второй, где 1.0.1 и 1.0.2 обе версии имеют версию 1.0.0, "побеждает первое совпадение" на основе порядка ld.so.{conf,d}. Помните, ldкомпоновщик времени компиляции — это другая программа, чем ld.soкомпоновщик времени выполнения, и может вести себя по-другому (обычно это приводит к ошибкам символов или к чему-то похуже, как вы видели).

$ cd /usr/local/src/openssl/openssl/1.0.2beta1
$ readelf -a libssl.so | grep SONAME
0x0000000e (SONAME)                     Library soname: [libssl.so.1.0.0]

$ cat verchk.c
int main(int argc, char *argv[]) {
    printf("build: %s\n",OPENSSL_VERSION_TEXT);
    printf("run  : %s\n",SSLeay_version(SSLEAY_VERSION));
    return 0;
}

$ gcc -Wall  -I/usr/local/src/openssl/openssl-1.0.2-beta1/include \
    -Wl,-rpath /usr/local/src/openssl/openssl-1.0.2-beta1/ \
    -o verchk /usr/local/src/openssl/openssl-1.0.2-beta1/libcrypto.so verchk.c

$ ./verchk
build: OpenSSL 1.0.2-beta1 24 Feb 2014
run  : OpenSSL 1.0.2-beta1 24 Feb 2014

$ grep SHLIB_M...R= Makefile
SHLIB_MAJOR=1
SHLIB_MINOR=0.0

Обновлять В OpenSSL-1.1 внесены некоторые изменения на уровне API, приведенный выше код не будет скомпилирован с заголовками v1.1 и старыми библиотеками ( undefined reference to `OpenSSL_version').

SSLeay_version()в настоящее время устарело и (в зависимости от OPENSSL_API_COMPAT) может быть #defineзаменено на соответствующую функцию API OpenSSL_version().

решение2

Путь к новой библиотеке находится в одном из файлов внутри /etc/ld.so.conf.d? Следующий запуск:-

#ldconfig -v

для перестроения кэша. Если вы быстры, вы должны увидеть новую библиотеку в длинном списке, который она выводит (или передать ее по конвейеру grepили less)

Может быть, на первом сервере путь уже был, а на втором — нет?

Связанный контент