Metamodules are
classes that are to be described in dynamic linked libraries and to be
explicitly loaded by an application core from a specified class API
signature. So, metamodules may be considered as API signed classes that
are able to be dynamically instanciated from a core application without
any explicit code resolution of the module on the core side, all based
on the c++ polymorphic mechanism.
Because such objects should be instanciated from a core application,
they must be described with dynamic metaclasses in
order the main code to be able to call some functions on the newly
linked and allocated class i.e. the vtable to be functional and the
code accessible.
A metamodule derives the
CSerialized declaration. It is also able to expand the serialization process to dynamic loaded modules with a core centralized dispatcher.
Once the dynamic metamodule is metaclass described,
there is just one requirement for the generics to manage it : the
metamodule code should resolve a specific function that will be the
entry point of the explicit dynamic load process and will return the
metaclass of the described meta module. This function is introduced
with the following macro :
DECLARE_METAMODULE_EXPORT (class); |
metamodule export declaration and code resolution macro.
class CMetaModule : public CSerialized
{
// instanciation section
public :
CMetaModule
();
virtual ~CMetaModule ()=0;
// generic metaclass association
SECTION_GENERIC_METACLASS;
};
// metaclass and class tag declaration
DECLARE_GENERIC_METACLASS ('mtmx', CMetaModule, CSerialized); |
There is no particular function handling on the
CMetaModule definition. It is just defined as a logical abstract base
class.
Meta Module Importer API
The generics
CMetaModuleImporter class defines facilities to explicitly
import metamodules defined in dynamic linked libraries. The
imported definitions should derive the CMetaModule class and declare
the DECLARE_METAMODULE_EXPORT macro as exposed above.
The application core should resolve the cmetaclass.h code
section. The modules should not include this code resolution as there
must be one and only one static
metaclasses list in the whole binary target ! See the "
Compiling your own libgenerics based on
applications" section for details on how to build such meta modules and core importers applications.
class CMetaModuleImporter : public CClass
{
// instanciation section
public :
CMetaModuleImporter
(const CString &inLibraryPath, const CMetaClass
*inRequestedAPI=__metaclass(CMetaModule));
virtual ~CMetaModuleImporter ();
// general importer functions
public :
// linked library handle, its name
void *
GetLibHandle
() const;
CString
GetLibName
() const;
// loaded module access
public :
// loaded module metaclass
access; do not instanciate the module via the returned metaclass
attributes, prefer using
// the CMetaModuleImporter
defined functions to ensure a correct resource freeing when done with it
const CMetaClass
*
GetModuleMetaClass () const;
// instanciate the imported metamodule
CMetaModule *
InstanciateModule ();
// delete the specified metamodule instance
void
DeleteModule
(CMetaModule *&);
// static function
public :
// potential library names of the specified path
static CStrings
GetLibNames
(const CString &inPath);
// protected section
protected :
// the loaded library name, its handle and the associated metaclass
CString
LibName;
void *
LibHandle;
CMetaClass *
LibMetaClass;
// the module instances
CMetaModules LibMetaModules;
// public capsule description
SECTION_CAPSULE_METACLASS;
};
// class tag and metaclass description
DECLARE_CAPSULE_METACLASS ('mtmi', CMetaModuleImporter, CClass); |
Sample code
As example, consider a core application that
manipulates some shapes (here a rectangle or a circle) to draw them on
a dedicated widget. The core application introduces some common
functionnalities to specific shapes handled by metamodule code
resolution. The serialization is not demonstrated here. This could be
written with the followings :
core application based on a generic shape definition |
specific shapes handlers, metamodules definitions |
main.c
cshape.h
cshape.c |
cshape.h
crectangle.c
ccircle.c |
g++ -o main -rdynamic `pkg-config --cflags libgenerics-1.2` main.c cshape.c `pkg-config --libs libgenerics-1.2`
g++ -o crectangle.so -shared `pkg-config --cflags libgenerics-1.2` crectangle.c
g++ -o ccircle.so -shared `pkg-config --cflags libgenerics-1.2` ccircle.c
"cshape.h"
// this section is destinated to the core application and its metamodules definitions
#include "cmetamodule.h"
...
class CShape : public CMetaModule
{
CShape
();
virtual ~CShape ();
virtual Draw (GtkWidget *) =0;
SECTION_GENERIC_METACLASS;
};
DECLARE_GENERIC_METACLASS ('shap', CShape, CMetaModule);
"cshape.c"
// this code section should only be linked into the application core binary
#include "cshape.h"
RESOLVE_GENERIC_METACLASS (CShape);
CShape::CShape () : CMetaModule ()
{ }
CShape::~CShape ()
{ }
"crectangle.c"
// this code section is unknown from the core application, we
define here a specific metamodule handling on a generic shape
#include "cshape.h"
class CRectangle : public CShape
{
public :
CRectangle () : CShape ()
{ }
virtual ~CRectangle ()
{ }
virtual void Draw (GtkWidget *inGtkWidget)
{
printf ("CRectangle::Draw : drawing a rectangle on
the specified widget\n");
}
SECTION_DYNAMIC_METACLASS;
};
DECLARE_DYNAMIC_METACLASS ('rect', CRectangle, CShape);
RESOLVE_DYNAMIC_METACLASS (CRectangle);
DECLARE_METAMODULE_EXPORT (CRectangle);
"ccircle.c"
// this code section is unknown from the core application, we
define here a specific metamodule handling on a generic shape
#include "cshape.h"
class CCircle : public CShape
{
public :
CCircle () : CShape ()
{ }
virtual ~CCircle ()
{ }
virtual void Draw (GtkWidget *inGtkWidget)
{
printf ("CCircle::Draw : drawing a circle on the
specified widget\n");
}
SECTION_DYNAMIC_METACLASS;
};
DECLARE_DYNAMIC_METACLASS ('circ', CCircle, CShape);
RESOLVE_DYNAMIC_METACLASS (CCircle);
DECLARE_METAMODULE_EXPORT (CCircle);
"main.c"
// this section code is the core application wich loads the
specific metamodule shapes handlers without knowing their explicit
content
#include "cshape.h"
#include "cmetamoduleimporter.h"
...
int main (int, char **)
{
// get the list of the potential metamodule
libraries names that should be in a "shapes" subdirectory in this sample
CStrings inMetaModuleNames (CMetaModuleImporter::GetLibNames (CString("./shapes")));
// declare a list of meta module importers, one for each metamodule
TBuffer <CMetaModuleImporter *> theMetaModuleImporters;
// foreach given library name, instanciate an importer
for (size_t i=0; i<inMetaModuleNames.GetLength(); i++)
{
// instanciate a new metamodule
importer and be sure to import a CShape derived module (exceptions are
not handled in this sample)
theMetaModuleImporters +=
new CMetaModuleImporter (*inMetaModuleNames[i], __metaclass(CShape));
}
// foreach metamodule importer, instanciate the
associated metamodule and call the virtual Draw specific definition
for (size_t i=0; i<theMetaModuleImporters.GetLength(); i++)
{
// we requested a CShape derived
metamodule to be dynamically linked, so cast the new metamodule instance
CShape *inShape = static_cast
<CShape *> ((*theMetaModuleImporters[i]) ->
InstanciateModule());
// call the specific function definition
inShape -> Draw (OnAGtkWidget);
}
...
// delete the metamodule importers i.e.
automatically unlink the metamodule libraries and free the instinciated
metamodules
for (size_t i=0; i<theMetaModuleImporters.GetLength(); i++) delete *theMetaModuleImporters[i];
// ok
return 0;
}