1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
#include "ModuleLoader.h"
#include "itextstream.h"
#include <iostream>
#include "imodule.h"
#include "os/dir.h"
#include "os/path.h"
#include "ModuleRegistry.h"
#include "module/CoreModule.h"
#include "string/case_conv.h"
namespace module
{
namespace
{
// This is the name of the entry point symbol in the module
const char* const SYMBOL_REGISTER_MODULE = "RegisterModule";
// Modules have to export a symbol of this type, which gets called during DLL loading
typedef void(*RegisterModulesFunc)(IModuleRegistry& registry);
}
ModuleLoader::ModuleLoader(IModuleRegistry& registry) :
_registry(registry)
{}
// Functor operator, gets invoked on directory traversal
void ModuleLoader::processModuleFile(const fs::path& file)
{
// Check for the correct extension of the visited file
if (string::to_lower_copy(file.extension().string()) != MODULE_FILE_EXTENSION) return;
std::string fullName = file.string();
rMessage() << "ModuleLoader: Loading module '" << fullName << "'" << std::endl;
// Skip the core module binary
if (file.filename() == CoreModule::Filename())
{
return;
}
// Create the encapsulator class
auto library = std::make_shared<DynamicLibrary>(fullName);
// greebo: Try to find our entry point and invoke it and add the library to the list
// on success. If the load fails, the shared pointer won't be added and
// self-destructs at the end of this scope.
if (library->failed())
{
rError() << "WARNING: Failed to load module " << library->getName() << ":" << std::endl;
#ifdef __linux__
rConsoleError() << dlerror() << std::endl;
#endif
return;
}
// Library was successfully loaded, lookup the symbol
auto funcPtr = library->findSymbol(SYMBOL_REGISTER_MODULE);
if (funcPtr == nullptr)
{
// Symbol lookup error
rError() << "WARNING: Could not find symbol " << SYMBOL_REGISTER_MODULE
<< " in module " << library->getName() << ":" << std::endl;
return;
}
// Brute-force conversion of the pointer to the desired type
auto regFunc = reinterpret_cast<RegisterModulesFunc>(funcPtr);
try
{
// Call the symbol and pass a reference to the ModuleRegistry
// This method might throw a ModuleCompatibilityException in its
// module::performDefaultInitialisation() routine.
regFunc(_registry);
// Add the library to the static list (for later reference)
_dynamicLibraryList.push_back(library);
}
catch (module::ModuleCompatibilityException&)
{
// Report this error and don't add the module to the _dynamicLibraryList
rError() << "Compatibility mismatch loading library " << library->getName() << std::endl;
}
catch (std::runtime_error& ex)
{
// Report this error and don't add the module to the _dynamicLibraryList
rError() << "Failure registering module " << library->getName() << ": " << ex.what() << std::endl;
}
}
#if 0
void ModuleLoader::loadModules(const std::string& libraryPath)
{
// Get standardised paths
std::string stdRoot = os::standardPathWithSlash(libraryPath);
#if defined(DR_MODULES_NEXT_TO_APP)
// Xcode output goes to the application folder right now
std::string modulesPath = stdRoot;
std::string pluginsPath = stdRoot;
#else
std::string modulesPath = stdRoot + MODULES_DIR;
std::string pluginsPath = stdRoot + PLUGINS_DIR;
#endif
rMessage() << "ModuleLoader: loading modules from " << libraryPath << std::endl;
// Load modules first, then plugins
loadModulesFromPath(modulesPath);
// Plugins are optional
if (pluginsPath != modulesPath)
{
loadModulesFromPath(pluginsPath);
}
}
#endif
void ModuleLoader::loadModulesFromPath(const std::string& path)
{
rMessage() << "ModuleLoader: loading modules from " << path << std::endl;
// In case the folder is non-existent, catch the exception
try
{
os::forEachItemInDirectory(os::standardPathWithSlash(path), [&](const fs::path& file)
{
processModuleFile(file);
});
}
catch (os::DirectoryNotFoundException&)
{
rError() << "ModuleLoader::loadModules(): modules directory '"
<< path << "' not found." << std::endl;
}
}
void ModuleLoader::unloadModules()
{
while (!_dynamicLibraryList.empty())
{
DynamicLibraryPtr lib = _dynamicLibraryList.back();
_dynamicLibraryList.pop_back();
lib.reset();
}
}
} // namespace module
|