3

I use CMake and Ninja to build a test executable of mine written in C++. I use gcc 4.8. I'm on Ubuntu 14.

I run CMake to configure the ninja build scripts, then I run ninja to build. I specify the libcrypto.so and other openssl *.so files as target dependencies in the CMake script.

When running the executable, I get the following error:

error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared object file: No such file or directory

I have my libcrypto.so file sitting right next to the test executable:

-rw-r--r-- 1 robert domain users 1796847 Apr 20 15:43 libboost_wave.so
-rw-r--r-- 1 robert domain users  410916 Apr 20 15:43 libboost_wserialization.so
-rw-r--r-- 1 robert domain users 2251519 Apr 21 11:28 libcrypto.so
-rw-r--r-- 1 robert domain users  701627 Apr 20 15:43 libEGL.so
-rw-r--r-- 1 robert domain users 4255871 Apr 20 15:43 libGLES_CM.so
-rw-r--r-- 1 robert domain users 7550551 Apr 20 15:43 libGLESv2.so
-rw-r--r-- 1 robert domain users  949113 Apr 17 14:34 libsqlite.so
-rw-r--r-- 1 robert domain users  496298 Apr 21 11:28 libssl.so
-rwxr-xr-x 1 robert domain users 3099250 Apr 21 11:30 Test_UI_String*

(The executable I'm running is named Test_UI_String)

CMake is setup to output shared libraries right next to executables because on other platforms like Windows (where I am most familiar with development) the DLL files need to be right next to the EXE for it to be found and loaded.

I'm confused about why it has appended 1.0.0 to the end of the library file. It should be looking for it without a version number at the end, since when I linked the dependency it had the same name as libcrypto.so does now in the directory shown above.

I'd like to better understand the behavior here, however my main question is basically about how to get this working as intended (Find the library dependencies that are located in the same directory as the executable).

  • Did you test ldconfig? – PersianGulf Apr 22 '15 at 1:03
  • @mohsen Test it how? – void.pointer Apr 22 '15 at 12:14
  • ldconfig yourdir – PersianGulf Apr 22 '15 at 14:29
1

When the linker generates an executable (or another shared library), it searches for libraries requested using -l by prefixing lib and suffixing .so to the name. For example, if you ask for -lcrypto then it searches for libcrypto.so.

Once the library has been found, the linker reads a piece of metadata from the library called its soname. The soname then gets recorded into the executable being built, and that's the name that will be used in order to search for the same library again at run time. The soname can of course be different from the name under which the library was actually found at link time.

The use case for this feature is the ability to have multiple different, incompatible versions of a library installed on the system at the same time. Here is how it is generally used.

First, let me describe what would happen in the absence of this convention:

The development headers (.h files) are coupled to a specific version of the library, and the .so file contains that version too:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so

An application myapp has been compiled against this version of the library and it loads /usr/lib/libmylibrary.so at run time.

Later, the library gets upgraded to a new version. Both the .h and .so file are replaced with the new version. Unfortunately, the new version has an incompatible ABI.

Now, when myapp is executed, it crashes or exhibits undefined behaviour because it was compiled against one version with one ABI but it loaded a different version at run time.

What happens with the soname convention:

The library is installed as follows:

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.1
/usr/lib/libmylibrary.so.1

And /usr/lib/libmylibrary.so.1 has embedded within it the soname libmylibrary.so.1.

When myapp is built, it locates /usr/lib/libmylibrary.so but the linker follows the symlink and actually loads /usr/lib/libmylibrary.so.1. Furthermore, the soname libmylibrary.so.1 is what actually gets recorded inside myapp. At run time, myapp loads /usr/lib/libmylibrary.so.1 directly, bypassing the symlink.

Later, the library gets upgraded to a new version with an incompatible ABI. Both the .h and .so file are replaced with the new version. A new file libmylibrary.so.2 appears. The libmylibrary.so.1 from the old version is left alone.

/usr/include/mylibrary.h
/usr/lib/libmylibrary.so -> libmylibrary.so.2
/usr/lib/libmylibrary.so.1
/usr/lib/libmylibrary.so.2

Now, when myapp is executed, is continues to load libmylibrary.so.1 and still functions as expected. But if other new apps are installed or myapp itself is recompiled, the symlink will be followed and the new version will be used.


The issue you are seeing is that when your application was linked, the linker found a library which had the soname libcrypto.so.1.0.0 inside it.

Was your copy of libcrypto.so generated with an soname if libcrypto.so.1.0.0?

Another possibility, quite likely here, is that your copy of libcrypto.so does not have an soname in it, but the linker actually found and used the system version of libcrypto.so (from OpenSSL) and that's where it got the soname.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.