# Migration Instructions

This file provides migration instructions for `ignition` library developers to
replace the `ignition-common` plugin framework with the `ignition-plugin`
framework. Some of the instructions here may also be useful to new adopters of
`ignition-plugin`.

# Linking to ignition-plugin

`ign-plugin` has three components: `core`, `loader`, and `register`. Code that
just wants to use `PluginPtr` objects can link to `core`, e.g.:

```
target_link_libraries(my_target PUBLIC ignition-plugin1::core)
```

However, if your code wants to be able to load plugins, it should link to the
`loader` component. In most cases, it should probably link privately, unless you
need the `ignition::plugin::Loader` class to be part of your library's API:

```
target_link_libraries(my_target PRIVATE ignition-plugin1::loader)
```

If `ignition::plugin::PluginPtr` objects are part of your library's API, then
you may want `loader` to be private while `core` is public:

```
target_link_libraries(my_target
  PUBLIC
    ignition-plugin1::core
  PRIVATE
    ignition-plugin1::loader
)
```

If you are building a plugin library that needs to register itself as a plugin,
then you should link against the `register` component. This should almost always
be a private link, since plugin registration is purely internal for a library:

```
target_link_libraries(my_plugin PRIVATE ignition-plugin1::register)
```

# Registering a plugin

The name of the header for registering plugins has changed:

* `<ignition/common/PluginMacros.hh>` should be replaced by `<ignition/plugin/Register.hh>`

The old `ign-common` plugin registration method had numerous macros for registering
plugins. Those have all been replaced with `IGNITION_ADD_PLUGIN`. Specifically:

* `IGN_COMMON_REGISTER_SINGLE_MACRO` can be directly replaced with `IGNITION_ADD_PLUGIN`.
* `IGN_COMMON_ADD_PLUGIN` can be directly replaced with `IGNITION_ADD_PLUGIN`.
* All uses of `IGN_COMMON_BEGIN_ADDING_PLUGINS` can simply be removed.
* All uses of `IGN_COMMON_FINISH_ADDING_PLUGINS` can simply be removed.
* All uses of `IGN_COMMON_SPECIALIZE_INTERFACE` can simply be removed. Interfaces no longer need to be "specialized" in order to have specialized plugins.

You can also register multiple interfaces with a single call to `IGNITION_ADD_PLUGIN`, e.g.:

```
IGNITION_ADD_PLUGIN(MyPluginClass, MyInterface1, MyInterface2, MyInterface3)
```

You may also place the `IGNITION_ADD_PLUGIN` macro into **any namespace**. You
simply need to make sure that the compiler can resolve the names of the classes
that you pass to it (and there will be a compilation error if it cannot).

It is now possible to register plugins across **multiple translation units**
within a single library. To do this, use `#include <ignition/plugin/Register.hh>`
in **exactly one** of your library's translation units, and then use
`#include <ignition/plugin/RegisterMore.hh>` in all other translation units. It
does not matter which translation unit you choose to be the "first", as long as
you choose exactly one.


# Loading a library

The `ignition::common::SystemPaths` class was not ported into `ign-plugin`
because it is more related to filesystem utilities than to plugins. If you are
currently using `ignition::common::SystemPaths` to help with loading plugins,
then you should continue to use it. It does not have a replacement in `ign-plugin`.

Here is a list of things that you *should* replace:

* `#include <ignition/common/PluginLoader.hh>` should be replaced with `#include <ignition/plugin/Loader.hh>`
* `ignition::common::PluginLoader` should be replaced with `ignition::plugin::Loader`
* When calling `Loader::Instantiate("....")` do **NOT** prefix the class name with `::`. E.g. `"::some_namespace::MyClass"` should now be `"some_namespace::MyClass"`.


# Querying an interface

Functions like `Plugin::QueryInterface()` and `Plugin::QueryInterfaceSharedPtr()`
used to require a `std::string` argument with the name of the interface. This is
no longer necessary, ever. Functions that accept `std::string` arguments will
remain in the initial release 0 of `ign-plugin`, but they are marked as
deprecated and will be removed by release 1. All interfaces can now be queried
by simply passing the class as a template argument to a query function. This is
a much safer method than relying on users to spell a string correctly.


# Template support

The new registration scheme also supports templated classes as plugins and as
interfaces. Note that the class template must be fully instantiated (i.e. all of
its template arguments must be provided).

For example, the following can work:

```
template <typename T>
class GetT_Interface
{
public:
  virtual T get() const = 0;
};


template <typename T>
class MyGetT_Plugin : public GetT_Interface<T>
{
public:
  T get() const override
  {
    return T();
  }
};

IGNITION_ADD_PLUGIN(MyGetT_Plugin<double>, GetT_Interface<double>)
```

When using the loader, you would call

```
loader.Instantiate("MyGetT_Plugin<double>");
```

to load this plugin.

Note that different compilers may have different conventions for how templated
objects get formatted. For example, nested templates like

```
std::vector<std::vector<int>>
```

might get formatted as `std::vector<std::vector<int> >`. That space between the
trailing brackets at the end can cause the Loader to not recognize the plugin
class that you're asking for if you neglect to include it in the string argument
that you pass to `Loader::Instantiate(std::string)`.

Additionally, STL implementations may vary in how they name their classes. For
example, if you use `std::string` as a template argument, then GCC will format
it as:

```
std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >
```

whereas MSVC might format it as something different.

In general, plugin names that get passed to a `Loader` should not be hard-coded.
They should be selected by either inspecting what interfaces they provide, or by
having a user specify the plugin name. This rule of thumb applies to both
template-based classes and to regular classes.

