Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions pluginlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,27 @@ find_package(rcutils REQUIRED)
find_package(rcpputils REQUIRED)
find_package(TinyXML2 REQUIRED)

add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE
# Everything that does not depend on the plugin base class T is compiled once here,
# rather than re-instantiated in every consumer for every ClassLoader<T>. Only the
# genuinely T-dependent members remain in the headers.
add_library(${PROJECT_NAME} SHARED
src/class_desc.cpp
src/class_loader_base.cpp
src/class_loader_impl.cpp
src/exceptions.cpp)
target_compile_definitions(${PROJECT_NAME} PRIVATE "PLUGINLIB_BUILDING_LIBRARY")
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
target_link_libraries(${PROJECT_NAME} INTERFACE
target_link_libraries(${PROJECT_NAME} PUBLIC
ament_cmake_ros_core::ament_ros_defaults
ament_index_cpp::ament_index_cpp
class_loader::class_loader
rcutils::rcutils
rcpputils::rcpputils
rcpputils::rcpputils)
# tinyxml2 is only used by the XML parsing in class_loader_impl.cpp; it is no longer
# reachable from any public header, so consumers do not need it.
target_link_libraries(${PROJECT_NAME} PRIVATE
tinyxml2::tinyxml2)

add_executable(list_plugins src/list_plugins.cpp)
Expand All @@ -48,6 +59,9 @@ ament_export_targets(export_${PROJECT_NAME})

install(
TARGETS ${PROJECT_NAME} EXPORT export_${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)

install(
Expand Down
14 changes: 4 additions & 10 deletions pluginlib/include/pluginlib/class_desc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@

#include <string>

#include "pluginlib/visibility_control.hpp"

namespace pluginlib
{

/// Storage for information about a given class.
class ClassDesc
class PLUGINLIB_PUBLIC ClassDesc
{
public:
/**
Expand All @@ -51,15 +53,7 @@ class ClassDesc
const std::string & lookup_name, const std::string & derived_class,
const std::string & base_class, const std::string & package,
const std::string & description, const std::string & library_name,
const std::string & plugin_manifest_path)
: lookup_name_(lookup_name),
derived_class_(derived_class),
base_class_(base_class),
package_(package),
description_(description),
library_name_(library_name),
resolved_library_path_("UNRESOLVED"),
plugin_manifest_path_(plugin_manifest_path) {}
const std::string & plugin_manifest_path);

std::string lookup_name_;
std::string derived_class_;
Expand Down
211 changes: 15 additions & 196 deletions pluginlib/include/pluginlib/class_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,15 @@
#ifndef PLUGINLIB__CLASS_LOADER_HPP_
#define PLUGINLIB__CLASS_LOADER_HPP_

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "class_loader/interface_traits.hpp"
#include "class_loader/multi_library_class_loader.hpp"
#include "pluginlib/class_desc.hpp"
#include "pluginlib/class_loader_base.hpp"
#include "pluginlib/class_loader_impl.hpp"
#include "pluginlib/exceptions.hpp"
#include "tinyxml2.h" // NOLINT

namespace pluginlib
{
Expand All @@ -56,12 +54,15 @@ template<typename T, typename ... Args>
concept InterfaceConstructible = class_loader::is_interface_constructible_v<T, Args...>;

/// A class to help manage and load classes.
/**
* Everything that does not depend on the plugin base class T lives in ClassLoaderImpl,
* which is compiled once into libpluginlib. Only the operations below genuinely need T,
* so only they are instantiated per plugin base class.
*/
template<class T>
class ClassLoader : public ClassLoaderBase
class ClassLoader : public ClassLoaderImpl
{
public:
using ClassMapIterator = typename std::map<std::string, ClassDesc>::iterator;

/**
* \param package The package containing the base class
* \param base_class The type of the base class for classes to be loaded
Expand All @@ -74,9 +75,12 @@ class ClassLoader : public ClassLoaderBase
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>());

~ClassLoader();
std::vector<std::string> plugin_xml_paths = std::vector<std::string>())
: ClassLoaderImpl(
std::move(package), std::move(base_class), std::move(attrib_name),
std::move(plugin_xml_paths))
{
}

/// Create an instance of a desired class.
/**
Expand Down Expand Up @@ -138,197 +142,12 @@ class ClassLoader : public ClassLoaderBase
requires InterfaceConstructible<T, Args...>
T * createUnmanagedInstance(const std::string & lookup_name, Args && ... args);

/// Return a list of all available plugin manifest paths for this ClassLoader's base class type.
/**
* \return A vector of strings corresponding to the paths of all available plugin manifests
*/
std::vector<std::string> getPluginXmlPaths();

/// Return a list of all available classes for this ClassLoader's base class type.
/**
* \return A vector of strings corresponding to the names of all available classes
*/
std::vector<std::string> getDeclaredClasses();

/// Strip the package name off of a lookup name.
/**
* \param lookup_name The name of the plugin
* \return The name of the plugin stripped of the package name
*/
virtual std::string getName(const std::string & lookup_name);

/// Given the lookup name of a class, return the type of the associated base class.
/**
* \return The type of the associated base class
*/
virtual std::string getBaseClassType() const;

/// Given the lookup name of a class, return the type of the derived class associated with it.
/**
* \param lookup_name The name of the class
* \return The name of the associated derived class
*/
virtual std::string getClassType(const std::string & lookup_name);

/// Given the lookup name of a class, return its description.
/**
* \param lookup_name The lookup name of the class
* \return The description of the class
*/
virtual std::string getClassDescription(const std::string & lookup_name);

/// Given the name of a class, return the path to its associated library.
/**
* \param lookup_name The name of the class
* \return The path to the associated library
*/
virtual std::string getClassLibraryPath(const std::string & lookup_name);

/// Given the name of a class, return name of the containing package.
/**
* \param lookup_name The name of the class
* \return The name of the containing package
*/
virtual std::string getClassPackage(const std::string & lookup_name);

/// Given the name of a class, return the path of the associated plugin manifest.
/**
* \param lookup_name The name of the class
* \return The path of the associated plugin manifest
*/
virtual std::string getPluginManifestPath(const std::string & lookup_name);

/// Return the libraries that are registered and can be loaded.
/**
* \return A vector of strings corresponding to the names of registered libraries
*/
virtual std::vector<std::string> getRegisteredLibraries();

/// Check if the library for a given class is currently loaded.
/**
* \param lookup_name The lookup name of the class to query
* \return True if the class is loaded, false otherwise
*/
bool isClassLoaded(const std::string & lookup_name);

/// Check if the class associated with a plugin name is available to be loaded.
/**
* \param lookup_name The name of the plugin
* \return true if the plugin is available, false otherwise
*/
virtual bool isClassAvailable(const std::string & lookup_name);

/// Attempt to load the library containing a class with a given name.
/**
* The counter for the library uses (refcount) is also incremented.
*
* \param lookup_name The lookup name of the class to load
* \throws pluginlib::LibraryLoadException if the library for the
* class cannot be loaded
*/
virtual void loadLibraryForClass(const std::string & lookup_name);

/// Refresh the list of all available classes for this ClassLoader's base class type.
/**
* \throws pluginlib::LibraryLoadException if package manifest cannot be found
*/
virtual void refreshDeclaredClasses();

/// Decrement the counter for the library containing a class with a given name.
/**
* Also try to unload the library, If the counter reaches zero.
*
* \param lookup_name The lookup name of the class to unload
* \throws pluginlib::LibraryUnloadException if the library for the
* class cannot be unloaded
* \return The number of pending unloads until the library is removed from memory
*/
virtual int unloadLibraryForClass(const std::string & lookup_name);

private:
/// Return the paths to plugin.xml files.
/**
* \throws pluginlib::LibraryLoadException if package manifest cannot be found
* \return A vector of paths
*/
std::vector<std::string> getPluginXmlPaths(
const std::string & package,
const std::string & attrib_name);

/// Return the available classes.
/**
* \param plugin_xml_paths The vector of paths of plugin.xml files
* \throws pluginlib::LibraryLoadException if package manifest cannot be found
* \return A map of class names and the corresponding descriptions
*/
std::map<std::string, ClassDesc> determineAvailableClasses(
const std::vector<std::string> & plugin_xml_paths);

/// Open a package.xml file and extract the package name (i.e. contents of <name> tag).
/**
* \param package_xml_path The path to the package.xml file
* \return The name of the package if successful, otherwise an empty string
*/
std::string extractPackageNameFromPackageXML(const std::string & package_xml_path);

/// Get a list of paths to try to find a library.
/**
* As we transition from rosbuild to Catkin build systems, plugins can be
* found in the old rosbuild place (pkg_name/lib usually) or somewhere in the
* Catkin build space.
*/
std::vector<std::string> getAllLibraryPathsToTry(
const std::string & library_name,
const std::string & exporting_package_name);

/// Return an error message for an unknown class.
/**
* \param lookup_name The name of the class
* \return The error message
*/
std::string getErrorStringForUnknownClass(const std::string & lookup_name);

/// Get the standard path separator for the native OS (e.g. "/" on *nix, "\" on Windows).
std::string getPathSeparator();

/// Get the package name from a path to a plugin XML file.
std::string getPackageFromPluginXMLFilePath(const std::string & path);

/// Join two filesystem paths together utilizing appropriate path separator.
std::string joinPaths(const std::string & path1, const std::string & path2);

/// Parse a plugin XML file.
/**
* Also insert the appropriate ClassDesc entries into the passes
* classes_available map.
*/
void processSingleXMLPluginFile(
const std::string & xml_file, std::map<std::string,
ClassDesc> & class_available);

/// Strip all but the filename from an explicit file path.
/**
* \param path The path to strip
* \return The basename of the path
*/
std::string stripAllButFileFromPath(const std::string & path);


/// Helper function for unloading a shared library.
/**
* \param library_path The exact path to the library to unload
* \return The number of pending unloads until the library is removed from memory
*/
int unloadClassLibraryInternal(const std::string & library_path);

private:
std::vector<std::string> plugin_xml_paths_;
// Map from library to class's descriptions described in XML.
std::map<std::string, ClassDesc> classes_available_;
std::string package_;
std::string base_class_;
std::string attrib_name_;
class_loader::MultiLibraryClassLoader lowlevel_class_loader_; // The underlying classloader
bool isClassLoaded(const std::string & lookup_name) override;
};

} // namespace pluginlib
Expand Down
6 changes: 4 additions & 2 deletions pluginlib/include/pluginlib/class_loader_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
#include <string>
#include <vector>

#include "pluginlib/visibility_control.hpp"

namespace pluginlib
{
/// Pure virtual base class of pluginlib::ClassLoader which is not templated.
Expand All @@ -40,11 +42,11 @@ namespace pluginlib
* which can call all the administrative functions of ClassLoaders -
* everything except createInstance() and createUnmanagedInstance().
*/
class ClassLoaderBase
class PLUGINLIB_PUBLIC ClassLoaderBase
{
public:
/// Empty virtual destructor.
virtual ~ClassLoaderBase() {}
virtual ~ClassLoaderBase();

/// Return a list of all available plugin manifest paths.
/**
Expand Down
Loading