/
ModuleLoader.cpp
144 lines (115 loc) · 3.84 KB
/
ModuleLoader.cpp
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
#include "ModuleLoader.h"
#include "itextstream.h"
#include <iostream>
#include "imodule.h"
#include "os/dir.h"
#include "os/path.h"
#include "ModuleRegistry.h"
#include "string/case_conv.h"
namespace module
{
namespace
{
const std::string PLUGINS_DIR = "plugins/"; ///< name of plugins directory
const std::string MODULES_DIR = "modules/"; ///< name of modules directory
// 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();
rConsole() << "ModuleLoader: Loading module '" << fullName << "'" << std::endl;
// 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;
}
}
void ModuleLoader::loadModules(const std::string& root)
{
// Get standardised paths
std::string stdRoot = os::standardPathWithSlash(root);
#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
rConsole() << "ModuleLoader: loading modules from " << root << std::endl;
// Load modules first, then plugins
loadModulesFromPath(modulesPath);
// Plugins are optional
if (pluginsPath != modulesPath)
{
loadModulesFromPath(pluginsPath);
}
}
void ModuleLoader::loadModulesFromPath(const std::string& path)
{
// In case the folder is non-existent, catch the exception
try
{
os::foreachItemInDirectory(path, [&](const fs::path& file)
{
processModuleFile(file);
});
}
catch (os::DirectoryNotFoundException&)
{
rConsole() << "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