PIPluginLoader #45

Manually merged
peri4 merged 6 commits from plugin into master 2020-10-06 10:08:20 +03:00
20 changed files with 607 additions and 102 deletions

View File

@@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
project(pip)
set(pip_MAJOR 2)
set(pip_MINOR 10)
set(pip_REVISION 0)
set(pip_REVISION 1)
set(pip_SUFFIX )
set(pip_COMPANY SHS)
set(pip_DOMAIN org.SHS)
@@ -433,6 +433,9 @@ if (NOT CROSSTOOLS)
# Test program
if(PIP_UTILS)
#add_library(pip_plugin SHARED "test_plugin.h" "test_plugin.cpp")
#target_link_libraries(pip_plugin pip)
add_executable(pip_test "main.cpp")
target_link_libraries(pip_test pip pip_cloud)
if (LUA_FOUND)

View File

@@ -174,6 +174,13 @@ inline const char * getMemberType(const char * class_name, const char * member_n
PIP_EXPORT PIVariant getMemberAsVariant(const void * p, const char * class_name, const char * member_name);
template<typename T, typename std::enable_if< std::is_assignable<T&, const T&>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {ret << v;}
template<typename T, typename std::enable_if<!std::is_assignable<T&, const T&>::value, int>::type = 0>
void serialize(PIByteArray & ret, const T & v) {}
}
class PIP_EXPORT __PICodeInfoInitializer__ {

View File

@@ -401,3 +401,14 @@ PIByteArray & operator >>(PIByteArray & s, PIByteArray & v) {
}
return s;
}
PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {
s << int(v.size_s());
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s());
memcpy(s.data(os), v.data(), v.size());
}
return s;
}

View File

@@ -175,27 +175,18 @@ inline PIByteArray & operator <<(PIByteArray & s, const char v) {s.push_back(v);
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const uchar v) {s.push_back(v); return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, const PIChar & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;}
//! \relatesalso PIByteArray \brief Store operator
template<typename T> inline PIByteArray & operator <<(PIByteArray & s, const PIFlags<T> & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;}
//! \relatesalso PIByteArray \brief Store operator for any trivial copyable type
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator <<(PIByteArray & s, const T & v) {int os = s.size_s(); s.enlarge(sizeof(v)); memcpy(s.data(os), &v, sizeof(v)); return s;}
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v) {
s << int(v.size_s());
inline PIByteArray & operator <<(PIByteArray & s, const T & v) {
int os = s.size_s();
if (v.size_s() > 0) {
s.enlarge(v.size_s());
memcpy(s.data(os), v.data(), v.size());
}
s.enlarge(sizeof(v));
memcpy(s.data(os), &v, sizeof(v));
return s;
}
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
PIP_EXPORT PIByteArray & operator <<(PIByteArray & s, const PIByteArray & v);
//! \relatesalso PIByteArray \brief Store operator, see \ref PIByteArray_sec1 for details
inline PIByteArray & operator <<(PIByteArray & s, const PIByteArray::RawData & v) {
int os = s.size_s();
@@ -264,15 +255,14 @@ inline PIByteArray & operator >>(PIByteArray & s, char & v) {assert(s.size() >=
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, uchar & v) {assert(s.size() >= 1u); v = s.take_front(); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, PIChar & v) {assert(s.size() >= sizeof(v)); memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;}
//! \relatesalso PIByteArray \brief Restore operator for any trivial copyable type
template<typename T, typename std::enable_if< std::is_trivially_copyable<T>::value, int>::type = 0>
inline PIByteArray & operator >>(PIByteArray & s, T & v) {assert(s.size() >= sizeof(v)); memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;}
//! \relatesalso PIByteArray \brief Restore operator
template<typename T> inline PIByteArray & operator >>(PIByteArray & s, PIFlags<T> & v) {memcpy((void*)(&v), s.data(), sizeof(v)); s.remove(0, sizeof(v)); return s;}
inline PIByteArray & operator >>(PIByteArray & s, T & v) {
assert(s.size() >= sizeof(v));
memcpy((void*)(&v), s.data(), sizeof(v));
s.remove(0, sizeof(v));
return s;
}
//! \relatesalso PIByteArray \brief Restore operator, see \ref PIByteArray_sec1 for details
PIP_EXPORT PIByteArray & operator >>(PIByteArray & s, PIByteArray & v);

View File

@@ -32,8 +32,6 @@ extern PIP_EXPORT char * __utf8name__;
class PIP_EXPORT PIChar
{
friend class PIString;
friend PIByteArray & operator <<(PIByteArray & s, const PIChar & v);
friend PIByteArray & operator >>(PIByteArray & s, PIChar & v);
friend PICout PIP_EXPORT operator <<(PICout s, const PIChar & v);
public:
//! Contructs ascii symbol

View File

@@ -38,8 +38,6 @@ public:
PIFlags(): flags(0) {;}
//! Constructor with flags = Enum "e"
PIFlags(Enum e): flags(e) {;}
//! Constructor with flags = PIFlags "f"
PIFlags(const PIFlags & f): flags(f.flags) {;}
//! Constructor with flags = int "i"
PIFlags(const int i): flags(i) {;}
//! Set flags "f" to value "on"
@@ -49,8 +47,6 @@ public:
//! Set flag "i" to value "on"
PIFlags & setFlag(const int & i, bool on = true) {if (on) flags |= i; else flags &= ~i; return *this;}
//! copy operator
void operator =(const PIFlags & f) {flags = f.flags;}
//! copy operator
void operator =(const Enum & e) {flags = e;}
//! copy operator
void operator =(const int & i) {flags = i;}

View File

@@ -79,6 +79,22 @@ PIString PIPVersion() {
return ret;
}
void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
qsort(base, num, size, compar);
}
void randomize() {
srand(PISystemTime::current(true).nanoseconds);
}
int randomi() {
return rand();
}
/*! \class PICout
* \brief Class for formatted output similar std::cout
*
@@ -131,6 +147,9 @@ PIString PIPVersion() {
* * packets extractor (\a PIPacketExtractor)
* * binary log (\a PIBinaryLog)
* * complex I/O point (\a PIConnection)
* * Run-time libraries
* * abstract (\a PILibrary)
* * plugin (\a PIPluginLoader)
* * connection quality diagnotic (\a PIDiagnostics)
* * command-line arguments parser (\a PICLI)
* * math evaluator (\a PIEvaluator)
@@ -247,19 +266,3 @@ int main(int argc, char * argv[]) {
/*! \page using_advanced Advanced using
* Sorry, creativity crysis xD
*/
void piqsort(void * base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
qsort(base, num, size, compar);
}
void randomize() {
srand(PISystemTime::current(true).nanoseconds);
}
int randomi() {
return rand();
}

View File

@@ -162,12 +162,12 @@ public:
*/
void setPropertyComment(const PIString & name, const PIString & comment);
/**
* @brief Set flags of property with specific name if name is present in storage.
*
* @param name of property to set flags
* @param flags to set
*/
/**
* @brief Set flags of property with specific name if name is present in storage.
*
* @param name of property to set flags
* @param flags to set
*/
void setPropertyFlags(const PIString & name, int flags);
PIPropertyStorage & operator <<(const PIPropertyStorage::Property & p) {props << p; return *this;}

View File

@@ -60,8 +60,6 @@ public:
//! Contructs system time with s = "s" and ns = "ns"
PISystemTime(int s, int ns) {seconds = s; nanoseconds = ns; checkOverflows();}
//! Contructs system time from another
PISystemTime(const PISystemTime & t) {seconds = t.seconds; nanoseconds = t.nanoseconds;}
//! Returns stored system time value in seconds
double toSeconds() const {return double(seconds) + nanoseconds / 1.e+9;}
@@ -172,13 +170,6 @@ private:
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
inline PICout operator <<(PICout s, const PISystemTime & v) {s.space(); s.setControl(0, true); s << "(" << v.seconds << " s, " << v.nanoseconds << " ns)"; s.restoreControl(); return s;}
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Output operator to PIByteArray
inline PIByteArray & operator <<(PIByteArray & s, const PISystemTime & v) {s << v.seconds << v.nanoseconds; return s;}
//! \relatesalso PISystemTime \relatesalso PIByteArray \brief Input operator from PIByteArray
inline PIByteArray & operator >>(PIByteArray & s, PISystemTime & v) {s >> v.seconds >> v.nanoseconds; return s;}
struct PIP_EXPORT PITime {
@@ -199,8 +190,6 @@ PIP_EXPORT bool operator >(const PITime & t0, const PITime & t1);
inline bool operator !=(const PITime & t0, const PITime & t1) {return !(t0 == t1);}
inline bool operator <=(const PITime & t0, const PITime & t1) {return !(t0 > t1);}
inline bool operator >=(const PITime & t0, const PITime & t1) {return !(t0 < t1);}
inline PIByteArray & operator <<(PIByteArray & s, const PITime & v) {s << v.hours << v.minutes << v.seconds << v.milliseconds; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PITime & v) {s >> v.hours >> v.minutes >> v.seconds >> v.milliseconds; return s;}
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PITime & v);
@@ -223,8 +212,6 @@ PIP_EXPORT bool operator >(const PIDate & t0, const PIDate & t1);
inline bool operator !=(const PIDate & t0, const PIDate & t1) {return !(t0 == t1);}
inline bool operator <=(const PIDate & t0, const PIDate & t1) {return !(t0 > t1);}
inline bool operator >=(const PIDate & t0, const PIDate & t1) {return !(t0 < t1);}
inline PIByteArray & operator <<(PIByteArray & s, const PIDate & v) {s << v.year << v.month << v.day; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIDate & v) {s >> v.year >> v.month >> v.day; return s;}
//! \relatesalso PICout \relatesalso PICout \brief Output operator to PICout
PIP_EXPORT PICout operator <<(PICout s, const PIDate & v);

View File

@@ -40,12 +40,21 @@ public:
virtual void deleteT(void *& ptr) {;}
//virtual PIByteArray toData(const void * ptr) const {return PIByteArray();}
//virtual void fromData(void *& ptr, PIByteArray ba) {;}
static PIMap<uint, __VariantFunctionsBase__*> & registered() {static PIMap<uint, __VariantFunctionsBase__*> ret; return ret;}
//static PIMap<uint, __VariantFunctionsBase__*> & registered() {static PIMap<uint, __VariantFunctionsBase__*> ret; return ret;}
};
/*
template<class T, class Enable = void>
class __VariantFunctions__: public __VariantFunctionsBase__ {
public:
__VariantFunctionsBase__ * instance() final {static __VariantFunctions__<T> ret; return &ret;}
PIString typeName() const final {static PIString ret(typeid(T).name()); return ret;}
uint hash() const final {static uint ret = typeName().hash(); return ret;}
};
*/
template<typename T>
class __VariantFunctions__: public __VariantFunctionsBase__ {
class __VariantFunctions__/*<T, typename std::enable_if< std::is_assignable<T&, const T&>::value>::type>*/: public __VariantFunctionsBase__ {
public:
__VariantFunctionsBase__ * instance() final {static __VariantFunctions__<T> ret; return &ret;}
PIString typeName() const final {static PIString ret(typeid(T).name()); return ret;}
@@ -58,6 +67,7 @@ public:
//void fromData(void *& ptr, PIByteArray ba) final {ba >> *(T*)ptr;}
};
class PIVariantSimple {
public:
PIVariantSimple() {ptr = 0; f = 0;}
@@ -129,6 +139,7 @@ public:
private:
template <typename T>
bool isMyType() const {
if (!f) return false;
uint mh = f->hash(), th = __VariantFunctions__<T>().instance()->hash();
if (mh == 0 || th == 0) return false;
return mh == th;
@@ -146,13 +157,13 @@ private:
};
/*
#define REGISTER_PIVARIANTSIMPLE_STREAM(Type) \
STATIC_INITIALIZER_BEGIN() \
__VariantFunctionsBase__ * f = __VariantFunctions__<Type>().instance(); \
__VariantFunctionsBase__::registered()[f->hash()] = f; \
STATIC_INITIALIZER_END()
*/
#endif // PIVARIANTSIMPLE_H

View File

@@ -65,8 +65,6 @@ public:
//! \brief IPv4 network address, IP and port
class PIP_EXPORT Address {
friend class PIEthernet;
friend inline PIByteArray & operator <<(PIByteArray & s, const PIEthernet::Address & v);
friend inline PIByteArray & operator >>(PIByteArray & s, PIEthernet::Address & v);
public:
//! Contructs %Address with binary representation of IP and port
@@ -519,7 +517,5 @@ inline PICout operator <<(PICout s, const PIEthernet::Address & v) {s.space(); s
inline bool operator ==(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() == v1.ip() && v0.port() == v1.port());}
inline bool operator !=(const PIEthernet::Address & v0, const PIEthernet::Address & v1) {return (v0.ip() != v1.ip() || v0.port() != v1.port());}
inline PIByteArray & operator <<(PIByteArray & s, const PIEthernet::Address & v) {s << v.ip_ << v.port_; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIEthernet::Address & v) {s >> v.ip_ >> v.port_; return s;}
#endif // PIETHERNET_H

View File

@@ -59,12 +59,6 @@ public:
template<typename Type>
PICout operator <<(PICout & s, const PIPoint<Type> & v) {s.setControl(0, true); s << "Point{" << v.x << ", " << v.y << "}"; s.restoreControl(); return s;}
template<typename Type>
inline PIByteArray & operator <<(PIByteArray & s, const PIPoint<Type> & v) {s << v.x << v.y; return s;}
template<typename Type>
inline PIByteArray & operator >>(PIByteArray & s, PIPoint<Type> & v) {s >> v.x >> v.y; return s;}
typedef PIPoint<int> PIPointi;
typedef PIPoint<uint> PIPointu;
@@ -145,12 +139,6 @@ public:
template<typename Type>
PICout operator <<(PICout & s, const PIRect<Type> & v) {s.setControl(0, true); s << "Rect{" << v.x0 << ", " << v.y0 << "; " << v.x1 - v.x0 << ", " << v.y1 - v.y0 << "}"; s.restoreControl(); return s;}
template<typename Type>
inline PIByteArray & operator <<(PIByteArray & s, const PIRect<Type> & v) {s << v.x0 << v.x1 << v.y0 << v.y1; return s;}
template<typename Type>
inline PIByteArray & operator >>(PIByteArray & s, PIRect<Type> & v) {s >> v.x0 >> v.x1 >> v.y0 >> v.y1; return s;}
typedef PIRect<int> PIRecti;
typedef PIRect<uint> PIRectu;

View File

@@ -69,20 +69,6 @@ inline complexd log10(const complexd & c) {return log(c) / M_LN10;}
template<typename T>
inline PICout operator <<(PICout s, const complex<T> & v) {s.space(); s.setControl(0, true); s << "(" << v.real() << "; " << v.imag() << ")"; s.restoreControl(); return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, complexf v) {float t; t = v.real(); s << t; t = v.imag(); s << t; return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, complexd v) {double t; t = v.real(); s << t; t = v.imag(); s << t; return s;}
//! \relatesalso PIByteArray \brief Store operator
inline PIByteArray & operator <<(PIByteArray & s, complexld v) {ldouble t; t = v.real(); s << t; t = v.imag(); s << t; return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, complexf & v) {float t0, t1; s >> t0; s >> t1; v = complexf(t0, t1); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, complexd & v) {double t0, t1; s >> t0; s >> t1; v = complexd(t0, t1); return s;}
//! \relatesalso PIByteArray \brief Restore operator
inline PIByteArray & operator >>(PIByteArray & s, complexld & v) {ldouble t0, t1; s >> t0; s >> t1; v = complexld(t0, t1); return s;}
inline PIVector<double> abs(const PIVector<complexd> & v) {
PIVector<double> result;

View File

@@ -130,6 +130,7 @@ inline PIByteArray & operator <<(PIByteArray & s, const PIMathVectorT<Size, Type
template<uint Size, typename Type>
inline PIByteArray & operator >>(PIByteArray & s, PIMathVectorT<Size, Type> & v) {for (uint i = 0; i < Size; ++i) s >> v[i]; return s;}
template<typename T>
inline PIMathVectorT<2u, T> createVectorT2(T x, T y) {return PIMathVectorT<2u, T>(PIVector<T>() << x << y);}
template<typename T>

View File

@@ -1,3 +1,6 @@
/*! \file pilibrary.h
* \brief Dynamic library
*/
/*
PIP - Platform Independent Primitives
Dynamic library

View File

@@ -0,0 +1,338 @@
/*
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 PIP_FREERTOS
#include "piplugin.h"
#include "pifile.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 cymbols 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)
PIPluginInfo::PIPluginInfo() {
in_plugin = false;
}
void PIPluginInfo::setUserVersion(const PIString & v) {
user_version[in_plugin ? 1 : 0] = v;
}
void PIPluginInfo::setStaticSection(int type, void * ptr) {
static_sections[in_plugin ? 1 : 0][type] = ptr;
}
PIString PIPluginInfo::userVersion(bool plugin) const {
return user_version[plugin ? 1 : 0];
}
PIMap<int, void *> PIPluginInfo::staticSections(bool plugin) const {
return static_sections[plugin ? 1 : 0];
}
void PIPluginInfo::enterPlugin() {
in_plugin = true;
}
PIPluginInfo * PIPluginInfo::instance() {
static PIPluginInfo ret;
return &ret;
}
PIPluginLoader::PIPluginLoader(const PIString & name) {
func_loader_version = nullptr;
func_plugin_info = nullptr;
func_static_merge = nullptr;
plugin_info = nullptr;
loaded = false;
if (!name.isEmpty())
load(name);
}
PIPluginLoader::~PIPluginLoader() {
lib.unload();
}
bool PIPluginLoader::load(const PIString & name) {
unload();
if (!lib.load(findLibrary(name))) return false;
//piCout << "loading" << lib.path() << "...";
func_loader_version = (FunctionLoaderVersion)lib.resolve(STR(__PIP_PLUGIN_LOADER_VERSION_FUNC__));
if (!func_loader_version) {
piCout << "Load plugin \"" << name << "\" error: can`t find" << STR(__PIP_PLUGIN_LOADER_VERSION_FUNC__);
unload();
return false;
}
if (__PIP_PLUGIN_LOADER_VERSION__ != func_loader_version()) {
piCout << "Load plugin \"" << name << "\" error: invalid loader version: plugin" << __PIP_PLUGIN_LOADER_VERSION__ << "!=" << func_loader_version();
unload();
return false;
}
func_plugin_info = (FunctionPluginInfo)lib.resolve(STR(__PIP_PLUGIN_PLUGIN_INFO_FUNC__));
if (!func_plugin_info) {
piCout << "Load plugin \"" << name << "\" error: can`t find" << STR(__PIP_PLUGIN_PLUGIN_INFO_FUNC__);
unload();
return false;
}
plugin_info = func_plugin_info();
if (!plugin_info) {
piCout << "Load plugin \"" << name << "\" error: null PIPluginInfo";
unload();
return false;
}
if (PIPluginInfo::instance()->userVersion(false).size_s() > 1) {
PIString pversion = plugin_info->userVersion(true), lversion = PIPluginInfo::instance()->userVersion(false);
if (pversion != lversion) {
piCout << "Load plugin \"" << name << "\" error: invalid user version: plugin" << pversion << "!=" << lversion;
unload();
return false;
}
}
func_static_merge = (FunctionStaticMerge)lib.resolve(STR(__PIP_PLUGIN_STATIC_MERGE_FUNC__));
if (func_static_merge) {
auto pss = plugin_info->staticSections(true), lss = PIPluginInfo::instance()->staticSections(false);
piCout << lss.keys() << pss.keys();
auto it = lss.makeIterator();
while (it.next()) {
if (!pss.contains(it.key()))
continue;
void * from = pss.value(it.key()), * to = it.value();
if (from != to)
func_static_merge(it.key(), from, to);
}
}
loaded = true;
return true;
}
void PIPluginLoader::unload() {
lib.unload();
plugin_info = nullptr;
loaded = false;
}
bool PIPluginLoader::isLoaded() const {
return loaded;
}
PIString PIPluginLoader::libPath() {
return lib.path();
}
void * PIPluginLoader::resolve(const char * name) {
if (!loaded) return nullptr;
return lib.resolve(name);
}
void PIPluginLoader::mergeStatic() {
if (!loaded || !func_static_merge || !plugin_info) return;
auto pss = plugin_info->staticSections(true), lss = PIPluginInfo::instance()->staticSections(false);
auto it = lss.makeIterator();
while (it.next()) {
if (!pss.contains(it.key()))
continue;
void * from = it.value(), * to = pss.value(it.key());
if (from != to)
func_static_merge(it.key(), from, to);
}
}
PIString PIPluginLoader::findLibrary(const PIString & path) {
static const PIStringList prefixes({"", "lib"});
static const PIStringList suffixes({"", libExtension()});
PIFile::FileInfo fi(path);
PIString dir = fi.dir(), name = fi.name();
piForeachC (PIString & p, prefixes) {
piForeachC (PIString & s, suffixes) {
PIString fn = dir + p + name + s;
if (PIFile::isExists(fn))
return fn;
}
}
return PIString();
}
PIString PIPluginLoader::libExtension() {
return
#ifdef WINDOWS
".dll"
#elif defined(MAC_OS)
".dylib"
#else
".so"
#endif
;
}
#endif // PIP_FREERTOS

178
libs/main/system/piplugin.h Normal file
View File

@@ -0,0 +1,178 @@
/*! \file piplugin.h
* \brief Plugin helpers
*/
/*
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 PIP_FREERTOS
#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_PLUGIN_INFO_FUNC__ pip_plugin_info
#define __PIP_PLUGIN_STATIC_MERGE_FUNC__ pip_merge_static
#define __PIP_PLUGIN_LOADER_VERSION__ 1
#define PIP_PLUGIN_SET_USER_VERSION(v) \
STATIC_INITIALIZER_BEGIN \
PIPluginInfo::instance()->setUserVersion(v); \
STATIC_INITIALIZER_END
#define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) \
STATIC_INITIALIZER_BEGIN \
PIPluginInfo::instance()->setStaticSection(type, ptr); \
STATIC_INITIALIZER_END
#define PIP_PLUGIN \
STATIC_INITIALIZER_BEGIN \
PIPluginInfo::instance()->enterPlugin(); \
STATIC_INITIALIZER_END \
extern "C" { \
PIP_PLUGIN_EXPORT int __PIP_PLUGIN_LOADER_VERSION_FUNC__() {return __PIP_PLUGIN_LOADER_VERSION__;} \
PIP_PLUGIN_EXPORT PIPluginInfo * __PIP_PLUGIN_PLUGIN_INFO_FUNC__() {return PIPluginInfo::instance();} \
}
#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(bool plugin) const;
PIMap<int, void*> staticSections(bool plugin) const;
void enterPlugin();
static PIPluginInfo * instance();
private:
PIString user_version[2];
PIMap<int, void*> static_sections[2];
bool in_plugin;
};
class PIP_EXPORT PIPluginLoader {
public:
typedef int(*FunctionLoaderVersion)();
typedef PIPluginInfo*(*FunctionPluginInfo)();
typedef void(*FunctionStaticMerge)(int, void *, void *);
//! 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 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();
private:
NO_COPY_CLASS(PIPluginLoader)
PIString findLibrary(const PIString & path);
static PIString libExtension();
PILibrary lib;
FunctionLoaderVersion func_loader_version;
FunctionPluginInfo func_plugin_info;
FunctionStaticMerge func_static_merge;
PIPluginInfo * plugin_info;
bool loaded;
};
#endif // PIP_FREERTOS
#endif // PIPLUGIN_H

View File

@@ -74,6 +74,14 @@ inline PICout operator <<(PICout c, const SwitchChannel & v) {
int Acnt = 0;
struct MM {
int x;
double y;
char c;
PIPointd h;
};
class A {
public:
A() {moved = false; i = "constructor"; piCout << "A()"; ++Acnt;}
@@ -86,10 +94,12 @@ public:
A & operator =(A && a) {piSwap(i, a.i); a.moved = true; piCout << "= A&&)"; return *this;}
PIString i;
bool moved;
MM m;
static void F(int) {}
};
PIByteArray & operator <<(PIByteArray & ba, const A & v) {ba << v.i; return ba;}
PIByteArray & operator >>(PIByteArray & ba, A & v) {ba >> v.i; return ba;}
inline PIByteArray & operator <<(PIByteArray & ba, const A & v) {ba << v.i << v.m; return ba;}
inline PIByteArray & operator >>(PIByteArray & ba, A & v) {ba >> v.i >> v.m; return ba;}
int main() {

View File

@@ -17,4 +17,3 @@ endmacro()
# Concurrent tests
pip_test(concurrent "")
pip_test(math "")
#pip_test(core "")

View File

@@ -325,7 +325,7 @@ void makeGetterValue(PIFile & f, const PICodeParser::Entity * e) {
piForeachC (PICodeParser::Member & m, e->members) {
if (m.is_type_ptr || m.isBitfield() || !m.dims.isEmpty() || (m.visibility != PICodeParser::Public))
continue;
f << "\tif (strcmp(name, \"" << m.name << "\") == 0) {ret << o->" << m.name << "; return ret;}\n";
f << "\tif (strcmp(name, \"" << m.name << "\") == 0) {serialize(ret, o->" << m.name << "); return ret;}\n";
}
f << "\treturn ret;\n}\n";
}