Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static plugins #97

Merged
merged 15 commits into from
Jul 29, 2022
Merged
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
8 changes: 8 additions & 0 deletions core/include/gz/plugin/Plugin.hh
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ namespace gz
const ConstInfoPtr &_info,
const std::shared_ptr<void> &_dlHandlePtr) const;

/// \brief Create a new plugin instance based on the info provided for a
/// plugin from the static plugin loader registry.
/// \param[in] _info
/// Pointer to the Info for this plugin
private: void PrivateCreateStaticPluginInstance(
const ConstInfoPtr &_info) const;


/// \brief Get a reference to the abstract instance being managed by this
/// wrapper
private: const std::shared_ptr<void> &PrivateGetInstancePtr() const;
Expand Down
5 changes: 5 additions & 0 deletions core/include/gz/plugin/PluginPtr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ namespace gz
private: explicit TemplatePluginPtr(
const ConstInfoPtr &_info,
const std::shared_ptr<void> &_dlHandlePtr);

/// \brief Private constructor. Used by the Loader to instantiate a
/// plugin class from the static registry.
/// \param[in] _info An Info instance that was generated by Loader.
private: explicit TemplatePluginPtr(const ConstInfoPtr &_info);
};

/// \brief Typical usage for TemplatePluginPtr is to just hold a generic
Expand Down
9 changes: 9 additions & 0 deletions core/include/gz/plugin/detail/PluginPtr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ namespace gz
{
dataPtr->PrivateCreatePluginInstance(_info, _dlHandlePtr);
}

//////////////////////////////////////////////////
template <typename PluginType>
TemplatePluginPtr<PluginType>::TemplatePluginPtr(
const ConstInfoPtr &_info)
: dataPtr(new PluginType)
{
dataPtr->PrivateCreateStaticPluginInstance(_info);
}
}
}

Expand Down
21 changes: 19 additions & 2 deletions core/src/Plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,13 @@ namespace gz
/// \param[in] _info Information describing the plugin to initialize
/// \param[in] _dlHandlePtr A reference to the dl handle that manages the
/// lifecycle of the plugin library.
/// \param[in] _allowNullDlHandlePtr Allow _dlHandlePtr to be null. Only
/// set true for plugin instances created from the static
/// registry.
public: void Create(
const ConstInfoPtr &_info,
const std::shared_ptr<void> &_dlHandlePtr)
const std::shared_ptr<void> &_dlHandlePtr,
bool _allowNullDlHandlePtr = false)
{
this->Clear();

Expand All @@ -139,7 +143,7 @@ namespace gz

this->info = _info;

if (!_dlHandlePtr)
if (!_dlHandlePtr && !_allowNullDlHandlePtr)
{
// LCOV_EXCL_START
std::cerr << "Received Info for [" << _info->name << "], "
Expand All @@ -148,6 +152,11 @@ namespace gz
assert(false);
return;
// LCOV_EXCL_STOP
} else if (_dlHandlePtr != nullptr && _allowNullDlHandlePtr) {
std::cerr << "Trying to create a plugin from a static plugin, but "
<< "a shared library handle was provided. This should "
<< "never happen! Please report this bug!\n";
assert(false);
}

// Create a std::shared_ptr to a struct which ensures that the
Expand Down Expand Up @@ -359,6 +368,14 @@ namespace gz
this->dataPtr->Create(_info, _dlHandlePtr);
}

//////////////////////////////////////////////////
void Plugin::PrivateCreateStaticPluginInstance(
const ConstInfoPtr &_info) const
{
this->dataPtr->Create(_info, /*_dlHandlePtr=*/nullptr,
/*_allowNullDlHandlePtr=*/true);
}

//////////////////////////////////////////////////
const std::shared_ptr<void> &Plugin::PrivateGetInstancePtr() const
{
Expand Down
3 changes: 2 additions & 1 deletion loader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ if (MSVC OR NOT GZ_TOOLS_PROGRAM)
endif()

# Create the library target
file(GLOB detail_sources RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "src/detail/*.cc")
gz_add_component(loader
SOURCES ${sources}
SOURCES ${sources} ${detail_sources}
GET_TARGET_NAME loader)

target_link_libraries(${loader}
Expand Down
41 changes: 38 additions & 3 deletions loader/include/gz/plugin/Loader.hh
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,50 @@ namespace gz
/// \sa bool ForgetLibrary(const std::string &_pathToLibrary)
public: bool ForgetLibraryOfPlugin(const std::string &_pluginNameOrAlias);

/// \brief Get a pointer to the Info corresponding to _pluginName.
/// \brief Specifically look up a plugin loaded from file.
///
/// \param[in] _nameOrAlias
/// The name or alias of the plugin of interest.
///
/// \return The name of the plugin being referred to, or an empty string
/// if no such plugin is known.
private: std::string PrivateLookupFilePlugin(
const std::string &_nameOrAlias) const;

/// \brief Get a pointer to the Info corresponding to _pluginName for a
/// plugin loaded from file.
///
/// \param[in] _resolvedName
/// The resolved name, i.e. the demangled class symbol name as returned
/// by LookupPlugin(~), of the plugin that you want to instantiate.
/// by PrivateLookupFilePlugin(~), of the plugin that you want to
/// instantiate.
///
/// \return Pointer to the corresponding Info, or nullptr if there
/// is no info for the requested _pluginName.
private: ConstInfoPtr PrivateGetInfoForFilePlugin(
const std::string &_resolvedName) const;

/// \brief Specifically look up a plugin in the static registry.
///
/// \param[in] _nameOrAlias
/// The name or alias of the plugin of interest.
///
/// \return The name of the plugin being referred to, or an empty string
/// if no such plugin is known.
private: std::string PrivateLookupStaticPlugin(
const std::string &_nameOrAlias) const;

/// \brief Get a pointer to the Info corresponding to _pluginName for a
/// plugin loaded from the static registry.
///
/// \param[in] _resolvedName
/// The resolved name, i.e. the demangled class symbol name as returned
/// by PrivateLookupStaticPlugin(~), of the plugin that you want to
/// instantiate.
///
/// \return Pointer to the corresponding Info, or nullptr if there
/// is no info for the requested _pluginName.
private: ConstInfoPtr PrivateGetInfo(
private: ConstInfoPtr PrivateGetInfoForStaticPlugin(
const std::string &_resolvedName) const;

/// \brief Get a std::shared_ptr that manages the lifecycle of the shared
Expand Down
36 changes: 27 additions & 9 deletions loader/include/gz/plugin/detail/Loader.hh
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,36 @@ namespace gz
PluginPtrType Loader::Instantiate(
const std::string &_pluginNameOrAlias) const
{
const std::string &resolvedName = this->LookupPlugin(_pluginNameOrAlias);
if (resolvedName.empty())
return PluginPtr();
// Higher priority for plugins loaded from file than from the static
// registry.
const std::string &resolvedNameForFilePlugin =
this->PrivateLookupFilePlugin(_pluginNameOrAlias);

const std::string &resolvedNameForStaticPlugin =
this->PrivateLookupStaticPlugin(_pluginNameOrAlias);

PluginPtrType ptr(this->PrivateGetInfo(resolvedName),
this->PrivateGetPluginDlHandlePtr(resolvedName));
PluginPtr ptr;

if (!resolvedNameForFilePlugin.empty())
{
ptr = PluginPtr(
this->PrivateGetInfoForFilePlugin(resolvedNameForFilePlugin),
this->PrivateGetPluginDlHandlePtr(resolvedNameForFilePlugin));
}
else if (!resolvedNameForStaticPlugin.empty())
{
ptr = PluginPtr(
this->PrivateGetInfoForStaticPlugin(resolvedNameForStaticPlugin));
}
else
{
return PluginPtr();
}

if (auto *enableFromThis =
ptr->template QueryInterface<EnablePluginFromThis>())
enableFromThis->PrivateSetPluginFromThis(ptr);
if (auto *enableFromThis = ptr->QueryInterface<EnablePluginFromThis>())
enableFromThis->PrivateSetPluginFromThis(ptr);

return ptr;
return ptr;
}

template <typename InterfaceType>
Expand Down
185 changes: 185 additions & 0 deletions loader/include/gz/plugin/detail/Registry.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2022 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/


#ifndef GZ_PLUGIN_DETAIL_REGISTRY_HH_
#define GZ_PLUGIN_DETAIL_REGISTRY_HH_

#include <map>
#include <set>
#include <string>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>

#include <gz/plugin/Info.hh>
#include <gz/plugin/loader/Export.hh>
#include <gz/utils/SuppressWarning.hh>

namespace gz
{
namespace plugin
{
/// \brief Manages a set of plugin Infos and allows querying by name or
/// by alias.
class GZ_PLUGIN_LOADER_VISIBLE Registry {
/// \brief Constructor
public: Registry() = default;

/// \brief Destructor
public: virtual ~Registry() = default;

/// \brief Makes a printable string with info about plugins
///
/// \returns A pretty string
public: std::string PrettyStr() const;

/// \brief Get demangled names of interfaces that the registry has plugins
/// for.
///
/// \returns Demangled names of the interfaces that are implemented
public: std::unordered_set<std::string> InterfacesImplemented() const;

/// \brief Get plugin names that implement the specified interface
///
/// \return names of plugins that implement the interface.
public: template <typename Interface>
std::unordered_set<std::string> PluginsImplementing() const
{
return this->PluginsImplementing(typeid(Interface).name(), false);
}

/// \brief Get plugin names that implement the specified interface string.
/// Note that the templated version of this function is recommended
/// instead of this version to avoid confusion about whether a mangled or
/// demangled version of a string is being used. Note that the function
/// InterfacesImplemented() returns demangled versions of the interface
/// names.
///
/// If you want to pass in a mangled version of an interface name, e.g.
/// the result that would be produced by typeid(T).name(), then set
/// `demangled` to false.
///
/// \param[in] _interface
/// Name of an interface
///
/// \param[in] _demangled
/// Specify whether the _interface string is demangled (default, true)
/// or mangled (false).
///
/// \returns Names of plugins that implement the interface
public: std::unordered_set<std::string> PluginsImplementing(
const std::string &_interface,
const bool _demangled = true) const;

/// \brief Get plugin names that correspond to the specified alias string.
///
/// If there is more than one entry in this set, then the alias cannot be
/// used to instantiate any of those plugins.
///
/// If the name of a plugin matches the alias string, then that plugin
/// will be instantiated any time the string is used to instantiate a
/// plugin, no matter how many other plugins use the alias.
///
/// \param[in] _alias
/// The std::string of the alias
///
/// \return A set of plugins that correspond to the desired alias
public: std::set<std::string> PluginsWithAlias(
const std::string &_alias) const;

/// \brief Get the aliases of the plugin with the given name
///
/// \param[in] _pluginName
/// The name of the desired plugin
///
/// \return A set of aliases corresponding to the desired plugin
public: std::set<std::string> AliasesOfPlugin(
const std::string &_pluginName) const;

/// \brief Resolve the plugin name or alias into the name of the plugin
/// that it maps to. If this is a name or alias that does not uniquely map
/// to a known plugin, then the return value will be an empty string.
///
/// \param[in] _nameOrAlias
/// The name or alias of the plugin of interest.
///
/// \return The name of the plugin being referred to, or an empty string
/// if no such plugin is known.
public: std::string LookupPlugin(const std::string &_nameOrAlias) const;

/// \brief Get a set of the names of all plugins that are in this
/// registry.
///
/// Method is virtual to allow other Info storage and memory management
/// models.
///
/// \return A set of all plugin names in this registry.
public: virtual std::set<std::string> AllPlugins() const;

/// \brief Get info as ConstInfoPtr.
///
/// Method is virtual to allow other Info storage and memory management
/// models.
///
/// \param[in] _pluginName
/// Name of the plugin as returned by LookupPlugin(~).
public: virtual ConstInfoPtr GetInfo(
const std::string &_pluginName) const;

/// \brief Add a new plugin info.
///
/// Tracked aliases in this registry are also updated.
///
/// \param[in] _info
/// Plugin info to add.
///
/// \return True if the info was added, false if a plugin with this name
/// already exists in the registry.
public: virtual bool AddInfo(const Info &_info);

/// \brief Forget a plugin info.
///
/// Tracked aliases in this registry are also updated.
///
/// \param[in] _pluginName
/// Name of the plugin as returned by LookupPlugin(~).
public: virtual void ForgetInfo(const std::string &_pluginName);

/// \brief Deleted copy constructor
public: Registry(const Registry&) = delete;

/// \brief Deleted copy assignment operator
public: Registry& operator=(Registry&) = delete;

GZ_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING
protected: using AliasMap = std::map<std::string, std::set<std::string>>;
/// \brief A map from known alias names to the plugin names that they
/// correspond to. Since an alias might refer to more than one plugin,
/// the key of this map is a set.
protected: AliasMap aliases;

protected: using PluginMap =
std::unordered_map<std::string, ConstInfoPtr>;
/// \brief A map from known plugin names to their Info.
protected: PluginMap plugins;
GZ_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING
};
}
}

#endif
Loading