Reputation: 76
Can someone shed some light on what is the best practice for loading plugins into a C++ Linux program?
Say we have a program (editor) with a plugin (libsyntax.so). The config file for editor contains the path to the libsyntax.so library (plugin1=/opt/editor/gizmos/libsyntax.so). The editor reads the config then calls:
void* library = dlopen(path, RTLD_NOW|RTLD_GLOBAL);
MYFUN* function = (MYFUN*)dlsym(library, "function");
All is fine, stuff works.
Now let us assume that (libsyntax.so) depends on a helper library (libcolor.so). When we run readelf we get:
readelf -d libsyntax.so
Dynamic section at offset 0x12b6b48 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libcolor.so]
...
However at this point the above dlopen() fails and the error is "No such file or directory". Using LD_DEBUG=all reveals that after libsyntax.so is loaded, messages are:
28664: file=libcolor.so [0]; needed by /home/.../libsyntax.so [0]
28664: find library=libcolor.so [0]; searching
28664: search cache=/etc/ld.so.cache
28664: search path=/lib64/tls/x86_64:/lib64/tls:...:/usr/lib64 (system search path)
28664: trying file=/lib64/tls/x86_64/libcolor.so
... and so on
The loader/linker is looking in standard places and, obviously, not finding my dependency. This can be easily taken care of by ldconfig or LD_LIBRARY_PATH but both solutions feel dirty.
Is there a clean way to load both the plugin and dependencies? How are you doing this?
Upvotes: 3
Views: 1925
Reputation: 8573
Persinally, I think that LD_LIBARY_PATH is your friend here. Just define, as the definition for the plugin interface, where libraries the plugin needs should be located, and make sure, in your program, to set the LD_LIBARY_PATH to that location.
Simply setting it before calling dlopen should be enough for the library to load. No other change is needed in the program, and no special linking of the plugin itself.
Upvotes: 0
Reputation: 1984
A clean way to ensure dependencies are found, is to set the run-time search path (RPATH) during linking of the program and its plugins to a sensible location, where the dependencies can be found.
If the rpath was set for a binary (which you can see with readelf
), the linker will use the additional paths listed there besides the default system locations, and LD_LIBRARY_PATH
.
Additionally, there's a special variable, $ORIGIN
, which is always resolved to the location of the current binary during runtime, and you can set paths relative to that!
For example, if your application's root path (that contains the main executable) is /opt/editor
, the plugins are under /opt/editor/gizmos
, and let's say you have another folder, /opt/editor/lib
with additional dependencies, you might use the linker options:
# editor executable
-Wl,-rpath=$ORIGIN/lib
# plugins
-Wl,-rpath=$ORIGIN/../lib,-rpath=$ORIGIN
Upvotes: 1