4
votes

My program uses plugins, that are loaded dynamically with dlopen(). The locations of these plugins can be arbitrary, so they aren't necessarily in the library path. In some cases, one plugin needs to depend on another plugin. So if A and B are dynamic libraries, I'll first load A, then load B which uses symbols defined in A.

My reading of the dlopen() documentation implies that if I specify RTLD_GLOBAL this should all work. But it doesn't. When I call dlopen() on the second library, it fails with an error saying it couldn't find the first one (which had already been loaded with dlopen()):

Error loading library /usr/local/openmm/lib/plugins/libOpenMMRPMDOpenCL.dylib: dlopen(/usr/local/openmm/lib/plugins/libOpenMMRPMDOpenCL.dylib, 9): Library not loaded: libOpenMMOpenCL.dylib
Referenced from: /usr/local/openmm/lib/plugins/libOpenMMRPMDOpenCL.dylib
Reason: image not found

How can I make this work?

1
What does ldd output on both libraries look like? - sarnold
Did you link the main program and each shared library with -rdynamic ? - Basile Starynkevitch
I think -rdynamic is being specified, though I'm not certain - I'm building with CMake, which has its own set of options for building libraries. In any case, I don't think that's the problem. The error doesn't complain about missing symbols, but rather about not being able to find a library. And yes, ldd (or otool on a Mac) reports that library as a dependency. Perhaps that's the problem. Is there a way to make the plugin not specifically require that library, but still use symbols defined in it? - peastman
At least on Linux, you can build a shared library by linking it to another one... ldd /usr/lib/libgtksourceviewmm-3.0.so gives 58 dependencies (i.e. other shared libraries linked by libgtksourceviewmm-3.0.so). - Basile Starynkevitch

1 Answers

1
votes

See this answer here: dlopen() error image not found

If you modify the library to have an install name of @rpath/blah.dylib, you'll be able to do this.

Edit:

I'm also using cmake, use this:

set_target_properties(${MY_LIB} PROPERTIES BUILD_WITH_INSTALL_RPATH 1 INSTALL_NAME_DIR "@rpath")

This doesn't break things on other platforms either, but make sure you haven't called CMAKE_SKIP_RPATH or it won't be invoked.