Codechange: refactor the Windows-only DllLoader in a cross-platform LibraryLoader (#11751)
parent
f7bd70baec
commit
d3ee045c2d
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file library_loader.h Functions/types related to loading libraries dynamically. */
|
||||
|
||||
#ifndef LIBRARY_LOADER_H
|
||||
#define LIBRARY_LOADER_H
|
||||
|
||||
class LibraryLoader {
|
||||
public:
|
||||
/**
|
||||
* A function loaded from a library.
|
||||
*
|
||||
* Will automatically cast to the correct function pointer type on retrieval.
|
||||
*/
|
||||
class Function {
|
||||
public:
|
||||
explicit Function(void *p) : p(p) {}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_function_v<T>>>
|
||||
operator T *() const
|
||||
{
|
||||
return reinterpret_cast<T *>(this->p);
|
||||
}
|
||||
|
||||
private:
|
||||
void *p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a library with the given filename.
|
||||
*/
|
||||
explicit LibraryLoader(const std::string &filename)
|
||||
{
|
||||
this->handle = this->OpenLibrary(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the library.
|
||||
*/
|
||||
~LibraryLoader()
|
||||
{
|
||||
if (this->handle != nullptr) {
|
||||
this->CloseLibrary();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an error occurred while loading the library or a function.
|
||||
*
|
||||
* @return Whether an error occurred.
|
||||
*/
|
||||
bool HasError()
|
||||
{
|
||||
return this->error.has_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error that occurred while loading the library or a function.
|
||||
*
|
||||
* @return The error message.
|
||||
*/
|
||||
std::string GetLastError()
|
||||
{
|
||||
return this->error.value_or("No error");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a function from a loaded library.
|
||||
*
|
||||
* @param symbol_name The name of the function to get.
|
||||
* @return The function. Check HasError() before using.
|
||||
*/
|
||||
Function GetFunction(const std::string &symbol_name)
|
||||
{
|
||||
if (this->error.has_value()) return Function(nullptr);
|
||||
return Function(this->GetSymbol(symbol_name));
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Open the library with the given filename.
|
||||
*
|
||||
* Should set error if any error occurred.
|
||||
*
|
||||
* @param filename The filename of the library to open.
|
||||
*/
|
||||
void *OpenLibrary(const std::string &filename);
|
||||
|
||||
/**
|
||||
* Close the library.
|
||||
*/
|
||||
void CloseLibrary();
|
||||
|
||||
/**
|
||||
* Get a symbol from the library.
|
||||
*
|
||||
* Should set error if any error occurred.
|
||||
*
|
||||
* @param symbol_name The name of the symbol to get.
|
||||
*/
|
||||
void *GetSymbol(const std::string &symbol_name);
|
||||
|
||||
std::optional<std::string> error = {}; ///< The last error that occurred, if set.
|
||||
void *handle = nullptr; ///< Handle to the library.
|
||||
};
|
||||
|
||||
#endif /* LIBRARY_LOADER_H */
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file library_loader_unix.cpp Implementation of the LibraryLoader for Linux / MacOS */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "../../library_loader.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/* Emscripten cannot dynamically load other files. */
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
|
||||
void *LibraryLoader::OpenLibrary(const std::string &)
|
||||
{
|
||||
this->error = "Dynamic loading is not supported on this platform.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LibraryLoader::CloseLibrary()
|
||||
{
|
||||
}
|
||||
|
||||
void *LibraryLoader::GetSymbol(const std::string &)
|
||||
{
|
||||
this->error = "Dynamic loading is not supported on this platform.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *LibraryLoader::OpenLibrary(const std::string &filename)
|
||||
{
|
||||
void *h = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL);
|
||||
if (h == nullptr) {
|
||||
this->error = dlerror();
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void LibraryLoader::CloseLibrary()
|
||||
{
|
||||
dlclose(this->handle);
|
||||
}
|
||||
|
||||
void *LibraryLoader::GetSymbol(const std::string &symbol_name)
|
||||
{
|
||||
void *p = dlsym(this->handle, symbol_name.c_str());
|
||||
if (p == nullptr) {
|
||||
this->error = dlerror();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* __EMSCRIPTEN__ */
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file library_loader_win.cpp Implementation of the LibraryLoader for Windows */
|
||||
|
||||
#include "../../stdafx.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "../../library_loader.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
static std::string GetLoadError()
|
||||
{
|
||||
auto error_code = GetLastError();
|
||||
|
||||
char buffer[512];
|
||||
if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), nullptr) == 0) {
|
||||
return fmt::format("Unknown error {}", error_code);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void *LibraryLoader::OpenLibrary(const std::string &filename)
|
||||
{
|
||||
void *h = ::LoadLibraryW(OTTD2FS(filename).c_str());
|
||||
if (h == nullptr) {
|
||||
this->error = GetLoadError();
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
void LibraryLoader::CloseLibrary()
|
||||
{
|
||||
HMODULE handle = static_cast<HMODULE>(this->handle);
|
||||
|
||||
::FreeLibrary(handle);
|
||||
}
|
||||
|
||||
void *LibraryLoader::GetSymbol(const std::string &symbol_name)
|
||||
{
|
||||
HMODULE handle = static_cast<HMODULE>(this->handle);
|
||||
|
||||
void *p = reinterpret_cast<void *>(::GetProcAddress(handle, symbol_name.c_str()));
|
||||
if (p == nullptr) {
|
||||
this->error = GetLoadError();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
Loading…
Reference in New Issue