-
Notifications
You must be signed in to change notification settings - Fork 20
/
MigrationFromCommon.md
168 lines (123 loc) · 5.99 KB
/
MigrationFromCommon.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# Migration Instructions (from common::Plugin)
This file provides migration instructions for `gz` library developers to
replace the `gz-common` plugin framework with the `gz-plugin`
framework. Some of the instructions here may also be useful to new adopters of
`gz-plugin`.
# Linking to gz-plugin
`gz-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 gz-plugin3::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 `gz::plugin::Loader` class to be part of your library's API:
```
target_link_libraries(my_target PRIVATE gz-plugin3::loader)
```
If `gz::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
gz-plugin3::core
PRIVATE
gz-plugin3::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 gz-plugin3::register)
```
# Registering a plugin
The name of the header for registering plugins has changed:
* `<gz/common/PluginMacros.hh>` should be replaced by `<gz/plugin/Register.hh>`
The old `gz-common` plugin registration method had numerous macros for registering
plugins. Those have all been replaced with `GZ_ADD_PLUGIN`. Specifically:
* `IGN_COMMON_REGISTER_SINGLE_MACRO` can be directly replaced with `GZ_ADD_PLUGIN`.
* `IGN_COMMON_ADD_PLUGIN` can be directly replaced with `GZ_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 `GZ_ADD_PLUGIN`, e.g.:
```
GZ_ADD_PLUGIN(MyPluginClass, MyInterface1, MyInterface2, MyInterface3)
```
You may also place the `GZ_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 <gz/plugin/Register.hh>`
in **exactly one** of your library's translation units, and then use
`#include <gz/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 `gz::common::SystemPaths` class was not ported into `gz-plugin`
because it is more related to filesystem utilities than to plugins. If you are
currently using `gz::common::SystemPaths` to help with loading plugins,
then you should continue to use it. It does not have a replacement in `gz-plugin`.
Here is a list of things that you *should* replace:
* `#include <ignition/common/PluginLoader.hh>` should be replaced with `#include <gz/plugin/Loader.hh>`
* `#include <gz/common/PluginLoader.hh>` should be replaced with `#include <gz/plugin/Loader.hh>`
* `gz::common::PluginLoader` should be replaced with `gz::plugin::Loader`
* `ignition::common::PluginLoader` should be replaced with `gz::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 `gz-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();
}
};
GZ_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.