File: ModuleLoader.cpp

package info (click to toggle)
darkradiant 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 41,080 kB
  • sloc: cpp: 264,743; ansic: 10,659; python: 1,852; xml: 1,650; sh: 92; makefile: 21
file content (157 lines) | stat: -rw-r--r-- 4,259 bytes parent folder | download | duplicates (2)
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