Files
pip/libs/main/system/piplugin.h
2026-03-12 14:46:57 +03:00

305 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! \~\ingroup System
//! \~\file piplugin.h
//! \~\brief
//! \~english Plugin control
//! \~russian Управление плагинами
//! \~\details
//! \~english Plugin helpers for dynamic library loading and plugin management
//! \~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 <http://www.gnu.org/licenses/>.
*/
#ifndef PIPLUGIN_H
#define PIPLUGIN_H
#ifndef MICRO_PIP
# include "pilibrary.h"
# include "pistringlist.h"
# ifdef DOXYGEN
//! \relatesalso PIPluginLoader
//! \~\brief
//! \~english Declares plugin entry points and should be used before other \c PIP_PLUGIN_* macros.
//! \~russian Объявляет точки входа плагина и должен использоваться перед другими макросами \c PIP_PLUGIN_*.
# define PIP_PLUGIN
//! \relatesalso PIPluginLoader
//! \~\brief
//! \~english Sets user version checked during loading, "version" is quoted string.
//! \~russian Устанавливает строковую пользовательскую версию, проверяемую при загрузке, "version" - строка в кавычках.
# define PIP_PLUGIN_SET_USER_VERSION(version)
//! \relatesalso PIPluginLoader
//! \~\brief
//! \~english Registers a static section pointer for future merge. \a type is an integer key.
//! \~russian Регистрирует указатель на статическую секцию для последующего слияния. \a type - целочисленный ключ.
# define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr)
//! \relatesalso PIPluginLoader
//! \~\brief
//! \~english Declares a function that merges plugin and application static sections.
//! \~russian Объявляет функцию для слияния статических секций плагина и приложения.
//! \~\details
//! \~english
//! 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.
//! \~russian
//! Этот метод имеет 3 аргумента: (int type, void * from, void * to).
//! Он вызывается первый раз при загрузке плагина с "from" - областью плагина,
//! "to" - областью приложения, и второй раз (необязательно) при вызове
//! \a PIPluginLoader::mergeStatic() с "from" - областью приложения и
//! "to" - областью плагина. Таким образом, этот макрос позволяет провести
//! слияние статических данных приложения и плагина.
//! \~\relatesalso PIPluginLoader
# define PIP_PLUGIN_STATIC_SECTION_MERGE
//! \relatesalso PIPluginLoader
//! \~\brief
//! \~english Marks a plugin function for export.
//! \~russian Помечает функцию плагина для экспорта.
# 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
//! \~\ingroup System
//! \~\brief
//! \~english Metadata collected for one plugin or for the host application.
//! \~russian Метаданные, собираемые для одного плагина или для основного приложения.
class PIP_EXPORT PIPluginInfo {
public:
//! \~english Constructs empty plugin metadata.
//! \~russian Создает пустые метаданные плагина.
PIPluginInfo();
//! \~english Sets user version checked by \a PIPluginLoader::load().
//! \~russian Устанавливает пользовательскую версию, проверяемую в \a PIPluginLoader::load().
void setUserVersion(const PIString & v);
//! \~english Associates a static section pointer with integer \a type.
//! \~russian Связывает указатель на статическую секцию с целочисленным типом \a type.
void setStaticSection(int type, void * ptr);
//! \~english Returns configured user version string.
//! \~russian Возвращает установленную строку пользовательской версии.
PIString userVersion() const;
//! \~english Returns registered static section pointers.
//! \~russian Возвращает зарегистрированные указатели статических секций.
PIMap<int, void *> staticSections() const;
private:
PIString user_version;
PIMap<int, void *> static_sections;
};
//! \~\ingroup System
//! \~\brief
//! \~english Storage of plugin metadata for the application and loaded plugins.
//! \~russian Хранилище метаданных плагинов для приложения и загруженных плагинов.
class PIP_EXPORT PIPluginInfoStorage {
public:
//! \~english Creates storage and initializes application metadata entry.
//! \~russian Создает хранилище и инициализирует запись метаданных приложения.
PIPluginInfoStorage();
//! \~english Returns metadata of the current initialization scope.
//! \~russian Возвращает метаданные текущей области инициализации.
PIPluginInfo * currentInfo();
//! \~english Returns metadata associated with plugin pointer \a p.
//! \~russian Возвращает метаданные, связанные с указателем плагина \a p.
PIPluginInfo * pluginInfo(void * p);
//! \~english Returns metadata entry of the host application.
//! \~russian Возвращает запись метаданных основного приложения.
PIPluginInfo * applicationInfo();
//! \~english Enters plugin scope \a p and creates metadata entry if needed.
//! \~russian Переходит в область плагина \a p и при необходимости создает запись метаданных.
PIPluginInfo * enterPlugin(void * p);
//! \~english Removes metadata associated with plugin pointer \a p.
//! \~russian Удаляет метаданные, связанные с указателем плагина \a p.
void unloadPlugin(void * p);
//! \~english Returns process-wide singleton storage.
//! \~russian Возвращает глобальный синглтон хранилища.
static PIPluginInfoStorage * instance();
private:
NO_COPY_CLASS(PIPluginInfoStorage);
void * current;
PIMap<void *, PIPluginInfo *> info;
};
//! \~\ingroup System
//! \~\brief
//! \~english Plugin loader.
//! \~russian Загрузчик плагина.
//! \details
//! \~english Handles dynamic library loading, symbol resolution, and plugin lifecycle management
//! \~russian Управляет загрузкой динамических библиотек, разрешением символов и жизненным циклом плагинов
class PIP_EXPORT PIPluginLoader {
public:
//! \~english Signature of the exported loader version function.
//! \~russian Сигнатура экспортируемой функции версии загрузчика.
typedef int (*FunctionLoaderVersion)();
//! \~english Signature of the exported static merge function.
//! \~russian Сигнатура экспортируемой функции слияния статических секций.
typedef void (*FunctionStaticMerge)(int, void *, void *);
//! \~english Possible load plugin error
//! \~russian Возможные ошибки загрузки плагина
enum Error {
Unknown /** \~english No \a load() call yet \~russian Не было вызова \a load() */,
NoError /** \~english No error \~russian Нет ошибки */,
NoSuchFile /** \~english Can`t find library file \~russian Не найден файл библиотеки */,
LibraryLoadError /** \~english System can`t load library \~russian Система не смогла загрузить библиотеку */,
MissingSymbols /** \~english Can`t find necessary symbols \~russian Нет необходимых методов */,
InvalidLoaderVersion /** \~english Internal version mismatch \~russian Неверная внутренняя версия */,
InvalidUserVersion /** \~english User version mismatch \~russian Неверная пользовательская версия */,
};
//! \~english Contruct loader with base filename "name" and call \a load() if "name" not empty
//! \~russian Создает загрузчик с базовым именем файла "name" и вызывает \a load() если "name" не пустое
PIPluginLoader(const PIString & name = PIString());
//! \~english Destructor, unload library
//! \~russian Деструктор, выгружает библиотеку
~PIPluginLoader();
//! \~english Loads plugin by base filename \a name and updates error state on failure.
//! \~russian Загружает плагин по базовому имени файла \a name и обновляет состояние ошибки при неудаче.
bool load(const PIString & name);
//! \~english Unload plugin and free library
//! \~russian Выгружает плагин и освобождает библиотеку
void unload();
//! \~english Returns if plugin is successfully loaded
//! \~russian Возвращает успешно ли загружен плагин
bool isLoaded() const;
//! \~english Returns error of last \a load() call
//! \~russian Возвращает ошибку последнего вызова \a load()
Error lastError() const;
//! \~english Returns error message of last \a load() call
//! \~russian Возвращает сообщение об ошибке последнего вызова \a load()
PIString lastErrorText() const;
//! \~english Set if %PIPluginLoader should print load messages, \b true by default
//! \~russian Устанавливает должен ли %PIPluginLoader выводить сообщения, \b true по умолчанию
void setMessages(bool yes);
//! \~english Returns if %PIPluginLoader should print load messages, \b true by default
//! \~russian Возвращает должен ли %PIPluginLoader выводить сообщения, \b true по умолчанию
bool isMessages() const;
//! \~english Returns loaded plugin library path
//! \~russian Возвращает путь к загруженной библиотеке
PIString libPath();
//! \~english Obtain exported library method with name "symbol"
//! \~russian Получает экспортированный метод библиотеки с именем "symbol"
//! \~\sa PILibrary::resolve()
void * resolve(const char * name);
//! \~english Invoke plugin \a PIP_PLUGIN_STATIC_SECTION_MERGE
//! \~russian Вызывает у плагина \a PIP_PLUGIN_STATIC_SECTION_MERGE
//! \details
//! \~english Calls the plugin's static section merge function to synchronize application and plugin data
//! \~russian Вызывает функцию слияния статических секций плагина для синхронизации данных приложения и плагина
void mergeStatic();
//! \~english Returns existing plugin directories for subdirectory \a name.
//! \~russian Возвращает существующие каталоги плагинов для подкаталога \a name.
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