Ich versuche, ein Programm zu kompilieren prog
und es mit der Betaversion 1.0.2 von OpenSSL zu verknüpfen, die aus den Quellen erstellt und in installiert wurde /usr/local/ssl-1.0.2
. Auf einem älteren System mit 0.9.8 funktioniert dies ohne allzu große Probleme. Auf einem neueren System mit installierter Version 1.0.1 ist dies etwas aufwändiger. Ich frage mich, warum.
1) Unter Ubuntu 10.04 mit OpenSSL 0.9.8:
Hier sind die Schritte, die ich zum Kompilieren und Verknüpfen mit 1.0.2 befolge.
$ ./config shared --openssldir=/usr/local/ssl-1.0.2 && make && make install
$ ldconfig
$ ldconfig -p | grep libcrypto
=> Es werden nur 0.9.8-Dateien angezeigt, also füge ich den Pfad zu den 1.0.2-Dateien hinzu …
$ 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
Und so kann ich kompilieren 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)
... und es ist korrekt mit 1.0.2 verknüpft.
2) Unter Debian Wheezy mit OpenSSL 1.0.1:
Dieselben Schritte, anderes Ergebnis.
$ ./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
Ebenso füge ich den Pfad zu 1.0.2 hinzu...
$ 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
Dann versuche ich zu kompilieren...
$ 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)
Aber hier ist es nicht mit 1.0.2 verknüpft. Der Bibliothekspfad zur Kompilierungszeit ist korrekt (angegeben mit -L
, gcc
würde andernfalls fehlschlagen, da einige in verwendete Funktionen prog
spezifisch für 1.0.2 sind), aber nicht der zur Laufzeit.
3) Wie man es auf Wheezy zum Laufen bringt
Mit oder ohne Laufen 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)
Alternativ können Sie export LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
vor dem Ausführen ausführen gcc
.
Was ich gerne wissen würde
Ich habe die von mr.spuratic vorgeschlagenen Schritte ausgeführt und LD_DEBUG=libs ./prog
festgestellt, dass die Pfade in nachgeschlagen wurden /etc/ld.so.cache
. Ich habe die Datei geöffnet und festgestellt, dass die Reihenfolge, in der .so nachgeschlagen werden, der Ausgabe von entspricht ldconfig -p
.
Die eigentliche Frage ist also:
- Warum steht die Datei 1.0.2 in 1) ganz oben auf der Liste von ldconfig, aber nicht in 2)? Reiner Zufall? Verwirrung, weil die Dateien 1.0.1 und 1.0.2 das gleiche Suffix haben? ("1.0.0")
Oder anders gesagt,
- Warum sind die in 3) hinzugefügten Flags in 1) nicht erforderlich?
Antwort1
Beim Kompilieren/Linken mit einem nicht standardmäßigen Paket müssen Sie drei Dinge beachten:
- Header (normalerweise
CFLAGS
) - Bibliothekspfad zur Kompilierungszeit (normalerweise
LDFLAGS
) - Laufzeitbibliothekspfad (rPfadüber
LDFLAGS
,LD_RUN_PATH
,LD_LIBRARY_PATH
oderld.so.conf
)
Sie haben nicht gesagt, was prog
es ist, also kann ich nicht sagen, wie gut sich die Konfiguration verhält (oder ob es Autoconf verwendet?). Ich habe viele gesehen, die nur die ersten beiden Schritte zuverlässig ausführen.
Während der Verknüpfungsphase ist die Reihenfolge der Bibliothekspfade relevant. Vorausgesetzt, Sie verwenden die GNU-Toolchain (gcc und binutils), können Sie wahrscheinlich sehen, was passiert, indem Sie CFLAGS
vorher configure
(oder möglicherweise direkt Makefile
) Folgendes festlegen:
export CFLAGS="-Wl,-t"
Dadurch wird die -t
Trace-Option an den Linker übergeben. Möglicherweise müssen Sie dem Make-Befehl V=1
oder hinzufügen VERBOSE=1
, wenn Sie während des Make-Befehls nur knappe „CC“- und „LD“-Zeilen als Ausgabe erhalten.)
Zur Laufzeit können Sie sehen, was ld.so
versucht wird, indem Sie sorgfältig einstellen LD_DEBUG
, zB
LD_DEBUG=libs ./myprog
(oder versuchen Sie es mit den Werten files
oder symbols
für weitere Einzelheiten)
Um alle drei Parameter zur Build-Zeit korrekt anzugeben, sollten Sie in der Lage sein, Folgendes zu tun:
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"
dann neu konfigurieren/neu kompilieren.
Sie verwenden --openssldir
anstelle der konventionelleren Version --prefix
(ich empfehle letztere und auch nur, make install_sw
wenn Sie die etwa 1000 Manpages und Symlinks, die Ihnen eine Standardinstallation bietet, nicht benötigen). Dies kann Teil des Problems sein. Aus irgendeinem Grund ist bekannt, dass die von Ihnen angezeigten .so-Bibliotheken ld.so
kein Versionssuffix haben (z. B. .so.1.0.2
), ein richtiges " make install
" hätte dies für Sie einrichten sollen (über das link-shared
Ziel im Haupt- Makefile
).
Die -R
Option weist den Linker an, einen RPATH in die ausführbare Ausgabe für die spezifische OpenSSL-Bibliothek einzubetten, sodass er nicht auf den Standard angewiesen ist, den der Runtime-Linker ( ld.so
) normalerweise bereitstellen würde. Sie können vorhandene Binärdateien ändern mitchrpath
stattdessen.
Dies entspricht mehr oder weniger dem Exportieren LD_LIBRARY_PATH=/usr/local/ssl-1.0.2/lib
. Weitere Informationen zu RPATH und dem zugehörigen RUNPATH finden Sie hier:http://blog.tremily.us/posts/rpath/
Als letzten Ausweg könnten Sie OpenSSL möglicherweise ohne „shared“ oder mit „noshared“ erstellen. Dadurch erhalten Sie statische Bibliotheken, die dieses Problem nicht haben (aber möglicherweise andere Probleme haben, z. B. bei der Verwendung innerhalb von ELF .so, was zu PIC/PIE-Problemen führt).
Basierend auf den aktualisierten Details glaube ich, dass das Problem darin liegt, dass 1.0.1 und 1.0.2beta beide das .so-Versionssuffix (SONAME) auf 1.0.0 setzen. Auf dem ersten System mit nur 0.9.8 verursacht dies keine Probleme; auf dem zweiten mit 1.0.1 und 1.0.2, beide als 1.0.0 versioniert, gilt aufgrund der ld.so.{conf,d}
Reihenfolge „das erste Match gewinnt“. Denken Sie daran, dass ld
der Linker zur Kompilierungszeit ein anderes Programm ist als ld.so
der Linker zur Laufzeit und ein anderes Verhalten aufweisen kann (was normalerweise zu Symbolfehlern oder Schlimmerem führt, wie Sie gesehen haben).
$ 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
Aktualisieren
OpenSSL-1.1 hat einige Änderungen auf API-Ebene vorgenommen; der obige Code kann mit v1.1-Headern und älteren Bibliotheken () nicht kompiliert werden undefined reference to `OpenSSL_version'
.
SSLeay_version()
ist mittlerweile veraltet und OPENSSL_API_COMPAT
kann (abhängig von ) mit #define
-d auf die richtige API-Funktion gesetzt werden OpenSSL_version()
.
Antwort2
Befindet sich der Pfad der neuen Bibliothek in einer der darin enthaltenen Dateien /etc/ld.so.conf.d
? Nächster Lauf:-
#ldconfig -v
um den Cache neu zu erstellen. Wenn Sie schnell sind, sollten Sie die neue Bibliothek in der langen Liste sehen, die sie ausgibt (oder sie an grep
oder weiterleiten less
).
Vielleicht war der Pfad bereits auf dem ersten Server vorhanden, aber nicht auf dem zweiten?