added possibility to specify modules dependencies

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39677 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2006-06-11 22:19:12 +00:00
parent dc26eeb36a
commit af266e5bf7
5 changed files with 277 additions and 34 deletions

View File

@@ -49,6 +49,7 @@ All:
- Added wxStandardPaths::GetDocumentsDir() (Ken Thomases) - Added wxStandardPaths::GetDocumentsDir() (Ken Thomases)
- Added wxStringTokenizer::GetLastDelimiter(); improved documentation. - Added wxStringTokenizer::GetLastDelimiter(); improved documentation.
- Fixed wxTextFile in Unicode build - Fixed wxTextFile in Unicode build
- Added possibility to specify dependencies for a wxModule
- Speed improvements to wxRegEx when matching is done in a loop such as - Speed improvements to wxRegEx when matching is done in a loop such as
during a search and replace. during a search and replace.
- Fix regerror and regfree name conficts when built-in regex and system regex - Fix regerror and regfree name conficts when built-in regex and system regex

View File

@@ -1,14 +1,16 @@
\section{\class{wxModule}}\label{wxmodule} \section{\class{wxModule}}\label{wxmodule}
The module system is a very simple mechanism to allow applications (and parts of wxWidgets itself) to The module system is a very simple mechanism to allow applications (and parts
define initialization and cleanup functions that are automatically called on wxWidgets of wxWidgets itself) to define initialization and cleanup functions that are
startup and exit. automatically called on wxWidgets startup and exit.
To define a new kind of module, derive a class from wxModule, override the OnInit and OnExit functions, To define a new kind of module, derive a class from wxModule, override the
and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to header and implementation files \helpref{OnInit}{wxmoduleoninit} and \helpref{OnExit}{wxmoduleonexit}
(which can be the same file). On initialization, wxWidgets will find all classes derived from wxModule, functions, and add the DECLARE\_DYNAMIC\_CLASS and IMPLEMENT\_DYNAMIC\_CLASS to
create an instance of each, and call each OnInit function. On exit, wxWidgets will call the OnExit header and implementation files (which can be the same file). On
function for each module instance. initialization, wxWidgets will find all classes derived from wxModule, create
an instance of each, and call each OnInit function. On exit, wxWidgets will
call the OnExit function for each module instance.
Note that your module class does not have to be in a header file. Note that your module class does not have to be in a header file.
@@ -18,17 +20,31 @@ For example:
// A module to allow DDE initialization/cleanup // A module to allow DDE initialization/cleanup
// without calling these functions from app.cpp or from // without calling these functions from app.cpp or from
// the user's application. // the user's application.
class wxDDEModule: public wxModule class wxDDEModule: public wxModule
{ {
DECLARE_DYNAMIC_CLASS(wxDDEModule)
public: public:
wxDDEModule() {} wxDDEModule() { }
bool OnInit() { wxDDEInitialize(); return true; }; virtual bool OnInit() { wxDDEInitialize(); return true; };
void OnExit() { wxDDECleanUp(); }; virtual void OnExit() { wxDDECleanUp(); };
private:
DECLARE_DYNAMIC_CLASS(wxDDEModule)
}; };
IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule) IMPLEMENT_DYNAMIC_CLASS(wxDDEModule, wxModule)
// Another module which uses DDE in its OnInit()
class MyModule: public wxModule
{
public:
wxDDEModule() { AddDependency(CLASSINFO(wxDDEModule)); }
virtual bool OnInit() { ... code using DDE ... }
virtual void OnExit() { ... }
private:
DECLARE_DYNAMIC_CLASS(wxDDEModule)
};
\end{verbatim} \end{verbatim}
\wxheading{Derived from} \wxheading{Derived from}
@@ -41,28 +57,47 @@ For example:
\latexignore{\rtfignore{\wxheading{Members}}} \latexignore{\rtfignore{\wxheading{Members}}}
\membersection{wxModule::wxModule}\label{wxmodulector} \membersection{wxModule::wxModule}\label{wxmodulector}
\func{}{wxModule}{\void} \func{}{wxModule}{\void}
Constructs a wxModule object. Constructs a wxModule object.
\membersection{wxModule::\destruct{wxModule}}\label{wxmoduledtor} \membersection{wxModule::\destruct{wxModule}}\label{wxmoduledtor}
\func{}{\destruct{wxModule}}{\void} \func{}{\destruct{wxModule}}{\void}
Destructor. Destructor.
\membersection{wxModule::AddDependency}\label{wxmoduleoninit}
\func{void}{AddDependency}{\param{wxClassInfo * }{dep}}
Call this function from the constructor of the derived class. \arg{dep} must be
the \helpref{CLASSINFO}{classinfo} of a wxModule-derived class and the
corresponding module will be loaded \emph{before} and unloaded \emph{after}
this module.
Note that circular dependencies are detected and result in a fatal error.
\wxheading{Parameters}
\docparam{dep}{The class information object for the dependent module.}
\membersection{wxModule::OnExit}\label{wxmoduleonexit} \membersection{wxModule::OnExit}\label{wxmoduleonexit}
\func{virtual void}{OnExit}{\void} \func{virtual void}{OnExit}{\void}
Provide this function with appropriate cleanup for your module. Provide this function with appropriate cleanup for your module.
\membersection{wxModule::OnInit}\label{wxmoduleoninit} \membersection{wxModule::OnInit}\label{wxmoduleoninit}
\func{virtual bool}{OnInit}{\void} \func{virtual bool}{OnInit}{\void}
Provide this function with appropriate initialization for your module. If the function Provide this function with appropriate initialization for your module. If the function
returns false, wxWidgets will exit immediately. returns false, wxWidgets will exit immediately.

View File

@@ -14,11 +14,17 @@
#include "wx/object.h" #include "wx/object.h"
#include "wx/list.h" #include "wx/list.h"
#include "wx/dynarray.h"
// declare a linked list of modules // declare a linked list of modules
class WXDLLIMPEXP_BASE wxModule; class WXDLLIMPEXP_BASE wxModule;
WX_DECLARE_USER_EXPORTED_LIST(wxModule, wxModuleList, WXDLLIMPEXP_BASE); WX_DECLARE_USER_EXPORTED_LIST(wxModule, wxModuleList, WXDLLIMPEXP_BASE);
// and an array of class info objects
WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxClassInfo *, wxArrayClassInfo,
class WXDLLIMPEXP_BASE);
// declaring a class derived from wxModule will automatically create an // declaring a class derived from wxModule will automatically create an
// instance of this class on program startup, call its OnInit() method and call // instance of this class on program startup, call its OnInit() method and call
// OnExit() on program termination (but only if OnInit() succeeded) // OnExit() on program termination (but only if OnInit() succeeded)
@@ -48,7 +54,7 @@ public:
static void RegisterModule(wxModule *module); static void RegisterModule(wxModule *module);
static void RegisterModules(); static void RegisterModules();
static bool InitializeModules(); static bool InitializeModules();
static void CleanUpModules(); static void CleanUpModules() { DoCleanUpModules(m_modules); }
// used by wxObjectLoader when unloading shared libs's // used by wxObjectLoader when unloading shared libs's
@@ -57,6 +63,40 @@ public:
protected: protected:
static wxModuleList m_modules; static wxModuleList m_modules;
// the function to call from constructor of a deriving class add module
// dependency which will be initialized before the module and unloaded
// after that
void AddDependency(wxClassInfo *dep)
{
wxCHECK_RET( dep, _T("NULL module dependency") );
m_dependencies.Add(dep);
}
private:
// initialize module and Append it to initializedModules list recursively
// calling itself to satisfy module dependencies if needed
static bool
DoInitializeModule(wxModule *module, wxModuleList &initializedModules);
// cleanup the modules in the specified list (which may not contain all
// modules if we're called during initialization because not all modules
// could be initialized) and also empty m_modules itself
static void DoCleanUpModules(const wxModuleList& modules);
// module dependencies: contains
wxArrayClassInfo m_dependencies;
// used internally while initiliazing/cleaning up modules
enum
{
State_Registered, // module registered but not initialized yet
State_Initializing, // we're initializing this module but not done yet
State_Initialized // module initialized successfully
} m_state;
DECLARE_CLASS(wxModule) DECLARE_CLASS(wxModule)
}; };

View File

@@ -65,6 +65,7 @@
#define TEST_LOCALE #define TEST_LOCALE
#define TEST_LOG #define TEST_LOG
#define TEST_MIME #define TEST_MIME
#define TEST_MODULE
#define TEST_PATHLIST #define TEST_PATHLIST
#define TEST_ODBC #define TEST_ODBC
#define TEST_PRINTF #define TEST_PRINTF
@@ -85,7 +86,7 @@
#define TEST_WCHAR #define TEST_WCHAR
#define TEST_ZIP #define TEST_ZIP
#else // #if TEST_ALL #else // #if TEST_ALL
#define TEST_STDPATHS #define TEST_MODULE
#endif #endif
// some tests are interactive, define this to run them // some tests are interactive, define this to run them
@@ -1381,6 +1382,80 @@ static void TestMimeAssociate()
#endif // TEST_MIME #endif // TEST_MIME
// ----------------------------------------------------------------------------
// module dependencies feature
// ----------------------------------------------------------------------------
#ifdef TEST_MODULE
#include "wx/module.h"
class wxTestModule : public wxModule
{
protected:
virtual bool OnInit() { wxPrintf(_T("Load module: %s\n"), GetClassInfo()->GetClassName()); return true; }
virtual void OnExit() { wxPrintf(_T("Unload module: %s\n"), GetClassInfo()->GetClassName()); }
};
class wxTestModuleA : public wxTestModule
{
public:
wxTestModuleA();
private:
DECLARE_DYNAMIC_CLASS(wxTestModuleA)
};
class wxTestModuleB : public wxTestModule
{
public:
wxTestModuleB();
private:
DECLARE_DYNAMIC_CLASS(wxTestModuleB)
};
class wxTestModuleC : public wxTestModule
{
public:
wxTestModuleC();
private:
DECLARE_DYNAMIC_CLASS(wxTestModuleC)
};
class wxTestModuleD : public wxTestModule
{
public:
wxTestModuleD();
private:
DECLARE_DYNAMIC_CLASS(wxTestModuleD)
};
IMPLEMENT_DYNAMIC_CLASS(wxTestModuleC, wxModule)
wxTestModuleC::wxTestModuleC()
{
AddDependency(CLASSINFO(wxTestModuleD));
}
IMPLEMENT_DYNAMIC_CLASS(wxTestModuleA, wxModule)
wxTestModuleA::wxTestModuleA()
{
AddDependency(CLASSINFO(wxTestModuleB));
AddDependency(CLASSINFO(wxTestModuleD));
}
IMPLEMENT_DYNAMIC_CLASS(wxTestModuleD, wxModule)
wxTestModuleD::wxTestModuleD()
{
}
IMPLEMENT_DYNAMIC_CLASS(wxTestModuleB, wxModule)
wxTestModuleB::wxTestModuleB()
{
AddDependency(CLASSINFO(wxTestModuleD));
AddDependency(CLASSINFO(wxTestModuleC));
}
#endif // TEST_MODULE
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// misc information functions // misc information functions
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@@ -36,6 +36,7 @@ wxModuleList wxModule::m_modules;
void wxModule::RegisterModule(wxModule* module) void wxModule::RegisterModule(wxModule* module)
{ {
module->m_state = State_Registered;
m_modules.Append(module); m_modules.Append(module);
} }
@@ -69,42 +70,133 @@ void wxModule::RegisterModules()
} }
} }
bool wxModule::InitializeModules() bool wxModule::DoInitializeModule(wxModule *module,
wxModuleList &initializedModules)
{ {
// Initialize user-defined modules if ( module->m_state == State_Initializing )
wxModuleList::compatibility_iterator node;
for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
{ {
wxModule *module = node->GetData(); wxLogError(_("Circular dependency involving module \"%s\" detected."),
if ( !module->Init() )
{
wxLogError(_("Module \"%s\" initialization failed"),
module->GetClassInfo()->GetClassName()); module->GetClassInfo()->GetClassName());
return false;
// clean up already initialized modules - process in reverse order
wxModuleList::compatibility_iterator n;
for ( n = node->GetPrevious(); n; n = n->GetPrevious() )
{
n->GetData()->OnExit();
} }
module->m_state = State_Initializing;
const wxArrayClassInfo& dependencies = module->m_dependencies;
// satisfy module dependencies by loading them before the current module
for ( unsigned int i = 0; i < dependencies.size(); ++i )
{
wxClassInfo * cinfo = dependencies[i];
// Check if the module is already initialized
wxModuleList::compatibility_iterator node;
for ( node = initializedModules.GetFirst(); node; node = node->GetNext() )
{
if ( node->GetData()->GetClassInfo() == cinfo )
break;
}
if ( node )
{
// this dependency is already initialized, nothing to do
continue;
}
// find the module in the registered modules list
for ( node = m_modules.GetFirst(); node; node = node->GetNext() )
{
wxModule *moduleDep = node->GetData();
if ( moduleDep->GetClassInfo() == cinfo )
{
if ( !DoInitializeModule(moduleDep, initializedModules ) )
{
// failed to initialize a dependency, so fail this one too
return false;
}
break;
}
}
if ( !node )
{
wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."),
cinfo->GetClassName(),
module->GetClassInfo()->GetClassName());
return false; return false;
} }
} }
if ( !module->Init() )
{
wxLogError(_("Module \"%s\" initialization failed"),
module->GetClassInfo()->GetClassName());
return false;
}
wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"),
module->GetClassInfo()->GetClassName());
module->m_state = State_Initialized;
initializedModules.Append(module);
return true; return true;
} }
void wxModule::CleanUpModules() // Initialize user-defined modules
bool wxModule::InitializeModules()
{ {
// Cleanup user-defined modules wxModuleList initializedModules;
wxModuleList::compatibility_iterator node;
for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst();
node;
node = node->GetNext() )
{
wxModule *module = node->GetData();
// the module could have been already initialized as dependency of
// another one
if ( module->m_state == State_Registered )
{
if ( !DoInitializeModule( module, initializedModules ) )
{
// failed to initialize all modules, so clean up the already
// initialized ones
DoCleanUpModules(initializedModules);
return false;
}
}
}
// remember the real initialisation order
m_modules = initializedModules;
return true;
}
// Clean up all currently initialized modules
void wxModule::DoCleanUpModules(const wxModuleList& modules)
{
// cleanup user-defined modules in the reverse order compared to their
// initialization -- this ensures that dependencies are respected
for ( wxModuleList::compatibility_iterator node = modules.GetLast();
node;
node = node->GetPrevious() )
{ {
wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"),
node->GetData()->GetClassInfo()->GetClassName()); node->GetData()->GetClassInfo()->GetClassName());
node->GetData()->Exit();
wxModule * module = node->GetData();
wxASSERT_MSG( module->m_state == State_Initialized,
_T("not initialized module being cleaned up") );
module->Exit();
module->m_state = State_Registered;
} }
// clear all modules, even the non-initialized ones
WX_CLEAR_LIST(wxModuleList, m_modules); WX_CLEAR_LIST(wxModuleList, m_modules);
} }