How to avoid 'cannot open shared object file' when using CMake?

5.5k views Asked by At

Situation

  • My project uses CMake and compiles without problems on Ubuntu 16.04.

  • When starting the compiled application I get the message cannot open shared object file.

  • All the shared object libs are available in the same non-standard folder (and I need them there).

  • For some reason some can be found, but others cannot.

What I need

  1. The reason why some shared objects can be found and others cannot be found. The project is pretty big with many CMake files. I tried to find the differences between the libs that can be loaded and the ones that can't, but without success. Any help that point me to the right place is welcome.
  2. A solution within CMake to make it find all the shared objects.

ldd

The ldd output shows me that most shared objects can be found. Here are some examples:

libboost_filesystem.so.1.55.0 => /path/to/libs/boost/lib/libboost_filesystem.so.1.55.0 (0x00007f2ed1fa0000)
libboost_filesystem.so.1.55.0 => /path/to/libs/boost/lib/libboost_filesystem.so.1.55.0 (0x00007f96af1f5000)
libboost_program_options.so.1.55.0 => /path/to/libs/boost/lib/libboost_program_options.so.1.55.0 (0x00007f96aef85000)
libboost_system.so.1.55.0 => /path/to/libs/boost/lib/libboost_system.so.1.55.0 (0x00007f96aed80000)

For some reason a few others cannot be found. For example:

libboost_iostreams.so.1.55.0 => not found
libboost_chrono.so.1.55.0 => not found

There are other non-boost libs that showing the same behavior, but for simplicity I am just showing the boost examples.

Workarounds already tried

Below are the workarounds that already work successfully. But I am really interested in the two points in the What I need section.

1

There are 1 answers

0
johnb003 On

tldr; Check that the imported library is imported as SHARED or UNKNOWN and not STATIC, and has an IMPORTED_SONAME property.

You should check how the library is being imported that you're linking.

I've analyzed a few of the config mode exported targets for static and dynamic libraries, and they are a little different in the properties they set for the target.

For example for zlib, here's the version for static libraries:

add_library(ZLIB::zlibstatic STATIC IMPORTED)
set_target_properties(ZLIB::zlibstatic PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "C"
  IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libz.a"
)

However, for dynamic libraries it's:

add_library(ZLIB::zlib SHARED IMPORTED)
set_target_properties(ZLIB::zlib PROPERTIES
  IMPORTED_LOCATION_NOCONFIG "${_IMPORT_PREFIX}/lib/libz.so.1.2.11"
  IMPORTED_SONAME_NOCONFIG "libz.so.1"
)

In a find_package module mode script, you might think you're importing a static library, when in fact the found library is a .so, so it may use the incorrect target properties. In config mode this is not likely because it's much more explicit when defining the target. Though, module mode (cmake/findXXX.cmake), you're often defining these properties as a result of FIND_PACKAGE_HANDLE_STANDARD_ARGS _LIBRARIES variable, and it's hard to tell what you're going to get. You can use libFoo.a in the search to be more explicit or playing with CMAKE_FIND_LIBRARY_SUFFIXES.