The skeleton plugin represents the most minimal amount of code needed to write a VFS plugin. It is included in the documentation as a starting place for new node packages and to show how a plugin identifies itself, names itself, and is compiled.
A plugin is composed of 3 main parts:
- A .pro file for qmake, which will tell Qt/qmake to compile it as a plugin, which files are to be compiled, and what to name the resulting dynamic/shared library.
- A VFS_node_interface subclass, which will register itself as a plugin with the VFS executable and Qt plugin loader, and provide an entry point for the node bundling mechanism in VFS_creator.
- The actual VFS_node subclasses themselves, which will usually be the bulk of a plugin.
Optionally, a plugin may include .qrc resources for images, code, stylesheets, or any other resource, which is visited in the Animated Clock example.
For this example, we will look at this directory structure for a plugin:
/skeleton.pro
/src/skeletonPlugin.h
/src/skeletonPlugin.cpp
/src/skeleton.h
/src/skeleton.cpp
This is the minumum amount of code and apparatus required to create a plugin.
- Attention
- The complete skeleton plugin can be found in the 'server/src/plugins/skeleton/' folder. If you intend to build it, you should copy it to a work folder.
The skeleton.pro file
This file will be used with qmake to build the makefiles and ultimately compile the library.
# skeleton.pro
# Read VFS_DIR from the environment
VFS_DIR=$$(VFS_DIR)
isEmpty(VFS_DIR){
error(VFS_DIR must be defined to compile a plugin)
}
# The name of the resulting dynamic lbrary
TARGET = $$qtLibraryTarget(skeleton)
# A series of settings which are global to all plugins. Requires VFS_PLUGINS_DIR to be set.
include($$VFS_DIR/VFS-plugin.pri)
# Plugins may include any additional Qt modules here: network, xml, opengl, etc.
#QT += network
# Include sources and headers to compile
SOURCES += src/skeletonPlugin.cpp \
src/skeleton.cpp
HEADERS += src/skeletonPlugin.h \
src/skeleton.h
# Resources for this project (unused in this example)
#RESOURCES += src/skeleton.qrc
- Attention
- You will want to rename your plugin to something other than "skeleton", and you will want to include your own (renamed) source files.
- Note
- if using Qt Creator, you will need to set the VFS_DIR and VFS_PLUGINS_DIR environment variables. This can be done by either setting them on the terminal and opening Creator on the command line, or by opening the project and adding VFS_DIR and VFS_PLUGINS_DIR as variables in the Build Environment section of the project settings. Paths are relative to the skeleton.pro file.
-
VFS_DIR must be set to the directory containing src/ in the server source tree.
-
VFS_PLUGINS_DIR must be set to the destination folder to place the compiled dynamic library. This variable is referenced in the VFS-plugin.pri include file.
The VFS_node_interface subclass header
#ifndef SKELETON_PLUGIN_H
#define SKELETON_PLUGIN_H
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.remoto.plugins.skeleton")
public:
virtual VFS_node *
create(QString type, QVariantMap env, QDomElement child);
virtual QString
code(QString nodename, QString libname, QString &error);
};
#endif
The interface class for dynamically loaded plugins.
virtual QString description(QString type)
Descriptive text about an individual node.
virtual QString arguments(QString type)
Describe the arguments needed to create a node.
virtual QString code(QString nodename, QString libname, QString &error)
Request code or other resource from a plugin bundle.
virtual QStringList provides()
A string list of node names that this plugin is prepared to create.
virtual VFS_node * create(QString type, QVariantMap env, QDomElement child)
Create a new node instance.
VFS_node is the base class from which all other VFS_node classes derive.
Define the VFS_node_interface class, and identify it as a Qt plugin by providing a metadata identifier with the Q_PLUGIN_METADATA(name) macro. Any string can be used here, but the example shows the common format.
Use the Q_INTERFACES() macro to tell the compiler what functions to expose in the dynamic library. This should always be VFS_node_interface.
- Note
- VFS_node_interface contains pure virtual methods, so initialize(), description(), licensed(), and code() are optional, but provides() and create() not optional.
- Attention
- You will want to rename the class and the metadata to your plugin name, and don't forget the preprocessor defines.
- See also
- VFS_node_interface
The VFS_node_interface subclass source
#include "skeletonPlugin.h"
#include "skeleton.h"
QString skeletonPlugin::description(QString
type)
{
return "A node provided as an example for the documentation. It does nothing.";
}
QString skeletonPlugin::arguments(QString
type)
{
return argumentString( skeleton::staticMetaObject );
}
QStringList skeletonPlugin::provides()
{
QStringList p;
p << "skeleton";
return p;
}
VFS_node *skeletonPlugin::create(QString
type, QVariantMap env, QDomElement child)
{
{
return new skeleton(alpha, beta);
}
return nullptr;
}
QString skeletonPlugin::code(QString nodename, QString libname, QString &
error)
{
if (nodename == "skeleton")
return skeleton::code(nodename,libname,
error);
}
static QString configAttribute(QVariantMap env, QDomElement e, QString attr, bool req=true, QString def="")
Fetch an XML node attribute value and resolve it against an environment.
setter type
a setter DOCME
The plugin bundle functions need to service requests for every node type defined in VFS_node_interface::provides(). The logic in each method is up to the developer. It can be complex or simple depending on your needs. For instance, If the plugin is always licensed, licensed() could just return true
.
- See also
- VFS_node_interface
The VFS_node subclass implementation
Since our skeletonPlugin serves the "skeleton" node, we have to define it. In this case, we define a node that does nothing but construct and destruct.
Header:
#ifndef SKELETON_H
#define SKELETON_H
{
Q_OBJECT
public:
Q_INVOKABLE explicit skeleton(QString alpha, int beta);
virtual ~skeleton();
private:
QString _alpha;
int _beta;
};
#endif
Source:
#include "skeleton.h"
skeleton::skeleton(QString alpha, int beta)
, _alpha(alpha)
, _beta(beta)
{
VFS::WARN( QString(
"Created skeleton instance: %1 / %2").arg(_alpha).arg(_beta));
}
skeleton::~skeleton()
{
}
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
- See also
- VFS_node
- Note
- If your plugin is relatively small, all of this (both plugin and node) could be included in single source/header files. But generally, plugins tend to swell over time as additional functionality is added. It can be difficult to separate all the files later, so it is recommended to follow the directory structure above.
- Attention
- Much of the setup work when using the skeleton as a starting place is in replacing "skeleton" with the proper name of your plugin. It is recommended you use
"grep -i skeleton *"
to find all instances and replace them to avoid future name collisions.
Building and Using the Plugin
If everything is configured properly, building the plugin is straightforward:
export VFS_DIR=[path/to/vfs_server/server]
export VFS_PLUGINS_DIR=[path/to/plugins/dir]
qmake skeleton.pro && make
Now that the plugin is successfully compiled as a dynamic library, it can be included in a Config File to be created when the application launches. Because provides() returns "skeleton" as the name, we will need to use that as an entry in the config file.
//skeleton.xml
<vfs>
<skeleton name='yorick' alpha='human' beta='120' />
</vfs>
Running the exectuable with this config file will create a VFS that uses this plugin, and will print a warning message when the node is created (or destroyed):
VFS skeleton.xml -plugins $VFS_PLUGINS_DIR
This VFS is not very interesting because we have no way to talk to it and it doesn't do anything useful. The Log Viewer and Animated Clock examples will take things a few steps further.
- See also
- XML Config File(s)
-
Invoking the Server