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.
SHARED libraries are linked dynamically and loaded at runtime. MODULE libraries 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
|
// 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.
|
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
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
MODULEtype instead of theSHAREDtype, and that caused the built library name to beliburdf_xml_parser.soinstead ofliburdf_xml_parser.dylib.https://github.com/ros2/urdf/pull/13/files#diff-a6cb7a77ca27d5dcfb7fe4ec2004f324R52-R54
It seems like
MODULEwould be more correct for pluginlib plugins.On OSX Shared Libraries and Loadable Modules are different. Summarizing from the link above: both can be loaded through the
dyldapi, but loadable modules can't be directly linked against, and shared libraries can't be dynamically unloaded. This means it's advantageous to useMODULEin 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
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, andlib???.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
Option 3 Recommend
SHAREDinstead ofMODULEThis is what we do in practice now, but I think this is the least desirable option because
SHAREDlibraries can't be unloaded on OSX.See also:
https://stackoverflow.com/questions/2339679/what-are-the-differences-between-so-and-dylib-on-osx