37 #ifndef PLUGINLIB__CLASS_LOADER_IMP_HPP_ 38 #define PLUGINLIB__CLASS_LOADER_IMP_HPP_ 50 #include "boost/algorithm/string.hpp" 51 #include "boost/bind.hpp" 52 #include "boost/filesystem.hpp" 53 #include "boost/foreach.hpp" 70 std::string package, std::string base_class, std::string attrib_name,
71 std::vector<std::string> plugin_xml_paths)
72 : plugin_xml_paths_(plugin_xml_paths),
74 base_class_(base_class),
75 attrib_name_(attrib_name),
80 lowlevel_class_loader_(false)
83 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Creating ClassLoader, base = %s, address = %p",
84 base_class.c_str(),
this);
94 "Finished constructring ClassLoader, base = %s, address = %p",
95 base_class.c_str(),
this);
102 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Destroying ClassLoader, base = %s, address = %p",
113 "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.",
114 (lookup_name.c_str()), auto_load);
118 "Autoloading class library before attempting to create instance.");
124 "Attempting to create instance through low-level MultiLibraryClassLoader...");
126 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance created with object pointer = %p", obj);
130 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"CreateClassException about to be raised for class %s",
131 lookup_name.c_str());
140 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create managed instance for class %s.",
141 lookup_name.c_str());
149 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
150 lookup_name.c_str(), class_type.c_str());
154 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"boost::shared_ptr to object of real type %s created.",
160 "Exception raised by low-level multi-library class loader when attempting " 161 "to create instance of class %s.",
162 lookup_name.c_str());
167 #if __cplusplus >= 201103L 172 "Attempting to create managed (unique) instance for class %s.",
173 lookup_name.c_str());
181 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
182 lookup_name.c_str(), class_type.c_str());
186 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"std::unique_ptr to object of real type %s created.",
192 "Exception raised by low-level multi-library class loader when attempting " 193 "to create instance of class %s.",
194 lookup_name.c_str());
204 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create UNMANAGED instance for class %s.",
205 lookup_name.c_str());
214 "Attempting to create instance through low level multi-library class loader.");
216 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
217 lookup_name.c_str(), class_type.c_str());
219 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance of type %s created.", class_type.c_str());
222 "Exception raised by low-level multi-library class loader when attempting " 223 "to create UNMANAGED instance of class %s.",
224 lookup_name.c_str());
232 const std::string & package,
233 const std::string & attrib_name,
238 std::vector<std::string> paths;
245 const std::vector<std::string> & plugin_xml_paths)
253 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Entering determineAvailableClasses()...");
254 std::map<std::string, ClassDesc> classes_available;
257 for (std::vector<std::string>::const_iterator it = plugin_xml_paths.begin();
258 it != plugin_xml_paths.end(); ++it)
264 "Skipped loading plugin with error: %s.",
269 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Exiting determineAvailableClasses()...");
270 return classes_available;
277 tinyxml2::XMLDocument document;
278 document.LoadFile(package_xml_path.c_str());
279 tinyxml2::XMLElement * doc_root_node = document.FirstChildElement(
"package");
280 if (NULL == doc_root_node) {
282 "Could not find a root element for package manifest at %s.",
283 package_xml_path.c_str());
287 assert(document.RootElement() == doc_root_node);
289 tinyxml2::XMLElement * package_name_node = doc_root_node->FirstChildElement(
"name");
290 if (NULL == package_name_node) {
292 "package.xml at %s does not have a <name> tag! Cannot determine package " 293 "which exports plugin.",
294 package_xml_path.c_str());
298 const char* package_name_node_txt = package_name_node->GetText();
299 if (NULL == package_name_node_txt) {
301 "package.xml at %s has an invalid <name> tag! Cannot determine package " 302 "which exports plugin.",
303 package_xml_path.c_str());
307 return package_name_node_txt;
314 std::vector<std::string> lib_paths;
315 const char * env = std::getenv(
"CMAKE_PREFIX_PATH");
317 std::string env_catkin_prefix_paths(env);
318 std::vector<std::string> catkin_prefix_paths;
319 boost::split(catkin_prefix_paths, env_catkin_prefix_paths, boost::is_any_of(
os_pathsep));
320 BOOST_FOREACH(std::string catkin_prefix_path, catkin_prefix_paths) {
321 boost::filesystem::path path(catkin_prefix_path);
323 boost::filesystem::path bin(
"bin");
324 lib_paths.push_back((path / bin).
string());
326 boost::filesystem::path lib(
"lib");
327 lib_paths.push_back((path / lib).
string());
335 const std::string & library_name,
336 const std::string & exporting_package_name)
346 std::vector<std::string> all_paths;
350 std::string non_debug_suffix;
351 if (debug_library_suffix) {
356 std::string library_name_with_extension = library_name + non_debug_suffix;
358 std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
362 for (
unsigned int c = 0; c < all_paths_without_extension.size(); c++) {
363 std::string current_path = all_paths_without_extension.at(c);
364 all_paths.push_back(current_path + path_separator + library_name_with_extension);
365 all_paths.push_back(current_path + path_separator + stripped_library_name_with_extension);
367 if (debug_library_suffix) {
371 current_path + path_separator + stripped_library_name +
399 return it->second.description_;
410 return it->second.derived_class_;
420 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
421 lookup_name.c_str());
425 std::string library_name = it->second.library_name_;
426 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s maps to library %s in classes_available_.",
427 lookup_name.c_str(), library_name.c_str());
429 std::vector<std::string> paths_to_try =
433 "Iterating through all possible paths where %s could be located...",
434 library_name.c_str());
435 for (std::vector<std::string>::const_iterator it = paths_to_try.begin(); it != paths_to_try.end();
438 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Checking path %s ", it->c_str());
439 if (boost::filesystem::exists(*it)) {
440 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Library %s found at explicit path %s.",
441 library_name.c_str(), it->c_str());
454 return it->second.package_;
470 std::vector<std::string> lookup_names;
472 lookup_names.push_back(it->first);
482 std::string declared_types;
484 for (
unsigned int i = 0; i < types.size(); i++) {
485 declared_types = declared_types + std::string(
" ") + types[i];
487 return "According to the loaded plugin descriptions the class " + lookup_name +
488 " with base class type " +
base_class_ +
" does not exist. Declared types are " +
497 std::vector<std::string> split;
498 boost::split(split, lookup_name, boost::is_any_of(
"/:"));
522 std::string package_name;
523 boost::filesystem::path p(plugin_xml_file_path);
524 boost::filesystem::path parent = p.parent_path();
528 if (boost::filesystem::exists(parent /
"package.xml")) {
529 std::string package_file_path = (boost::filesystem::path(parent /
"package.xml")).
string();
531 }
else if (boost::filesystem::exists(parent /
"manifest.xml")) {
532 #if BOOST_FILESYSTEM_VERSION >= 3 533 std::string
package = parent.filename().string();
535 std::string
package = parent.filename();
540 if (0 == plugin_xml_file_path.find(package_path)) {
547 parent = parent.parent_path().string();
550 if (parent.string().empty()) {
562 #if BOOST_FILESYSTEM_VERSION >= 3 564 return boost::filesystem::path(
"/").string();
566 return boost::filesystem::path(
"/").native();
569 return boost::filesystem::path(
"/").external_file_string();
580 return it->second.plugin_manifest_path_;
611 boost::filesystem::path p1(path1);
612 return (p1 / path2).string();
621 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
622 lookup_name.c_str());
627 if (
"" == library_path) {
628 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"No path could be found to the library containing %s.",
629 lookup_name.c_str());
630 std::ostringstream error_msg;
631 error_msg <<
"Could not find library corresponding to plugin " << lookup_name <<
632 ". Make sure the plugin description XML file has the correct name of the " 633 "library and that the library actually exists.";
639 it->second.resolved_library_path_ = library_path;
641 std::string error_string =
642 "Failed to load library " + library_path +
". " 643 "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the " 644 "library code, and that names are consistent between this macro and your XML. " 645 "Error string: " + ex.what();
652 const std::string & xml_file, std::map<std::string,
656 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Processing xml file %s...", xml_file.c_str());
657 tinyxml2::XMLDocument document;
658 document.LoadFile(xml_file.c_str());
659 tinyxml2::XMLElement * config = document.RootElement();
660 if (NULL == config) {
662 "XML Document '" + xml_file +
663 "' has no Root Element. This likely means the XML is malformed or missing.");
666 const char* config_value = config->Value();
667 if (NULL == config_value) {
669 "XML Document '" + xml_file +
670 "' has an invalid Root Element. This likely means the XML is malformed or missing.");
673 if (!(strcmp(config_value,
"library") == 0 ||
674 strcmp(config_value,
"class_libraries") == 0))
677 "The XML document '" + xml_file +
"' given to add must have either \"library\" or " 678 "\"class_libraries\" as the root tag");
682 if (strcmp(config_value,
"class_libraries") == 0) {
683 config = config->FirstChildElement(
"library");
686 tinyxml2::XMLElement * library = config;
687 while (library != NULL) {
688 const char* path = library->Attribute(
"path");
691 "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
694 std::string library_path(path);
695 if (0 == library_path.size()) {
697 "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
702 if (
"" == package_name) {
704 "Could not find package manifest (neither package.xml or deprecated " 705 "manifest.xml) at same directory level as the plugin XML file %s. " 706 "Plugins will likely not be exported properly.\n)",
710 tinyxml2::XMLElement * class_element = library->FirstChildElement(
"class");
711 while (class_element) {
712 std::string derived_class;
713 if (class_element->Attribute(
"type") != NULL) {
714 derived_class = std::string(class_element->Attribute(
"type"));
717 "Class could not be loaded. Attribute 'type' in class tag is missing.");
720 std::string base_class_type;
721 if (class_element->Attribute(
"base_class_type") != NULL) {
722 base_class_type = std::string(class_element->Attribute(
"base_class_type"));
725 "Class could not be loaded. Attribute 'base_class_type' in class tag is missing.");
728 std::string lookup_name;
729 if (class_element->Attribute(
"name") != NULL) {
730 lookup_name = class_element->Attribute(
"name");
732 "XML file specifies lookup name (i.e. magic name) = %s.",
733 lookup_name.c_str());
736 "XML file has no lookup name (i.e. magic name) for class %s, " 737 "assuming lookup_name == real class name.",
738 derived_class.c_str());
739 lookup_name = derived_class;
745 tinyxml2::XMLElement * description = class_element->FirstChildElement(
"description");
746 std::string description_str;
748 description_str = description->GetText() ? description->GetText() :
"";
750 description_str =
"No 'description' tag for this plugin in plugin description file.";
753 classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
754 ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
755 library_path, xml_file)));
759 class_element = class_element->NextSiblingElement(
"class");
761 library = library->NextSiblingElement(
"library");
769 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Refreshing declared classes.");
771 std::list<std::string> remove_classes;
772 for (std::map<std::string, ClassDesc>::const_iterator it =
classes_available_.begin();
775 std::string resolved_library_path = it->second.resolved_library_path_;
777 if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) {
778 remove_classes.push_back(it->first);
782 while (!remove_classes.empty()) {
784 remove_classes.pop_front();
790 for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
791 it != updated_classes.end(); it++)
803 std::string only_file;
805 if (std::string::npos == c) {
808 return path.substr(c, path.size());
817 if (it !=
classes_available_.end() && it->second.resolved_library_path_ !=
"UNRESOLVED") {
818 std::string library_path = it->second.resolved_library_path_;
819 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to unload library %s for class %s",
820 library_path.c_str(), lookup_name.c_str());
836 #endif // PLUGINLIB__CLASS_LOADER_IMP_HPP_ virtual std::string getClassType(const std::string &lookup_name)
Given the lookup name of a class, return the type of the derived class associated with it...
virtual std::string getPluginManifestPath(const std::string &lookup_name)
Given the name of a class, return the path of the associated plugin manifest.
ClassLoader::UniquePtr< Base > createUniqueInstance(const std::string &class_name)
std::map< std::string, ClassDesc > determineAvailableClasses(const std::vector< std::string > &plugin_xml_paths)
Return the available classes.
const std::string os_pathsep(":")
Thrown when pluginlib is unable to instantiate a class loader.
class_loader::MultiLibraryClassLoader lowlevel_class_loader_
std::string getPathSeparator()
Get the standard path separator for the native OS (e.g. "/" on *nix, "\" on Windows).
std::string getPackageFromPluginXMLFilePath(const std::string &path)
Get the package name from a path to a plugin XML file.
std::string getROSBuildLibraryPath(const std::string &exporting_package_name)
Given a package name, return the path where rosbuild thinks plugins are installed.
virtual int unloadLibraryForClass(const std::string &lookup_name)
Decrement the counter for the library containing a class with a given name.
virtual std::string getClassDescription(const std::string &lookup_name)
Given the lookup name of a class, return its description.
boost::shared_ptr< T > createInstance(const std::string &lookup_name)
Create an instance of a desired class.
T * createClassInstance(const std::string &lookup_name, bool auto_load=true)
Create an instance of a desired class, optionally loading the associated library too.
int unloadLibrary(const std::string &library_path)
virtual void loadLibraryForClass(const std::string &lookup_name)
Attempt to load the library containing a class with a given name.
virtual std::string getClassLibraryPath(const std::string &lookup_name)
Given the name of a class, return the path to its associated library.
T * createUnmanagedInstance(const std::string &lookup_name)
Create an instance of a desired class.
std::vector< std::string > plugin_xml_paths_
virtual std::string getBaseClassType() const
Given the lookup name of a class, return the type of the associated base class.
virtual std::string getClassPackage(const std::string &lookup_name)
Given the name of a class, return name of the containing package.
CLASS_LOADER_PUBLIC std::string systemLibrarySuffix()
bool isClassLoaded(const std::string &lookup_name)
Check if the library for a given class is currently loaded.
std::string extractPackageNameFromPackageXML(const std::string &package_xml_path)
Open a package.xml file and extract the package name (i.e. contents of <name> tag).
std::map< std::string, ClassDesc >::iterator ClassMapIterator
#define ROS_DEBUG_NAMED(name,...)
Storage for information about a given class.
void loadLibrary(const std::string &library_path)
Thrown when pluginlib is unable to unload the library associated with a given plugin.
virtual void refreshDeclaredClasses()
Refresh the list of all available classes for this ClassLoader's base class type. ...
std::string joinPaths(const std::string &path1, const std::string &path2)
Join two filesystem paths together utilzing appropriate path separator.
std::vector< std::string > getDeclaredClasses()
Return a list of all available classes for this ClassLoader's base class type.
std::vector< std::string > getAllLibraryPathsToTry(const std::string &library_name, const std::string &exporting_package_name)
Get a list of paths to try to find a library.
std::vector< std::string > getCatkinLibraryPaths()
Return the paths where libraries are installed according to the Catkin build system.
std::vector< std::string > getRegisteredLibraries()
virtual std::vector< std::string > getRegisteredLibraries()
Return the libraries that are registered and can be loaded.
Thrown when pluginlib is unable to load a plugin XML file.
virtual std::string getName(const std::string &lookup_name)
Strip the package name off of a lookup name.
ROSLIB_DECL std::string getPath(const std::string &package_name)
ROSLIB_DECL void getPlugins(const std::string &package, const std::string &attribute, V_string &plugins, bool force_recrawl=false)
std::vector< std::string > getPluginXmlPaths()
Return a list of all available plugin manifest paths for this ClassLoader's base class type...
std::string stripAllButFileFromPath(const std::string &path)
Strip all but the filename from an explicit file path.
ClassLoader(std::string package, std::string base_class, std::string attrib_name=std::string("plugin"), std::vector< std::string > plugin_xml_paths=std::vector< std::string >())
#define ROS_ERROR_NAMED(name,...)
A class to help manage and load classes.
Thrown when pluginlib is unable to load the library associated with a given plugin.
virtual bool isClassAvailable(const std::string &lookup_name)
Check if the class associated with a plugin name is available to be loaded.
std::map< std::string, ClassDesc > classes_available_
int unloadClassLibraryInternal(const std::string &library_path)
Helper function for unloading a shared library.
Thrown when pluginlib is unable to create the class associated with a given plugin.
boost::shared_ptr< Base > createInstance(const std::string &class_name)
std::string getErrorStringForUnknownClass(const std::string &lookup_name)
Return an error message for an unknown class.
void processSingleXMLPluginFile(const std::string &xml_file, std::map< std::string, ClassDesc > &class_available)
Parse a plugin XML file.
bool isClassAvailable(const std::string &class_name)
Base * createUnmanagedInstance(const std::string &class_name)