1

I'm having problems with opening a shared library when using roslaunch.

I have a ROS package with a c++ script containing the line:

handle = dlopen("./rk4.so", RTLD_LAZY);

This shared library resides inside my ROS package. I managed to build the package with catking build, having in my CMakeLists.txt the lines

add_library(RK4 SHARED IMPORTED)
set_target_properties(RK4 PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/src/SharedLibs/rk4.so)

target_link_libraries(simulator_node
  RK4
  ${CMAKE_DL_LIBS}
  ${catkin_LIBRARIES} 
)

The problem is when I try to run my executable. Since the library is not in a folder where libraries usually are, I added the path to that folder to LD_LIBRARY_PATH and exported it. However I don't understand why I don't get the error in the title only when I use rosrun while I'm inside the exact folder in which the library is. My issue is that I want to launch that node with a launch file, but using roslaunch I get the error in the title anyway, even if I run it from inside the folder of that library.

LucaGare
  • 13
  • 3
  • Couldn't you just add [`ros::package::getPath("your_package_name")`](https://stackoverflow.com/a/67802827/9938686) to the directory in `dlopen`? – 2b-t Jun 04 '21 at 16:40
  • @2b-t what do you mean with it? Could you explain it more explicitly? (Sorry, I'm a beginner) – LucaGare Jun 06 '21 at 14:21
  • What I meant is that `dlopen` takes as a first argument the `filename`. With `ros::package::getPackage("your_package_name")` you can get the directory of your package. If your ROS package resides inside your package directory as you stated then you should be able to combine it to an absolute file path like `handle = dlopen(ros::package::getPackage("your_package_name") + "/rk4.so", RTLD_LAZY);`. I am not sure if that solves your issue as I haven't had the opportunity to test it yet. – 2b-t Jun 06 '21 at 15:35
  • Just tested it and it works if you take into consideration the conversion from `std::string` to a `char const*` (see my answer below). **I would not recommend you modifying `LD_LIBRARY_PATH` as it is an environment variable. Instead try to keep your modifications as portable as possible.** – 2b-t Jun 06 '21 at 16:48

2 Answers2

0

This code:

handle = dlopen("./rk4.so", RTLD_LAZY);

will succeed if and only if there is rk4.so in the current directory. In particular, it will ignore any LD_LIBRARY_PATH setting.

This is working as designed.

If you want dlopen to respect LD_LIBRARY_PATH, change it like so:

  handle = dlopen("rk4.so", RTLD_LAZY);

A better approach is to make above change and avoid the need to set LD_LIBRARY_PATH by using -Wl,-rpath=/dir/where/rk4.so/is/installed at link time of the application.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
0

I think the most portable way of doing so is to supply dlopen with the full path to the shared library file by using ros::package::getPath("your_package_name") as follows (and not modifying LD_LIBRARY_PATH!). This way you can easily get your package up and running on another computer!

  • Modify your node to load the shared library using the absolute path to the shared library by using the function ros::package::getPath from the ros/package.h header:

    std::string const library_path = ros::package::getPath("your_package") + "/relative/path/to/libyourlib.so";
    auto* handle = ::dlopen(library_path.c_str(), RTLD_LAZY);
    

    This for example would be a minimal working example for a node your_node :

    #include <cstdlib>
    #include <iostream>
    #include <string>
    
    #include <dlfcn.h>
    
    #include <ros/ros.h>
    #include <ros/package.h>
    
    int main (int argc, char** argv) {
      ros::init(argc, argv, "your_node");
      ros::NodeHandle n;
    
      std::string const package_path = ros::package::getPath("your_package");
      std::string const library_path = package_path + "/src/libyourlib.so";
      auto* handle = ::dlopen(library_path.c_str(), RTLD_LAZY);
    
      if (!handle) {
        std::cerr << "Error: could not load shared library!" << std::endl;
      } else {
        std::cout << "Library successfully loaded!" << std::endl;
      }
      return EXIT_SUCCESS;
    }
    
  • Modify your CMakeLists.txt to include the roslib library which contains the ros::package::getPath function:

    find_package(catkin REQUIRED COMPONENTS
      roscpp
      roslib
    )
    
    include_directories(
      ${catkin_INCLUDE_DIRS}
    )
    
    add_executable(your_node src/your_node.cpp)
    target_link_libraries(your_node ${catkin_LIBRARIES} ${CMAKE_DL_LIBS})
    
2b-t
  • 2,414
  • 1
  • 10
  • 18