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",
103 getBaseClassType().c_str(),
this);
113 "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.",
114 (lookup_name.c_str()), auto_load);
116 if (auto_load && !isClassLoaded(lookup_name)) {
118 "Autoloading class library before attempting to create instance.");
119 loadLibraryForClass(lookup_name);
124 "Attempting to create instance through low-level MultiLibraryClassLoader...");
125 T * obj = lowlevel_class_loader_.createUnmanagedInstance<T>(getClassType(lookup_name));
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());
143 if (!isClassLoaded(lookup_name)) {
144 loadLibraryForClass(lookup_name);
148 std::string class_type = getClassType(lookup_name);
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());
175 if (!isClassLoaded(lookup_name)) {
176 loadLibraryForClass(lookup_name);
180 std::string class_type = getClassType(lookup_name);
181 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
182 lookup_name.c_str(), class_type.c_str());
184 UniquePtr<T> obj = lowlevel_class_loader_.createUniqueInstance<T>(class_type);
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());
207 if (!isClassLoaded(lookup_name)) {
208 loadLibraryForClass(lookup_name);
214 "Attempting to create instance through low level multi-library class loader.");
215 std::string class_type = getClassType(lookup_name);
216 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
217 lookup_name.c_str(), class_type.c_str());
218 instance = lowlevel_class_loader_.createUnmanagedInstance<T>(class_type);
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)
261 processSingleXMLPluginFile(*it, classes_available);
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;
347 std::vector<std::string> all_paths_without_extension = getCatkinLibraryPaths();
348 all_paths_without_extension.push_back(getROSBuildLibraryPath(exporting_package_name));
350 std::string non_debug_suffix;
351 if (debug_library_suffix) {
356 std::string library_name_with_extension = library_name + non_debug_suffix;
357 std::string stripped_library_name = stripAllButFileFromPath(library_name);
358 std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
360 const std::string path_separator = getPathSeparator();
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 +
383 return lowlevel_class_loader_.isClassAvailable<T>(getClassType(lookup_name));
398 if (it != classes_available_.end()) {
399 return it->second.description_;
409 if (it != classes_available_.end()) {
410 return it->second.derived_class_;
419 if (classes_available_.find(lookup_name) == classes_available_.end()) {
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 =
430 getAllLibraryPathsToTry(library_name, it->second.package_);
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());
453 if (it != classes_available_.end()) {
454 return it->second.package_;
463 return plugin_xml_paths_;
470 std::vector<std::string> lookup_names;
471 for (
ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it) {
472 lookup_names.push_back(it->first);
482 std::string declared_types;
483 std::vector<std::string> types = getDeclaredClasses();
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();
530 return extractPackageNameFromPackageXML(package_file_path);
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();
579 if (it != classes_available_.end()) {
580 return it->second.plugin_manifest_path_;
590 return lowlevel_class_loader_.getRegisteredLibraries();
604 return classes_available_.find(lookup_name) != classes_available_.end();
611 boost::filesystem::path p1(path1);
612 return (p1 / path2).string();
620 if (it == classes_available_.end()) {
621 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
622 lookup_name.c_str());
626 std::string library_path = getClassLibraryPath(lookup_name);
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.";
638 lowlevel_class_loader_.loadLibrary(library_path);
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());
701 std::string package_name = getPackageFromPluginXMLFilePath(xml_file);
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;
743 if (base_class_type == base_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();
773 it != classes_available_.end(); it++)
775 std::string resolved_library_path = it->second.resolved_library_path_;
776 std::vector<std::string> open_libs = lowlevel_class_loader_.getRegisteredLibraries();
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()) {
783 classes_available_.erase(remove_classes.front());
784 remove_classes.pop_front();
788 plugin_xml_paths_ = getPluginXmlPaths(package_, attrib_name_,
true);
789 std::map<std::string, ClassDesc> updated_classes = determineAvailableClasses(plugin_xml_paths_);
790 for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
791 it != updated_classes.end(); it++)
793 if (classes_available_.find(it->first) == classes_available_.end()) {
794 classes_available_.insert(std::pair<std::string, ClassDesc>(it->first, it->second));
803 std::string only_file;
804 size_t c = path.find_last_of(getPathSeparator());
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());
821 return unloadClassLibraryInternal(library_path);
831 return lowlevel_class_loader_.unloadLibrary(library_path);
836 #endif // PLUGINLIB__CLASS_LOADER_IMP_HPP_