Joe
Joe

Reputation: 6796

Finding my Linux shared libraries at runtime

I'm porting an SDK written in C++ from Windows to Linux. There are other binaries, but at its simplest, our SDK is this:

All of my binaries must live in one folder somewhere that apps can find. I've achieved that on Windows. I wanted to achieve the same thing in Linux. I'm failing miserably

To illustrate, Here's the basic project tree. We use CMake. After I build I've got

mysdk
  |---CMakeLists.txt (has add_subdirectory() statements for "tests" and "core")
  |---/tests  (source code + CMakeLists.txt)
  |---/core   (source code + CMakeLists.txt)
  |---/build  (all build ouput, CMake output, etc)
        |---tests  (build output)
        |---core   (build output)

The goal is to "flatten" the "build" tree and put all the binary outputs of tests, core, etc into one folder.

  1. I tried adding CMake's "install" command, to each of my CMakeLists.txt files (e.g. install(TARGETS core DESTINATION bin). I then then executed sudo make install after my normal build. This put all my binaries in /usr/local/bin with no errors. But when I ran tests from there, it failed to find libcore.so, even though it was sitting right there in the same folder
tests: error while loading shared libraries: libcore.so: Cannot open shared object file: No such file or directory
  1. I read up on the LD_LIBRARY_PATH environment variable and so tried adding that folder (/usr/local/bin) into it and running. I can see I've properly altered LD_LIBRARY_PATH but it still doesn't work. "tests" still can't find libcore.so. I even tried changing the PATH environment variable as well. Same result.

  2. In frustration, I tried brute-force copying the output binaries to a temporary subfolder (of /mysdk/build) and running tests from there. To my surprise it ran. Then I realized why: Instead of loading the local copy of libcore.so it had loaded the one from the build output folder (as if the full path were "baked in" to the app at build time). Subsequently deleting that build-output copy of libcore.so made "tests" fail altogether as before, instead of loading the local copy. So maybe the path really was baked in.

I'm at a loss. I've read the CMake tutorial and reference. It makes this sound so easy. Aside from the obvious (What am I doing wrong?) I would appreciate if anyone could answer any of the following questions:

  1. What is the correct way to control where my app looks for my shared libraries?
  2. Is there a relationship between my project build structure and how my binaries must then appear when installed?
  3. Am I even close to the right way of doing this?
  4. Is it possible I've somehow inadvertently "baked" (into my app) full paths to my shared libraries? Is that a thing? I use all CMAKE variables in my CMakeLists files.

Upvotes: 0

Views: 2247

Answers (2)

mustafagonul
mustafagonul

Reputation: 1209

Updating LD_LIBRARY_PATH is an option. Another option is using RPATH. Please check the example.

https://github.com/mustafagonul/cmake-examples/blob/master/005-executable-with-shared-library/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

# Project
project(005-executable-with-shared-library)

# Directories
set(example_BIN_DIR bin)
set(example_INC_DIR include)
set(example_LIB_DIR lib)
set(example_SRC_DIR src)

# Library files
set(library_SOURCES ${example_SRC_DIR}/library.cpp)
set(library_HEADERS ${example_INC_DIR}/library.h)
set(executable_SOURCES ${example_SRC_DIR}/main.cpp)

# Setting RPATH
# See https://cmake.org/Wiki/CMake_RPATH_handling
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${example_LIB_DIR})

# Add library to project
add_library(library SHARED ${library_SOURCES})

# Include directories
target_include_directories(library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/${example_INC_DIR})

# Add executable to project
add_executable(executable ${executable_SOURCES})

# Linking
target_link_libraries(executable PRIVATE library)

# Install
install(TARGETS executable DESTINATION ${example_BIN_DIR})
install(TARGETS library DESTINATION ${example_LIB_DIR})
install(FILES ${library_HEADERS} DESTINATION ${example_INC_DIR})

Upvotes: 1

J B
J B

Reputation: 341

You can run ldd file to print the shared object dependencies for file. It will tell you where are its dependencies being read from.

You can export the environment variable LD_LIBRARY_PATH with the paths you want the linker to look for. If a dependency is not found, try adding the path where that dependency is located at to LD_LIBRARY_PATH and then run ldd again (make sure you export the variable).

Also, make sure the dependencies have the right permissions.

Upvotes: 2

Related Questions