2
0
mirror of https://github.com/boostorg/dll.git synced 2026-01-31 08:02:19 +00:00
Files
dll/doc/tutorial.qbk
2014-08-15 13:20:44 +04:00

191 lines
5.5 KiB
Plaintext

[/
Copyright 2014 Renato Tegon Forti, Antony Polukhin
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section Tutorial]
Tutorial is provided to give you an idea of how to create and use plugins.
[section Plugin basics]
The first thing to do when creating your own plugins is define the plugin interface. There is an example
of an abstract class that will be our plugin API:
[import ../example/tutorial_common/plugin_api.hpp]
[plugapi]
Now let's make a DLL/DSO library that will holds implementation of plugin interface and exports it using the
[macroref BOOST_PLUGIN_ALIAS]:
[import ../example/tutorial1/my_plugin_sum.cpp]
[plugcpp_my_plugin_sum]
Simple application that loads plugin using the [funcref boost::plugin::shared_variable_alias]:
[import ../example/tutorial1/tutorial1.cpp]
[callplugcpp_tutorial1]
That application will output:
[pre
Application started
Loading the plugin
Constructing my_plugin_sum
Plugin Version: 1
Plugin Method: 3
Destructing my_plugin_sum ;o)
]
[endsect]
[section Factory method in plugin]
In previous example we were importing from a plugin a single variable. Let's make a class
that uses our plugin API plugin and holds some state:
[import ../example/tutorial2/my_plugin_aggregator.cpp]
[plugcpp_my_plugin_aggregator]
As you may see, `my_namespace::create_plugin` is a factory method, that creates
instances of `my_namespace::my_plugin_aggregator`. We export that method with the name "create_plugin"
using [macroref BOOST_PLUGIN_ALIAS].
[import ../example/tutorial2/tutorial2.cpp]
[callplugcpp_tutorial2]
In that application we have imported the factory method using [funcref boost::plugin::shared_function_alias].
[caution Be careful: `creator` variable holds a reference to the loaded shared library. If this
variable goes out of scope or will be reset, then the *DLL/DSO will be unloaded* and any attempt to
dereference the `plugin` variable will lead to *undefined behavior*. ]
Output of the application will be the following:
[pre
Plugin Version: 1
Plugin Method: 3
Plugin Method second call: 6
Plugin Name: aggregator
]
[endsect]
[section Searching for a symbol in multiple plugins]
Consider the situation: we have multiple plugins, but only some of them have symbols that we need.
Let's write a function that search list of plugins and attempts to find `"create_plugin"` method.
[import ../example/tutorial3/tutorial3.cpp]
[callplugcpp_tutorial3]
If we call that method for all our plugins we'll get the following output:
[pre
Loading plugin: "/test/libmy_plugin_aggregator.so"
Matching plugin name: aggregator
Loading plugin: "/test/libmy_plugin_sum.so.1.56"
Constructing my_plugin_sum
Destructing my_plugin_sum ;o)
]
[endsect]
[section Linking plugin into the executable]
Linking plugin into the executable has the advantages of
* reducing common size of distibution
* simplification of installation of distribution
* faster load times of plugin
Let's start from creating a linkable in plugin. Such plugin will have a header,
common for plugin library itself and for the executable:
[import ../example/tutorial4/static_plugin.hpp]
[plugcpp_my_plugin_static]
Main trick here is the alias definition. When linking plugin into the executable, the alias *must*
be instantiated in one of the source files of the executable. Otherwise the linker will optimize
away our plugin.
Here's how the implementation of the plugin looks like:
[import ../example/tutorial4/static_plugin.cpp]
[plugcpp_my_plugin_staic_impl]
And here is how it can be used from the executable:
[import ../example/tutorial4/load_self.cpp]
[plugcpp_my_plugin_load_self]
[note Flag '-rdynamic' must be used when linking the plugin into the executable on Linux OS.
Otherwise loading symbols from self *will fail*.]
Running the program will output the following:
[pre
Application started
Call function
Constructing my_plugin_static
Computed Value: 0
Destructing my_plugin_static
]
[endsect]
[section Symbol shadowing problem (Linux)]
Let's make an executable, link a plugin into it and attempt to load all the existing plugins:
[import ../example/tutorial5/load_all.cpp]
[plugcpp_plugins_collector_def]
[plugcpp_load_all]
With the default flags you'll get a very strange output:
[pre
Loaded (0x180db60):"/libs/plugin/test/libmy_plugin_aggregator.so"
Constructing my_plugin_static
Destructing my_plugin_static
...
Unique plugins 2:
(0x180db60): static
(0x180e3b0): sum
Destructing my_plugin_sum ;o)
]
Why `my_plugin_static` was constructed while we were loading `my_plugin_aggregator`?
That's because function `create_plugin` from `libmy_plugin_aggregator.so` was shadowed by
the `create_plugin` function from onther plugin. Dynamik linker thought that `create_plugin`
was already loaded and there is no need to load it again.
[warning Use "-fvisibility=hidden" flag (at least for plugins) while compiling for POSIX platforms.
This flag makes your code more portable ("-fvisibility=hidden" is the default behavior under Windows),
reduces size of the binaries and improves binary load time.
]
Now if we recompile your example with "-fvisibility=hidden" we'll get the following output:
[pre
Loaded (0x2406b60):"/home/apolukhin/boost_maintain/modular-boost/bin.v2/libs/plugin/test/libmy_plugin_aggregator.so"
Loaded (0x2407410):"/home/apolukhin/boost_maintain/modular-boost/bin.v2/libs/plugin/test/libgetting_started_library.so"
Constructing my_plugin_sum
...
Unique plugins 3:
(0x2406b60): aggregator
(0x7fd1cadce2c8): static
(0x24073b0): sum
Destructing my_plugin_sum ;o)
]
[endsect]
[endsect]