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" 68 std::vector<std::string> catkinFindLib()
70 std::vector<std::string> lib_paths;
71 const char * env = std::getenv(
"CMAKE_PREFIX_PATH");
73 std::string env_catkin_prefix_paths(env);
74 std::vector<std::string> catkin_prefix_paths;
75 boost::split(catkin_prefix_paths, env_catkin_prefix_paths, boost::is_any_of(
os_pathsep));
76 BOOST_FOREACH(std::string catkin_prefix_path, catkin_prefix_paths) {
77 boost::filesystem::path path(catkin_prefix_path);
78 boost::filesystem::path lib(
"lib");
79 lib_paths.push_back((path / lib).
string());
91 std::string package, std::string base_class, std::string attrib_name,
92 std::vector<std::string> plugin_xml_paths)
93 : plugin_xml_paths_(plugin_xml_paths),
95 base_class_(base_class),
96 attrib_name_(attrib_name),
101 lowlevel_class_loader_(false)
104 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Creating ClassLoader, base = %s, address = %p",
105 base_class.c_str(),
this);
115 "Finished constructring ClassLoader, base = %s, address = %p",
116 base_class.c_str(),
this);
123 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Destroying ClassLoader, base = %s, address = %p",
134 "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.",
135 (lookup_name.c_str()), auto_load);
139 "Autoloading class library before attempting to create instance.");
145 "Attempting to create instance through low-level MultiLibraryClassLoader...");
147 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance created with object pointer = %p", obj);
151 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"CreateClassException about to be raised for class %s",
152 lookup_name.c_str());
161 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create managed instance for class %s.",
162 lookup_name.c_str());
170 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
171 lookup_name.c_str(), class_type.c_str());
175 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"boost::shared_ptr to object of real type %s created.",
181 "Exception raised by low-level multi-library class loader when attempting " 182 "to create instance of class %s.",
183 lookup_name.c_str());
188 #if __cplusplus >= 201103L 193 "Attempting to create managed (unique) instance for class %s.",
194 lookup_name.c_str());
202 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
203 lookup_name.c_str(), class_type.c_str());
207 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"std::unique_ptr to object of real type %s created.",
213 "Exception raised by low-level multi-library class loader when attempting " 214 "to create instance of class %s.",
215 lookup_name.c_str());
225 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create UNMANAGED instance for class %s.",
226 lookup_name.c_str());
235 "Attempting to create instance through low level multi-library class loader.");
237 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
238 lookup_name.c_str(), class_type.c_str());
240 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance of type %s created.", class_type.c_str());
243 "Exception raised by low-level multi-library class loader when attempting " 244 "to create UNMANAGED instance of class %s.",
245 lookup_name.c_str());
253 const std::string & package,
254 const std::string & attrib_name,
259 std::vector<std::string> paths;
266 const std::vector<std::string> & plugin_xml_paths)
274 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Entering determineAvailableClasses()...");
275 std::map<std::string, ClassDesc> classes_available;
278 for (std::vector<std::string>::const_iterator it = plugin_xml_paths.begin();
279 it != plugin_xml_paths.end(); ++it)
285 "Skipped loading plugin with error: %s.",
290 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Exiting determineAvailableClasses()...");
291 return classes_available;
298 tinyxml2::XMLDocument document;
299 document.LoadFile(package_xml_path.c_str());
300 tinyxml2::XMLElement * doc_root_node = document.FirstChildElement(
"package");
301 if (NULL == doc_root_node) {
303 "Could not find a root element for package manifest at %s.",
304 package_xml_path.c_str());
308 assert(document.RootElement() == doc_root_node);
310 tinyxml2::XMLElement * package_name_node = doc_root_node->FirstChildElement(
"name");
311 if (NULL == package_name_node) {
313 "package.xml at %s does not have a <name> tag! Cannot determine package " 314 "which exports plugin.",
315 package_xml_path.c_str());
319 return package_name_node->GetText();
326 return catkinFindLib();
331 const std::string & library_name,
332 const std::string & exporting_package_name)
342 std::vector<std::string> all_paths;
346 std::string non_debug_suffix;
347 if (debug_library_suffix) {
352 std::string library_name_with_extension = library_name + non_debug_suffix;
354 std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
358 for (
unsigned int c = 0; c < all_paths_without_extension.size(); c++) {
359 std::string current_path = all_paths_without_extension.at(c);
360 all_paths.push_back(current_path + path_separator + library_name_with_extension);
361 all_paths.push_back(current_path + path_separator + stripped_library_name_with_extension);
363 if (debug_library_suffix) {
367 current_path + path_separator + stripped_library_name +
395 return it->second.description_;
406 return it->second.derived_class_;
416 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
417 lookup_name.c_str());
421 std::string library_name = it->second.library_name_;
422 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s maps to library %s in classes_available_.",
423 lookup_name.c_str(), library_name.c_str());
425 std::vector<std::string> paths_to_try =
429 "Iterating through all possible paths where %s could be located...",
430 library_name.c_str());
431 for (std::vector<std::string>::const_iterator it = paths_to_try.begin(); it != paths_to_try.end();
434 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Checking path %s ", it->c_str());
435 if (boost::filesystem::exists(*it)) {
436 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Library %s found at explicit path %s.",
437 library_name.c_str(), it->c_str());
450 return it->second.package_;
466 std::vector<std::string> lookup_names;
468 lookup_names.push_back(it->first);
478 std::string declared_types;
480 for (
unsigned int i = 0; i < types.size(); i++) {
481 declared_types = declared_types + std::string(
" ") + types[i];
483 return "According to the loaded plugin descriptions the class " + lookup_name +
484 " with base class type " +
base_class_ +
" does not exist. Declared types are " +
493 std::vector<std::string> split;
494 boost::split(split, lookup_name, boost::is_any_of(
"/:"));
518 std::string package_name;
519 boost::filesystem::path p(plugin_xml_file_path);
520 boost::filesystem::path parent = p.parent_path();
524 if (boost::filesystem::exists(parent /
"package.xml")) {
525 std::string package_file_path = (boost::filesystem::path(parent /
"package.xml")).
string();
527 }
else if (boost::filesystem::exists(parent /
"manifest.xml")) {
528 #if BOOST_FILESYSTEM_VERSION >= 3 529 std::string
package = parent.filename().string();
531 std::string
package = parent.filename();
536 if (0 == plugin_xml_file_path.find(package_path)) {
543 parent = parent.parent_path().string();
546 if (parent.string().empty()) {
558 #if BOOST_FILESYSTEM_VERSION >= 3 559 return boost::filesystem::path(
"/").native();
561 return boost::filesystem::path(
"/").external_file_string();
572 return it->second.plugin_manifest_path_;
603 boost::filesystem::path p1(path1);
604 return (p1 / path2).string();
613 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
614 lookup_name.c_str());
619 if (
"" == library_path) {
620 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"No path could be found to the library containing %s.",
621 lookup_name.c_str());
622 std::ostringstream error_msg;
623 error_msg <<
"Could not find library corresponding to plugin " << lookup_name <<
624 ". Make sure the plugin description XML file has the correct name of the " 625 "library and that the library actually exists.";
631 it->second.resolved_library_path_ = library_path;
633 std::string error_string =
634 "Failed to load library " + library_path +
". " 635 "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the " 636 "library code, and that names are consistent between this macro and your XML. " 637 "Error string: " + ex.what();
644 const std::string & xml_file, std::map<std::string,
648 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Processing xml file %s...", xml_file.c_str());
649 tinyxml2::XMLDocument document;
650 document.LoadFile(xml_file.c_str());
651 tinyxml2::XMLElement * config = document.RootElement();
652 if (NULL == config) {
654 "XML Document '" + xml_file +
655 "' has no Root Element. This likely means the XML is malformed or missing.");
658 if (!(strcmp(config->Value(),
"library") == 0 ||
659 strcmp(config->Value(),
"class_libraries") == 0))
662 "The XML document '" + xml_file +
"' given to add must have either \"library\" or " 663 "\"class_libraries\" as the root tag");
667 if (strcmp(config->Value(),
"class_libraries") == 0) {
668 config = config->FirstChildElement(
"library");
671 tinyxml2::XMLElement * library = config;
672 while (library != NULL) {
673 std::string library_path = library->Attribute(
"path");
674 if (0 == library_path.size()) {
676 "Failed to find Path Attirbute in library element in %s", xml_file.c_str());
681 if (
"" == package_name) {
683 "Could not find package manifest (neither package.xml or deprecated " 684 "manifest.xml) at same directory level as the plugin XML file %s. " 685 "Plugins will likely not be exported properly.\n)",
689 tinyxml2::XMLElement * class_element = library->FirstChildElement(
"class");
690 while (class_element) {
691 std::string derived_class;
692 if (class_element->Attribute(
"type") != NULL) {
693 derived_class = std::string(class_element->Attribute(
"type"));
696 "Class could not be loaded. Attribute 'type' in class tag is missing.");
699 std::string base_class_type;
700 if (class_element->Attribute(
"base_class_type") != NULL) {
701 base_class_type = std::string(class_element->Attribute(
"base_class_type"));
704 "Class could not be loaded. Attribute 'base_class_type' in class tag is missing.");
707 std::string lookup_name;
708 if (class_element->Attribute(
"name") != NULL) {
709 lookup_name = class_element->Attribute(
"name");
711 "XML file specifies lookup name (i.e. magic name) = %s.",
712 lookup_name.c_str());
715 "XML file has no lookup name (i.e. magic name) for class %s, " 716 "assuming lookup_name == real class name.",
717 derived_class.c_str());
718 lookup_name = derived_class;
724 tinyxml2::XMLElement * description = class_element->FirstChildElement(
"description");
725 std::string description_str;
727 description_str = description->GetText() ? description->GetText() :
"";
729 description_str =
"No 'description' tag for this plugin in plugin description file.";
732 classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
733 ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
734 library_path, xml_file)));
738 class_element = class_element->NextSiblingElement(
"class");
740 library = library->NextSiblingElement(
"library");
748 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Refreshing declared classes.");
750 std::list<std::string> remove_classes;
751 for (std::map<std::string, ClassDesc>::const_iterator it =
classes_available_.begin();
754 std::string resolved_library_path = it->second.resolved_library_path_;
756 if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) {
757 remove_classes.push_back(it->first);
761 while (!remove_classes.empty()) {
763 remove_classes.pop_front();
769 for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
770 it != updated_classes.end(); it++)
782 std::string only_file;
784 if (std::string::npos == c) {
787 return path.substr(c, path.size());
796 if (it !=
classes_available_.end() && it->second.resolved_library_path_ !=
"UNRESOLVED") {
797 std::string library_path = it->second.resolved_library_path_;
798 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to unload library %s for class %s",
799 library_path.c_str(), lookup_name.c_str());
815 #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.
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.
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.
virtual std::string getBaseClassType() const
Given the lookup name of a class, return the type of the associated base class.
T * createUnmanagedInstance(const std::string &lookup_name)
Create an instance of a desired class.
std::vector< std::string > plugin_xml_paths_
virtual std::string getClassPackage(const std::string &lookup_name)
Given the name of a class, return name of the containing package.
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)