37 #ifndef PLUGINLIB__CLASS_LOADER_IMP_HPP_
38 #define PLUGINLIB__CLASS_LOADER_IMP_HPP_
50 #include "boost/algorithm/string.hpp"
51 #include "boost/filesystem.hpp"
52 #include "boost/foreach.hpp"
69 std::string package, std::string base_class, std::string attrib_name,
70 std::vector<std::string> plugin_xml_paths)
71 : plugin_xml_paths_(plugin_xml_paths),
73 base_class_(base_class),
74 attrib_name_(attrib_name),
79 lowlevel_class_loader_(false)
82 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Creating ClassLoader, base = %s, address = %p",
83 base_class.c_str(),
this);
93 "Finished constructring ClassLoader, base = %s, address = %p",
94 base_class.c_str(),
this);
101 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Destroying ClassLoader, base = %s, address = %p",
102 getBaseClassType().c_str(),
this);
112 "In deprecated call createClassInstance(), lookup_name = %s, auto_load = %i.",
113 (lookup_name.c_str()), auto_load);
115 if (auto_load && !isClassLoaded(lookup_name)) {
117 "Autoloading class library before attempting to create instance.");
118 loadLibraryForClass(lookup_name);
123 "Attempting to create instance through low-level MultiLibraryClassLoader...");
124 T * obj = lowlevel_class_loader_.createUnmanagedInstance<T>(getClassType(lookup_name));
125 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance created with object pointer = %p", obj);
129 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"CreateClassException about to be raised for class %s",
130 lookup_name.c_str());
139 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create managed instance for class %s.",
140 lookup_name.c_str());
142 if (!isClassLoaded(lookup_name)) {
143 loadLibraryForClass(lookup_name);
147 std::string class_type = getClassType(lookup_name);
148 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
149 lookup_name.c_str(), class_type.c_str());
153 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"boost::shared_ptr to object of real type %s created.",
159 "Exception raised by low-level multi-library class loader when attempting "
160 "to create instance of class %s.",
161 lookup_name.c_str());
166 #if __cplusplus >= 201103L
171 "Attempting to create managed (unique) instance for class %s.",
172 lookup_name.c_str());
174 if (!isClassLoaded(lookup_name)) {
175 loadLibraryForClass(lookup_name);
179 std::string class_type = getClassType(lookup_name);
180 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
181 lookup_name.c_str(), class_type.c_str());
183 UniquePtr<T> obj = lowlevel_class_loader_.createUniqueInstance<T>(class_type);
185 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"std::unique_ptr to object of real type %s created.",
191 "Exception raised by low-level multi-library class loader when attempting "
192 "to create instance of class %s.",
193 lookup_name.c_str());
203 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to create UNMANAGED instance for class %s.",
204 lookup_name.c_str());
206 if (!isClassLoaded(lookup_name)) {
207 loadLibraryForClass(lookup_name);
213 "Attempting to create instance through low level multi-library class loader.");
214 std::string class_type = getClassType(lookup_name);
215 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"%s maps to real class type %s",
216 lookup_name.c_str(), class_type.c_str());
217 instance = lowlevel_class_loader_.createUnmanagedInstance<T>(class_type);
218 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Instance of type %s created.", class_type.c_str());
221 "Exception raised by low-level multi-library class loader when attempting "
222 "to create UNMANAGED instance of class %s.",
223 lookup_name.c_str());
231 const std::string & package,
232 const std::string & attrib_name,
237 std::vector<std::string> paths;
244 const std::vector<std::string> & plugin_xml_paths)
252 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Entering determineAvailableClasses()...");
253 std::map<std::string, ClassDesc> classes_available;
256 for (std::vector<std::string>::const_iterator it = plugin_xml_paths.begin();
257 it != plugin_xml_paths.end(); ++it)
260 processSingleXMLPluginFile(*it, classes_available);
263 "Skipped loading plugin with error: %s.",
268 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Exiting determineAvailableClasses()...");
269 return classes_available;
276 tinyxml2::XMLDocument document;
277 document.LoadFile(package_xml_path.c_str());
278 tinyxml2::XMLElement * doc_root_node = document.FirstChildElement(
"package");
279 if (NULL == doc_root_node) {
281 "Could not find a root element for package manifest at %s.",
282 package_xml_path.c_str());
286 assert(document.RootElement() == doc_root_node);
288 tinyxml2::XMLElement * package_name_node = doc_root_node->FirstChildElement(
"name");
289 if (NULL == package_name_node) {
291 "package.xml at %s does not have a <name> tag! Cannot determine package "
292 "which exports plugin.",
293 package_xml_path.c_str());
297 const char* package_name_node_txt = package_name_node->GetText();
298 if (NULL == package_name_node_txt) {
300 "package.xml at %s has an invalid <name> tag! Cannot determine package "
301 "which exports plugin.",
302 package_xml_path.c_str());
306 return package_name_node_txt;
313 std::vector<std::string> lib_paths;
314 const char * env = std::getenv(
"CMAKE_PREFIX_PATH");
316 std::string env_catkin_prefix_paths(env);
317 std::vector<std::string> catkin_prefix_paths;
318 boost::split(catkin_prefix_paths, env_catkin_prefix_paths, boost::is_any_of(
os_pathsep));
319 BOOST_FOREACH(std::string catkin_prefix_path, catkin_prefix_paths) {
320 boost::filesystem::path path(catkin_prefix_path);
322 boost::filesystem::path bin(
"bin");
323 lib_paths.push_back((path / bin).
string());
325 boost::filesystem::path lib(
"lib");
326 lib_paths.push_back((path / lib).
string());
334 const std::string & library_name,
335 const std::string & exporting_package_name)
345 std::vector<std::string> all_paths;
346 std::vector<std::string> all_paths_without_extension = getCatkinLibraryPaths();
347 all_paths_without_extension.push_back(getROSBuildLibraryPath(exporting_package_name));
349 std::string non_debug_suffix;
350 if (debug_library_suffix) {
355 std::string library_name_with_extension = library_name + non_debug_suffix;
356 std::string stripped_library_name = stripAllButFileFromPath(library_name);
357 std::string stripped_library_name_with_extension = stripped_library_name + non_debug_suffix;
359 const std::string path_separator = getPathSeparator();
361 for (
unsigned int c = 0; c < all_paths_without_extension.size(); c++) {
362 std::string current_path = all_paths_without_extension.at(c);
363 all_paths.push_back(current_path + path_separator + library_name_with_extension);
364 all_paths.push_back(current_path + path_separator + stripped_library_name_with_extension);
366 if (debug_library_suffix) {
370 current_path + path_separator + stripped_library_name +
382 return lowlevel_class_loader_.isClassAvailable<T>(getClassType(lookup_name));
397 if (it != classes_available_.end()) {
398 return it->second.description_;
408 if (it != classes_available_.end()) {
409 return it->second.derived_class_;
418 if (classes_available_.find(lookup_name) == classes_available_.end()) {
419 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
420 lookup_name.c_str());
424 std::string library_name = it->second.library_name_;
425 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s maps to library %s in classes_available_.",
426 lookup_name.c_str(), library_name.c_str());
428 std::vector<std::string> paths_to_try =
429 getAllLibraryPathsToTry(library_name, it->second.package_);
432 "Iterating through all possible paths where %s could be located...",
433 library_name.c_str());
434 for (std::vector<std::string>::const_iterator it = paths_to_try.begin(); it != paths_to_try.end();
437 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Checking path %s ", it->c_str());
438 boost::system::error_code error_code;
439 if (boost::filesystem::exists(*it, error_code)) {
440 if (error_code.value() == boost::system::errc::success) {
441 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Library %s found at explicit path %s.",
442 library_name.c_str(), it->c_str());
455 if (it != classes_available_.end()) {
456 return it->second.package_;
465 return plugin_xml_paths_;
472 std::vector<std::string> lookup_names;
473 for (
ClassMapIterator it = classes_available_.begin(); it != classes_available_.end(); ++it) {
474 lookup_names.push_back(it->first);
484 std::string declared_types;
485 std::vector<std::string> types = getDeclaredClasses();
486 for (
unsigned int i = 0; i < types.size(); i++) {
487 declared_types = declared_types + std::string(
" ") + types[i];
489 return "According to the loaded plugin descriptions the class " + lookup_name +
490 " with base class type " + base_class_ +
" does not exist. Declared types are " +
499 std::vector<std::string> split;
500 boost::split(split, lookup_name, boost::is_any_of(
"/:"));
524 std::string package_name;
525 boost::filesystem::path p(plugin_xml_file_path);
526 boost::filesystem::path parent = p.parent_path();
530 if (boost::filesystem::exists(parent /
"package.xml")) {
531 std::string package_file_path = (boost::filesystem::path(parent /
"package.xml")).
string();
532 return extractPackageNameFromPackageXML(package_file_path);
533 }
else if (boost::filesystem::exists(parent /
"manifest.xml")) {
534 #if BOOST_FILESYSTEM_VERSION >= 3
535 std::string
package = parent.filename().string();
537 std::string
package = parent.filename();
542 if (0 == plugin_xml_file_path.find(package_path)) {
549 parent = parent.parent_path().string();
552 if (parent.string().empty()) {
564 #if BOOST_FILESYSTEM_VERSION >= 3
566 return boost::filesystem::path(
"/").string();
568 return boost::filesystem::path(
"/").native();
571 return boost::filesystem::path(
"/").external_file_string();
581 if (it != classes_available_.end()) {
582 return it->second.plugin_manifest_path_;
592 return lowlevel_class_loader_.getRegisteredLibraries();
606 return classes_available_.find(lookup_name) != classes_available_.end();
613 boost::filesystem::path p1(path1);
614 return (p1 / path2).string();
622 if (it == classes_available_.end()) {
623 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Class %s has no mapping in classes_available_.",
624 lookup_name.c_str());
628 std::string library_path = getClassLibraryPath(lookup_name);
629 if (
"" == library_path) {
630 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"No path could be found to the library containing %s.",
631 lookup_name.c_str());
632 std::ostringstream error_msg;
633 error_msg <<
"Could not find library corresponding to plugin " << lookup_name <<
634 ". Make sure the plugin description XML file has the correct name of the "
635 "library and that the library actually exists.";
640 lowlevel_class_loader_.loadLibrary(library_path);
641 it->second.resolved_library_path_ = library_path;
643 std::string error_string =
644 "Failed to load library " + library_path +
". "
645 "Make sure that you are calling the PLUGINLIB_EXPORT_CLASS macro in the "
646 "library code, and that names are consistent between this macro and your XML. "
647 "Error string: " + ex.what();
654 const std::string & xml_file, std::map<std::string,
658 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Processing xml file %s...", xml_file.c_str());
659 tinyxml2::XMLDocument document;
660 document.LoadFile(xml_file.c_str());
661 tinyxml2::XMLElement * config = document.RootElement();
662 if (NULL == config) {
664 "XML Document '" + xml_file +
665 "' has no Root Element. This likely means the XML is malformed or missing.");
668 const char* config_value = config->Value();
669 if (NULL == config_value) {
671 "XML Document '" + xml_file +
672 "' has an invalid Root Element. This likely means the XML is malformed or missing.");
675 if (!(strcmp(config_value,
"library") == 0 ||
676 strcmp(config_value,
"class_libraries") == 0))
679 "The XML document '" + xml_file +
"' given to add must have either \"library\" or "
680 "\"class_libraries\" as the root tag");
684 if (strcmp(config_value,
"class_libraries") == 0) {
685 config = config->FirstChildElement(
"library");
688 tinyxml2::XMLElement * library = config;
689 while (library != NULL) {
690 const char* path = library->Attribute(
"path");
693 "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
696 std::string library_path(path);
697 if (0 == library_path.size()) {
699 "Attribute 'path' in 'library' tag is missing in %s.", xml_file.c_str());
703 std::string package_name = getPackageFromPluginXMLFilePath(xml_file);
704 if (
"" == package_name) {
706 "Could not find package manifest (neither package.xml or deprecated "
707 "manifest.xml) at same directory level as the plugin XML file %s. "
708 "Plugins will likely not be exported properly.\n)",
712 tinyxml2::XMLElement * class_element = library->FirstChildElement(
"class");
713 while (class_element) {
714 std::string derived_class;
715 if (class_element->Attribute(
"type") != NULL) {
716 derived_class = std::string(class_element->Attribute(
"type"));
719 "Class could not be loaded. Attribute 'type' in class tag is missing.");
722 std::string base_class_type;
723 if (class_element->Attribute(
"base_class_type") != NULL) {
724 base_class_type = std::string(class_element->Attribute(
"base_class_type"));
727 "Class could not be loaded. Attribute 'base_class_type' in class tag is missing.");
730 std::string lookup_name;
731 if (class_element->Attribute(
"name") != NULL) {
732 lookup_name = class_element->Attribute(
"name");
734 "XML file specifies lookup name (i.e. magic name) = %s.",
735 lookup_name.c_str());
738 "XML file has no lookup name (i.e. magic name) for class %s, "
739 "assuming lookup_name == real class name.",
740 derived_class.c_str());
741 lookup_name = derived_class;
745 if (base_class_type == base_class_) {
747 tinyxml2::XMLElement * description = class_element->FirstChildElement(
"description");
748 std::string description_str;
750 description_str = description->GetText() ? description->GetText() :
"";
752 description_str =
"No 'description' tag for this plugin in plugin description file.";
755 classes_available.insert(std::pair<std::string, ClassDesc>(lookup_name,
756 ClassDesc(lookup_name, derived_class, base_class_type, package_name, description_str,
757 library_path, xml_file)));
761 class_element = class_element->NextSiblingElement(
"class");
763 library = library->NextSiblingElement(
"library");
771 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Refreshing declared classes.");
773 std::list<std::string> remove_classes;
774 for (std::map<std::string, ClassDesc>::const_iterator it = classes_available_.begin();
775 it != classes_available_.end(); it++)
777 std::string resolved_library_path = it->second.resolved_library_path_;
778 std::vector<std::string> open_libs = lowlevel_class_loader_.getRegisteredLibraries();
779 if (std::find(open_libs.begin(), open_libs.end(), resolved_library_path) != open_libs.end()) {
780 remove_classes.push_back(it->first);
784 while (!remove_classes.empty()) {
785 classes_available_.erase(remove_classes.front());
786 remove_classes.pop_front();
790 plugin_xml_paths_ = getPluginXmlPaths(package_, attrib_name_,
true);
791 std::map<std::string, ClassDesc> updated_classes = determineAvailableClasses(plugin_xml_paths_);
792 for (std::map<std::string, ClassDesc>::const_iterator it = updated_classes.begin();
793 it != updated_classes.end(); it++)
795 if (classes_available_.find(it->first) == classes_available_.end()) {
796 classes_available_.insert(std::pair<std::string, ClassDesc>(it->first, it->second));
805 std::string only_file;
806 size_t c = path.find_last_of(getPathSeparator());
807 if (std::string::npos == c) {
810 return path.substr(c, path.size());
819 if (it != classes_available_.end() && it->second.resolved_library_path_ !=
"UNRESOLVED") {
820 std::string library_path = it->second.resolved_library_path_;
821 ROS_DEBUG_NAMED(
"pluginlib.ClassLoader",
"Attempting to unload library %s for class %s",
822 library_path.c_str(), lookup_name.c_str());
823 return unloadClassLibraryInternal(library_path);
833 return lowlevel_class_loader_.unloadLibrary(library_path);
838 #endif // PLUGINLIB__CLASS_LOADER_IMP_HPP_