-
Notifications
You must be signed in to change notification settings - Fork 104
Description
I ran into an issue on ros2/urdf#13 where pluginlib is unable to find a module on only OSX. The cause is I buit the library using the MODULE type instead of the SHARED type, and that caused the built library name to be liburdf_xml_parser.so instead of liburdf_xml_parser.dylib.
add_library(urdf_xml_parser MODULE
src/urdf_plugin.cpp
)https://github.com/ros2/urdf/pull/13/files#diff-a6cb7a77ca27d5dcfb7fe4ec2004f324R52-R54
It seems like MODULE would be more correct for pluginlib plugins.
SHAREDlibraries are linked dynamically and loaded at runtime.MODULElibraries are plugins that are not linked into other targets but may be loaded dynamically at runtime using dlopen-like functionality
On OSX Shared Libraries and Loadable Modules are different. Summarizing from the link above: both can be loaded through the dyld api, but loadable modules can't be directly linked against, and shared libraries can't be dynamically unloaded. This means it's advantageous to use MODULE in cases where one wants plugins to be unloaded. The practical difference to pluginlib is loadable modules have different file extensions on OSX. CMake creates modules with the file extension .so, but Apple apparently recommends an extension of .bundle (though I only found second hand references to this recommendation). Pluginlib should search for libraries with all of these extensions.
I can think of a few paths forward
Option 1 Embed the path in the ament index entry
pluginlib/pluginlib/include/pluginlib/class_loader_imp.hpp
Lines 371 to 373 in 7c3e7d5
| // TODO(wjwwood): probably should avoid "searching" and just embed the | |
| // relative path to the libraries in the ament index, since CMake knows it | |
| // at build time... |
This option seems preferable to me because OSX allows modules to have any file extension. If it's known at build time, then no platform specific knowledge is needed in code, and it will take less time to load the module because it's location will be known right away.
Option 2 Add std::vector<std::string> rcpptuils_get_platform_module_names()
This would be a new utility that returned lib???.so, lib???.dylib, and lib???.bundle. It would be called adjacent to the blocks below to add to the search paths.
pluginlib/pluginlib/include/pluginlib/class_loader_imp.hpp
Lines 409 to 419 in 7c3e7d5
| std::vector<std::string> all_relative_library_paths = { | |
| rcpputils::get_platform_library_name(library_name), | |
| rcpputils::get_platform_library_name(library_name_alternative), | |
| rcpputils::get_platform_library_name(stripped_library_name), | |
| rcpputils::get_platform_library_name(stripped_library_name_alternative) | |
| }; | |
| std::vector<std::string> all_relative_debug_library_paths = { | |
| rcpputils::get_platform_library_name(library_name, true), | |
| rcpputils::get_platform_library_name(library_name_alternative, true), | |
| rcpputils::get_platform_library_name(stripped_library_name, true), | |
| rcpputils::get_platform_library_name(stripped_library_name_alternative, true) |
Option 3 Recommend SHARED instead of MODULE
This is what we do in practice now, but I think this is the least desirable option because SHARED libraries can't be unloaded on OSX.
See also:
https://stackoverflow.com/questions/2339679/what-are-the-differences-between-so-and-dylib-on-osx