/*! \file piplugin.h
* \ingroup System
* \~\brief
* \~english Plugin control
* \~russian Управление плагинами
*/
/*
PIP - Platform Independent Primitives
Plugin helpers
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#ifndef PIPLUGIN_H
#define PIPLUGIN_H
#ifndef MICRO_PIP
#include "pilibrary.h"
#include "pistringlist.h"
#ifdef DOXYGEN
//! Declare plugin export functions, should be used before other PIP_PLUGIN_* macros
//! \relatedalso PIPluginLoader
#define PIP_PLUGIN
//! Set user version to check it while loading
//! \relatedalso PIPluginLoader
#define PIP_PLUGIN_SET_USER_VERSION(version)
//! Add pointer to future merge with plugin. Type is integer
//! \relatedalso PIPluginLoader
#define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr)
//! Declare function to merge static sections. This is functions
//! with 3 arguments: (int type, void * from, void * to).
//! This function invoked first while loading plugin with
//! "from" - plugin scope, "to" - application scope, and second
//! (optionally) on \a PIPluginLoader::mergeStatic() method with
//! "from" - application scope, "to" - plugin scope. So with macro
//! you can merge application and plugin static data.
//! \relatedalso PIPluginLoader
#define PIP_PLUGIN_STATIC_SECTION_MERGE
//! Mark method to export
//! \relatedalso PIPluginLoader
#define PIP_PLUGIN_EXPORT
#else
#ifdef WINDOWS
# define PIP_PLUGIN_EXPORT __declspec(dllexport)
#else
# define PIP_PLUGIN_EXPORT
#endif
#define __PIP_PLUGIN_LOADER_VERSION_FUNC__ pip_loader_version
#define __PIP_PLUGIN_STATIC_MERGE_FUNC__ pip_merge_static
#define __PIP_PLUGIN_LOADER_VERSION__ 2
#define PIP_PLUGIN_SET_USER_VERSION(v) \
STATIC_INITIALIZER_BEGIN \
PIPluginInfo * pi = PIPluginInfoStorage::instance()->currentInfo(); \
if (pi) pi->setUserVersion(v); \
STATIC_INITIALIZER_END
#define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) \
STATIC_INITIALIZER_BEGIN \
PIPluginInfo * pi = PIPluginInfoStorage::instance()->currentInfo(); \
if (pi) pi->setStaticSection(type, ptr); \
STATIC_INITIALIZER_END
#define PIP_PLUGIN \
extern "C" { \
PIP_PLUGIN_EXPORT int __PIP_PLUGIN_LOADER_VERSION_FUNC__() {return __PIP_PLUGIN_LOADER_VERSION__;} \
}
#define PIP_PLUGIN_STATIC_SECTION_MERGE \
extern "C" { \
PIP_PLUGIN_EXPORT void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to); \
} \
void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to)
#endif
class PIP_EXPORT PIPluginInfo {
public:
PIPluginInfo();
void setUserVersion(const PIString & v);
void setStaticSection(int type, void * ptr);
PIString userVersion() const;
PIMap staticSections() const;
private:
PIString user_version;
PIMap static_sections;
};
class PIP_EXPORT PIPluginInfoStorage {
public:
PIPluginInfoStorage();
PIPluginInfo * currentInfo();
PIPluginInfo * pluginInfo(void * p);
PIPluginInfo * applicationInfo();
PIPluginInfo * enterPlugin(void * p);
void unloadPlugin(void * p);
static PIPluginInfoStorage * instance();
private:
NO_COPY_CLASS(PIPluginInfoStorage)
void * current;
PIMap info;
};
class PIP_EXPORT PIPluginLoader {
public:
typedef int(*FunctionLoaderVersion)();
typedef void(*FunctionStaticMerge)(int, void *, void *);
//! Possible load plugin error
enum Error {
Unknown /** No \a load call yet */ ,
NoError /** No error */ ,
LibraryLoadError /** System can`t load library */ ,
MissingSymbols /** Can`t find necessary symbols */ ,
InvalidLoaderVersion /** Integer version mismatch */ ,
InvalidUserVersion /** User version mismatch */ ,
};
//! Contruscts loader with filename "name"
PIPluginLoader(const PIString & name = PIString());
//! Destructor
~PIPluginLoader();
//! Load plugin with base filename "name". Loader try prefix "lib"
//! and suffix ".dll", ".so" or ".dylib", depends on platform
bool load(const PIString & name);
//! Unload plugin and free library
void unload();
//! Returns if plugin is successfully loaded
bool isLoaded() const;
//! Returns error of last \a load() call
Error lastError() const;
//! Returns error message of last \a load() call
PIString lastErrorText() const;
//! Set if %PIPluginLoader should print load messages, \b true by default
void setMessages(bool yes);
//! Returns if %PIPluginLoader should print load messages, \b true by default
bool isMessages() const;
//! Returns loaded plugin library path
PIString libPath();
//! Resolve symbol "name" from plugin library
void * resolve(const char * name);
//! Invoke plugin PIP_PLUGIN_STATIC_SECTION_MERGE function
//! on every common type, with "from" - application scope,
//! "to" - plugin scope
void mergeStatic();
static PIStringList pluginsDirectories(const PIString & name);
private:
NO_COPY_CLASS(PIPluginLoader)
PIString findLibrary(const PIString & path);
static PIString libExtension();
PILibrary lib;
FunctionLoaderVersion func_loader_version;
FunctionStaticMerge func_static_merge;
PIString error_str;
Error error;
bool loaded, messages;
};
#endif // MICRO_PIP
#endif // PIPLUGIN_H