diff --git a/src/ModuleManager.cpp b/src/ModuleManager.cpp index 1bdc984f9..0de3f7f94 100755 --- a/src/ModuleManager.cpp +++ b/src/ModuleManager.cpp @@ -85,8 +85,8 @@ wxWindow * MakeHijackPanel() static tpRegScriptServerFunc scriptFn; Module::Module(const FilePath & name) + : mName{ name } { - mName = name; mLib = std::make_unique(); mDispatch = NULL; } @@ -119,6 +119,9 @@ bool Module::Load(wxString &deferredErrorMessage) auto ShortName = wxFileName(mName).GetName(); if (!mLib->Load(mName, wxDL_NOW | wxDL_QUIET | wxDL_GLOBAL)) { + // For this failure path, only, there is a possiblity of retrial + // after some other dependency of this module is loaded. So the + // error is not immediately reported. deferredErrorMessage = wxString(wxSysErrorMsg()); return false; } @@ -265,7 +268,8 @@ void ModuleManager::FindModules(FilePaths &files) #endif } -void ModuleManager::TryLoadModules(const FilePaths &files) +void ModuleManager::TryLoadModules( + const FilePaths &files, FilePaths &decided, DelayedErrors &errors) { FilePaths checked; wxString saveOldCWD = ::wxGetCwd(); @@ -284,6 +288,10 @@ void ModuleManager::TryLoadModules(const FilePaths &files) continue; checked.Add( ShortName ); + // Skip if a previous pass through this function decided it already + if( decided.Index( ShortName, false ) != wxNOT_FOUND ) + continue; + #ifdef EXPERIMENTAL_MODULE_PREFS int iModuleStatus = ModulePrefs::GetModuleStatus( file ); if( iModuleStatus == kModuleDisabled ) @@ -323,6 +331,7 @@ void ModuleManager::TryLoadModules(const FilePaths &files) } #endif if(action == 1){ // "No" + decided.Add( ShortName ); continue; } } @@ -336,6 +345,7 @@ void ModuleManager::TryLoadModules(const FilePaths &files) auto umodule = std::make_unique(file); if (umodule->Load(Error)) // it will get rejected if there are version problems { + decided.Add( ShortName ); auto module = umodule.get(); { @@ -376,7 +386,11 @@ void ModuleManager::TryLoadModules(const FilePaths &files) } } else if (!Error.empty()) { - umodule->ShowLoadFailureError(Error); + // Module is not yet decided in this pass. + // Maybe it depends on another which has not yet been loaded. + // But don't take the kModuleAsk path again in a later pass. + ModulePrefs::SetModuleStatus( file, kModuleEnabled ); + errors.emplace_back( std::move( umodule ), Error ); } } } @@ -387,7 +401,25 @@ void ModuleManager::Initialize() FilePaths files; FindModules(files); - TryLoadModules(files); + FilePaths decided; + DelayedErrors errors; + size_t numDecided = 0; + + // Multiple passes give modules multiple chances to load in case they + // depend on some other module not yet loaded + do { + numDecided = decided.size(); + errors.clear(); + TryLoadModules(files, decided, errors); + } + while ( errors.size() && numDecided < decided.size() ); + + // Only now show accumulated errors of modules that failed to load + for ( const auto &pair : errors ) { + auto &pModule = pair.first; + pModule->ShowLoadFailureError(pair.second); + ModulePrefs::SetModuleStatus( pModule->GetName(), kModuleFailed ); + } // After loading all the modules, we may have a registered scripting function. if(scriptFn) diff --git a/src/ModuleManager.h b/src/ModuleManager.h index 75957fc11..890143796 100644 --- a/src/ModuleManager.h +++ b/src/ModuleManager.h @@ -47,9 +47,10 @@ public: bool HasDispatch() { return mDispatch != NULL; }; int Dispatch(ModuleDispatchTypes type); void * GetSymbol(const wxString &name); + const FilePath &GetName() const { return mName; } private: - FilePath mName; + const FilePath mName; std::unique_ptr mLib; fnModuleDispatch mDispatch; }; @@ -78,7 +79,10 @@ public: private: static void FindModules(FilePaths &files); - static void TryLoadModules(const FilePaths &files); + using DelayedErrors = + std::vector< std::pair< std::unique_ptr, wxString > >; + static void TryLoadModules( + const FilePaths &files, FilePaths &decided, DelayedErrors &errors); public: void Initialize();