I've been trying to upgrade some programs on an old Linux box (Debian 7.5 wheezy). I'd like to keep default system libs untouched and to add some custom builds alongside them. It works fine for most libs, only OpenSSL gives me a hard time (libssl.so + libcrypt.so).
Here is my OpenSSL configure line:
# ./config --prefix=/usr/local --openssldir=/usr/local/openssl no-gost shared zlib no-ssl2 -fPIC
Then for other programs, for example cURL:
# ./configure LDFLAGS="-L/usr/local/ssl/lib -ldl" --with-ssl --enable-shared
But then I get the wrong OpenSSL version:
# curl --version
curl 7.44.0 (x86_64-unknown-linux-gnu) libcurl/7.44.0 OpenSSL/1.0.1e
I know libssl.so has copies in the following folders on this system:
/usr/lib/libssl.so
/usr/lib/x86_64-linux-gnu/libssl.so
/usr/local/lib/libssl.so
/usr/local/ssl/lib/libssl.so
All of them are the same custom-compiled version, except /usr/lib/x86_64-linux-gnu/libssl.so which appears to be my default system lib (v1.0.5e).
I'd like to know how I can instruct configure scripts to avoid looking inside /lib/x86_64-linux-gnu?
Can I just change the /usr/lib/x86_64-linux-gnu/libssl.so symlink and point it to my builds? Is it safe?
Thanks,
Best Answer
There are two different linker operations involved, build time (used to find libraries and "symbols", performed by
ld
or equivalent), and run time (performed byld.so
) which loads libraries into process memory and performs relocations.When you use
-L
during build,ld
only confirms the libraries and required symbols (typically functions which comprise the API) are available. At run time, libraries with different paths can be used.LD_LIBRARY_PATH
,LD_PRELOAD
and RPATH (-R
or-rpath
) are some of the ways of controlling that – the last one being the way to specify this at build time (so it's a property of the binary, and less dependent on the user environment).With any library, the features, API, and ABI can change, leading to errors or instability if the linker finds or loads the "wrong" binary. Even though the symbols can match as expected (or you would get an error before execution), the wheels may come off during process execution. There are solutions to this, versioning of the library filename, and versioning of the symbols in a library, though those won't be of much use here. (A complication is that the
SHLIB_MAJOR
/SHLIB_MINOR
in all the OpenSSL 1.0.x series is "1.0.0", so those libraries cannot be readily distinguished unless you hack theMakefile
.)Curl itself checks for this kind of problem, it compares the build-time
libcurl
version to the run-time version, and may issue:A contemporary
ld
will do similar at build time when it notes potentially conflicting libraries in dependencies.For a clean build, with no run time environment trickery, you can:
libssl.so
links againstlibcrypto.so
, and install to a specific pathlibssl.so
/libcrypto.so
A cheap and nasty way to fix the problem would be to usr
chrpath
to alter the ELF RPATH in binaries after building, I don't recommend this generally, and definitely not for curl, read on.Now for the complications: curl supports lots of protocols, some of those protocols are provided via other libraries, and where the protocol supports TLS (or uses crypto functions) it will tend to also link against
libssl.so
and/orlibcrypto.so
, e.g. for LDAP and SSH. What you do not want is:where
curl
itself would use one version, butlibldap.so
may expect a different version to load; this may also fail at run-time if there's an ABI incompatibility. You can be unlucky with symbol or load ordering, and end up with two (or more!) versions of a library loaded.There are generally three ways to try to work around that:
.a
libraries for some static linking. For curl, this is not the same thing as just using--enable-static
. It can work, I've done it in the distant past, but it may not work here so I won't mention it further; and it can cause many headaches, not least with with PIC/PIE.GnuTLS can further muddy the water, though it's not a problem to use both libraries concurrently (at least, not that I've seen so far); that doesn't hold for other libraries that aim for ABI compatibility, like LibreSSL. Curl does go to some trouble to use only a single SSL library in its build (it currently supports 8, AFAIK), but it doesn't know what for example,
libssh2
might be linked against.So, depending on versions, you can try building OpenSSL and curl respectively:
(Despite documentation to the contrary,
--with-ldap=no
and--without-ldap
have no useful effect, use--enable-ldap=no
.libssh2
(for scp) is not usually on by default.)After install,
ldd /usr/local/bin/curl
should contain no surprises: exactly one reference to each of the expectedlibssl.so
andlibcrypto.so
.OpenSSL build (non-autoconf) will set the
RPATH
correctly on theopenssl
binary, but it does not set it on the libraries by default. There are platform specific variations in how libraries are located (much of the RPATH handling in the OpenSSL build is a decoy: it applies to platforms other than Linux). This might not be required for curl, but it won't cause problems.When you use autoconf's
configure
there is no guarantee that non-default library locations will result in a matching RPATH in the binaries,CFLAGS
/LDFLAGS
can usually fix that. Here though, with OpenSSL's two-step process,config
doesn't quite get along with variables likeLDFLAGS
, so add at the end of theconfig
line instead, andConfigure
handles it correctly when creating theMakefile
.You can check an ELF executable or library run-time path with:
You can debug library loading with:
(Note the original question is old, and OpenSSL 1.0.x is no longer supported officially, though distributions may vary. The instructions herein are generally applicable to building special versions of OpenSSL 1.0.x for specific purposes. Building an
stunnel
binary to reverse-proxy an old network device so that it can work with a contemporary browser is a good example. )You can find some further explanation and instructions in my answer to this question: Get ld to pick the correct library.