This commit is contained in:
2022-04-22 21:19:12 +03:00
parent 91216c4b17
commit 39e4d9a73c
9 changed files with 325 additions and 153 deletions

View File

@@ -26,6 +26,107 @@
#endif
//! \addtogroup System
//! \{
//! \class PILibrary pilibrary.h
//!
//! \~\brief
//! \~english Run-time library
//! \~russian Run-time библиотека
//!
//! \~\details
//! \~english \section _sec0 Synopsis
//! \~russian \section _sec0 Краткий обзор
//! \~english
//! %PILibrary allow you dynamically load external library and use
//! some methods from it. %PILibrary instance contains library
//! pointer and unload library on destructor, so recommended
//! to use it with \b new creation.
//!
//! Main method of %PILibrary is \a resolve(const char *), which returns
//! "void*" pointer to requested method. One should test it
//! to \c nullptr and convert it in pointer to the required method.
//!
//! In case of C++ libraries it`s very important to use C-linkage
//! of exported methods! You may also need to mark methods for
//! export, e.g. \с __declspec(dllexport)
//!
//! \~russian
//! %PILibrary позволяет динамически загружать стороннюю библиотеку
//! и использовать оттуда методы. Экземпляр %PILibrary содержит
//! указатель на библиотеку и выгружает её в деструкторе, поэтому
//! рекомендуется создавать её с помощью \b new.
//!
//! Основной метод %PILibrary - это \a resolve(const char *), который возвращает
//! "void*" указатель на запрошенный метод. Необходимо проверить его
//! на \c nullptr и преобразовать в указатель на нужный метод.
//!
//! В случае C++ библиотеки очень важно использовать C-linkage
//! для экспортируемых методов! Также может понадобиться пометить
//! методы на экспорт, например, \с __declspec(dllexport)
//!
//! \~\code
//! extern "C" {
//! __declspec(dllexport) int exportedSum(int,int);
//! __declspec(dllexport) int exportedMul(int,int);
//! }
//! \endcode
//!
//! \~english \section _sec1 Usage
//! \~russian \section _sec1 Использование
//!
//! \~english Library:
//! \~russian Библиотека:
//! \~\code
//! #include <piplugin.h>
//!
//! extern "C" {
//! PIP_PLUGIN_EXPORT int exportedSum(int,int);
//! PIP_PLUGIN_EXPORT int exportedMul(int,int);
//! }
//!
//! int exportedSum(int a, int b) {
//! return a + b;
//! }
//! int exportedMul(int a, int b) {
//! return a * b;
//! }
//! \endcode
//!
//! \~english Program:
//! \~russian Программа:
//! \~\code
//! int main(int argc, char * argv[]) {
//! typedef int(*MyFunc)(int,int);
//! PILibrary * lib = new PILibrary();
//! if (lib->load("mylib.dll")) {
//! MyFunc fadd = (MyFunc)lib->resolve("exportedSum");
//! MyFunc fmul = (MyFunc)lib->resolve("exportedMul");
//! if (fadd) {
//! int sum = fadd(1, 2);
//! piCout << "sum =" << sum;
//! } else {
//! piCout << "Can`t resolve" << "exportedSum";
//! }
//! if (fmul) {
//! int mul = fadd(10, 20);
//! piCout << "mul =" << mul;
//! } else {
//! piCout << "Can`t resolve" << "exportedMul";
//! }
//! } else {
//! piCout << lib->lastError();
//! }
//! delete lib;
//! }
//!
//! // sum = 3
//! // mul = 30
//! \endcode
//!
//! \}
PRIVATE_DEFINITION_START(PILibrary)
#ifdef WINDOWS
HMODULE

View File

@@ -32,16 +32,43 @@
class PIP_EXPORT PILibrary {
public:
//! \~english Constructs %PILibrary and load if "path_" not empty
//! \~russian Создает %PILibrary и загружает если "path_" не пустой
PILibrary(const PIString & path_ = PIString());
//! \~english Destroy %PILibrary, unload if library was loaded
//! \~russian Уничтожает %PILibrary и выгружает библиотеку, если она была загружена
~PILibrary();
//! \~english Load library with relative or absolute path "path_"
//! \~russian Загружает библиотеку по относительному или абсолютному пути "path_"
bool load(const PIString & path_);
//! \~english Load library with \a path() path
//! \~russian Загружает библиотеку по пути \a path()
bool load();
//! \~english Unload library if it was loaded
//! \~russian Выгружает библиотеку, если она была загружена
void unload();
//! \~english Obtain exported library method with name "symbol"
//! \~russian Получает экспортированный метод библиотеки с именем "symbol"
void * resolve(const char * symbol);
//! \~english Returns if library successfully loaded
//! \~russian Возвращает успешно ли загружена библиотека
bool isLoaded() const;
//! \~english Returns library path
//! \~russian Возвращает путь к библиотеке
PIString path() const {return libpath;}
//! \~english Returns last occured error in human-readable format
//! \~russian Возвращает последнюю ошибку в читаемом виде
PIString lastError() const {return liberror;}
private:

View File

@@ -24,139 +24,144 @@
#include "pidir.h"
#include "piincludes_p.h"
/*! \class PIPluginLoader
* \brief Plugin loader
*
* \section PIPluginLoader_sec0 Synopsis
* This class provides several macro to define plugin and %PIPluginLoader - class
* to load and check plugin.
*
* \section PIPluginLoader_sec1 Plugin side
* Plugin is a shared library that can be loaded in run-time.
* This is only PIP_PLUGIN macro necessary to define plugin.
* If you want to set and check some version, use macro
* \a PIP_PLUGIN_SET_USER_VERSION(version). Also you can
* define a function to merge static sections between application
* and plugin with macro \a PIP_PLUGIN_STATIC_SECTION_MERGE. Before
* merge, you should set pointers to that sections with macro
* \a PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr).
*
* \section PIPluginLoader_sec2 Application side
* Application should use class \a PIPluginLoader to load
* plugin. Main function is \a load(PIString name).
* "name" is base name of library, %PIPluginLoader
* try to use sevaral names, \<name\>, lib\<name\> and
* "dll", "so" and "dylib" extensions, depends on system.
* For example:
* \code
* PIPluginLoader l;
* l.load("foo");
* \endcode
* On Windows, try to open "foo", "libfoo", "foo.dll" and
* "libfoo.dll".
* If you using user version check, you should set it
* with macro \a PIP_PLUGIN_SET_USER_VERSION(version).
* When plugin is successfully loaded and checked,
* you can load your custom symbols with function
* \a resolve(name), similar to PILibrary.
* \note You should use PIP_PLUGIN_EXPORT and "export "C""
* with functions you want to use with \a resolve(name)!
*
* \section PIPluginLoader_sec3 Static sections
* Macro \a PIP_PLUGIN_STATIC_SECTION_MERGE defines function
* with arguments (int type, void * from, void * to), so you
* can leave this macro as declaration or define its body next:
* \code
* PIP_PLUGIN_STATIC_SECTION_MERGE() {
* switch (type) {
* ...
* }
* }
* \endcode
* \note If you using singletones, remember that cpp-defined
* singletones in shared libraries are single for whole application,
* including plugins! But if you use h-defined singletones or
* static linking, there are many objects in application and you
* should merge their content with this macro.
*
* Anyway, if this is macro \a PIP_PLUGIN_STATIC_SECTION_MERGE, it
* called once while loading plugin with "from" - plugin side
* and "to" - application side, and second (optionally) on method
* \a mergeStatic() with "from" - application side and "to" - plugin side.
* First direction allow you to copy all defined static content from plugin
* to application, and second - after loading all plugins (for example)
* to copy static content from application (and all plugins) to plugin.
*
* \section PIPluginLoader_sec4 Examples
* Simple plugin:
* \code
* #include <piplugin.h>
*
* PIP_PLUGIN
*
* extern "C" {
* PIP_PLUGIN_EXPORT void myFunc() {
* piCout << "Hello plugin!";
* }
* }
* \endcode
*
* Application:
* \code
* #include <piplugin.h>
* int main() {
* PIPluginLoader pl;
* pl.load("your_lib");
* if (pl.isLoaded()) {
* typedef void(*MyFunc)();
* MyFunc f = (MyFunc)pl.resolve("myFunc");
* if (f) f();
* }
* return 0;
* }
* \endcode
*
* Complex plugin:
* \code
* #include <piplugin.h>
*
* PIStringList global_list;
*
* PIP_PLUGIN
* PIP_PLUGIN_SET_USER_VERSION("1.0.0")
* PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list)
*
* STATIC_INITIALIZER_BEGIN
* global_list << "plugin_init";
* STATIC_INITIALIZER_END
*
* PIP_PLUGIN_STATIC_SECTION_MERGE {
* PIStringList * sfrom = (PIStringList*)from, * sto = (PIStringList*)to;
* *sto << *sfrom;
* sto->removeDuplicates();
* }
* \endcode
*
* Application:
* \code
* #include <piplugin.h>
*
* PIStringList global_list;
*
* PIP_PLUGIN_SET_USER_VERSION("1.0.0");
* PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list);
*
* int main() {
* global_list << "app";
* PIPluginLoader pl;
* pl.load("your_lib");
* pl.mergeStatic();
* piCout << "list =" << global_list;
* return 0;
* }
* \endcode
*
*/
//! \addtogroup System
//! \{
//! \class PIPluginLoader piplugin.h
//!
//! \brief
//! \~english Plugin loader
//! \~russian Загрузчик плагина
//!
//! \section PIPluginLoader_sec0 Synopsis
//! This class provides several macro to define plugin and %PIPluginLoader - class
//! to load and check plugin.
//!
//! \section PIPluginLoader_sec1 Plugin side
//! Plugin is a shared library that can be loaded in run-time.
//! This is only PIP_PLUGIN macro necessary to define plugin.
//! If you want to set and check some version, use macro
//! \a PIP_PLUGIN_SET_USER_VERSION(version). Also you can
//! define a function to merge static sections between application
//! and plugin with macro \a PIP_PLUGIN_STATIC_SECTION_MERGE. Before
//! merge, you should set pointers to that sections with macro
//! \a PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr).
//!
//! \section PIPluginLoader_sec2 Application side
//! Application should use class \a PIPluginLoader to load
//! plugin. Main function is \a load(PIString name).
//! "name" is base name of library, %PIPluginLoader
//! try to use sevaral names, \<name\>, lib\<name\> and
//! "dll", "so" and "dylib" extensions, depends on system.
//! For example:
//! \code
//! PIPluginLoader l;
//! l.load("foo");
//! \endcode
//! On Windows, try to open "foo", "libfoo", "foo.dll" and
//! "libfoo.dll".
//! If you using user version check, you should set it
//! with macro \a PIP_PLUGIN_SET_USER_VERSION(version).
//! When plugin is successfully loaded and checked,
//! you can load your custom symbols with function
//! \a resolve(name), similar to PILibrary.
//! \note You should use PIP_PLUGIN_EXPORT and "export "C""
//! with functions you want to use with \a resolve(name)!
//!
//! \section PIPluginLoader_sec3 Static sections
//! Macro \a PIP_PLUGIN_STATIC_SECTION_MERGE defines function
//! with arguments (int type, void * from, void * to), so you
//! can leave this macro as declaration or define its body next:
//! \code
//! PIP_PLUGIN_STATIC_SECTION_MERGE() {
//! switch (type) {
//! ...
//! }
//! }
//! \endcode
//! \note If you using singletones, remember that cpp-defined
//! singletones in shared libraries are single for whole application,
//! including plugins! But if you use h-defined singletones or
//! static linking, there are many objects in application and you
//! should merge their content with this macro.
//!
//! Anyway, if this is macro \a PIP_PLUGIN_STATIC_SECTION_MERGE, it
//! called once while loading plugin with "from" - plugin side
//! and "to" - application side, and second (optionally) on method
//! \a mergeStatic() with "from" - application side and "to" - plugin side.
//! First direction allow you to copy all defined static content from plugin
//! to application, and second - after loading all plugins (for example)
//! to copy static content from application (and all plugins) to plugin.
//!
//! \section PIPluginLoader_sec4 Examples
//! Simple plugin:
//! \code
//! #include <piplugin.h>
//!
//! PIP_PLUGIN
//!
//! extern "C" {
//! PIP_PLUGIN_EXPORT void myFunc() {
//! piCout << "Hello plugin!";
//! }
//! }
//! \endcode
//!
//! Application:
//! \code
//! #include <piplugin.h>
//! int main() {
//! PIPluginLoader pl;
//! pl.load("your_lib");
//! if (pl.isLoaded()) {
//! typedef void(*MyFunc)();
//! MyFunc f = (MyFunc)pl.resolve("myFunc");
//! if (f) f();
//! }
//! return 0;
//! }
//! \endcode
//!
//! Complex plugin:
//! \code
//! #include <piplugin.h>
//!
//! PIStringList global_list;
//!
//! PIP_PLUGIN
//! PIP_PLUGIN_SET_USER_VERSION("1.0.0")
//! PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list)
//!
//! STATIC_INITIALIZER_BEGIN
//! global_list << "plugin_init";
//! STATIC_INITIALIZER_END
//!
//! PIP_PLUGIN_STATIC_SECTION_MERGE {
//! PIStringList * sfrom = (PIStringList*)from, * sto = (PIStringList*)to;
//! *sto << *sfrom;
//! sto->removeDuplicates();
//! }
//! \endcode
//!
//! Application:
//! \code
//! #include <piplugin.h>
//!
//! PIStringList global_list;
//!
//! PIP_PLUGIN_SET_USER_VERSION("1.0.0");
//! PIP_PLUGIN_ADD_STATIC_SECTION(1, &global_list);
//!
//! int main() {
//! global_list << "app";
//! PIPluginLoader pl;
//! pl.load("your_lib");
//! pl.mergeStatic();
//! piCout << "list =" << global_list;
//! return 0;
//! }
//! \endcode
//!
//! \}
#define STR_WF(s) #s
#define STR(s) STR_WF(s)