Skip to content

Commit

Permalink
Adds headers to handle loading shared libraries and their functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
aliakatas committed Dec 30, 2024
1 parent 27d4afb commit 2f4a198
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 0 deletions.
51 changes: 51 additions & 0 deletions include/load_shared_libraries/funcloader.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#if defined (__WIN32__) || defined(_WIN32)
#include <windows.h>
#define Dlsym(handle, symbol) GetProcAddress(handle, symbol)
#elif defined(__linux__)
#include <dlfcn.h>
#define Dlsym(handle, symbol) dlsym(handle, symbol)
#endif
#include "get_os_error.hxx"

#include <string>
#include <stdexcept>

template <typename func_t>
class FuncLoader
{
public:
/**
* @brief Loads a function from a shared library.
* The shared library must be loaded before calling this.
*
* @param func_name [in] The name of the function to load from the shared library.
* @param libname [in] The name of the shared library (used for messages only).
* @param lib_handle [in] The handle for the shared lirbary loaded using the LibLoader.
* @return The handle for the function to be used later in the program.
*
* @throws Runtime error if the load fails.
*/
#if defined (__WIN32__) || defined(_WIN32)
static func_t load(const char* func_name, const char* libname, HINSTANCE lib_handle) noexcept(false)
#elif defined(__linux__)
static func_t load(const char* func_name, const char* libname, void* lib_handle) noexcept(false)
#endif
{
func_t l_func = (func_t)Dlsym(lib_handle, func_name);
if (l_func == nullptr)
{ // Error handling for symbol resolution
std::string message = std::string("Failed to load function: ") + std::string(func_name) + std::string(" from ") +
std::string(libname) + std::string(" (");

std::string what_happened = get_os_error();

message += what_happened + std::string(")");

throw std::runtime_error(message.c_str());
}
return l_func;
}
};

51 changes: 51 additions & 0 deletions include/load_shared_libraries/get_os_error.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include <string>

#if defined (__WIN32__) || defined(_WIN32)
#include <windows.h>
#elif defined(__linux__)
#include <dlfcn.h>
#define Dlerror dlerror
#endif

inline std::string get_os_error() noexcept
{
#if defined (__WIN32__) || defined(_WIN32)

DWORD error_code = GetLastError();

// Buffer to store the error message
TCHAR win_message[256];

// Call FormatMessage to convert the error code to a string
DWORD result = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM, // Get message from system error codes
NULL, // No source string to format
error_code, // The error code to convert
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
win_message, // Buffer to receive the message
sizeof(win_message) / sizeof(TCHAR) - 1, // Size of message buffer in TCHARs
NULL // No additional formatting arguments
);

std::string what_happened;
if (result)
{
#ifdef UNICODE
std::wstring tt = std::wstring(win_message);
#else
std::string tt = std::string(win_message);
#endif

what_happened = std::string(tt.begin(), tt.end());
}
else
// Handle potential formatting errors
what_happened = std::string("Unknown error ") + std::to_string(error_code);
#elif defined(__linux__)
std::string what_happened = std::string(Dlerror());
#endif
return what_happened;
}

93 changes: 93 additions & 0 deletions include/load_shared_libraries/libloader.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#pragma once

#if defined (__WIN32__) || defined(_WIN32)
#include <windows.h>
#define Dlopen(name, flags) LoadLibraryA(name)
#define Dlclose FreeLibrary
#define Dlerror GetLastError
#elif defined(__linux__)
#include <dlfcn.h>
#define Dlopen(name, flags) dlopen(name, flags)
#define Dlclose dlclose
#define Dlerror dlerror
#endif

#include "get_os_error.hxx"

#include <stdexcept>
#include <string>

/**
* @brief Cross-platform loader for dynamic libraries.
*/
template <typename dtype_t>
class LibLoader
{
private:
#if defined (__WIN32__) || defined(_WIN32)
HMODULE p_lib_handle = nullptr;
#elif defined(__linux__)
void* p_lib_handle = nullptr;
#endif
public:

/**
* @brief Loads the dynamic library in memory.
*
* @param libname [in] The name of the library to load. For linux, "lib" is prepended to the name.
* @param load_options [in] Ignored for Windows.
*
* @throws Runtime error if the load fails.
*/
explicit LibLoader(const char* libname, const int load_options) noexcept(false)
{
std::string local_libname{ libname };
#if defined(__linux__)
local_libname = std::string("lib") + local_libname;
#endif
p_lib_handle = Dlopen(local_libname.c_str(), load_options);
if (p_lib_handle == nullptr)
{ // Error handling for loading the library
std::string message = std::string("Failed to open library: ") + local_libname + std::string(" (");

std::string what_happened = get_os_error();

message += what_happened + std::string(")");

throw std::runtime_error(message.c_str());
}
}

/**
* @brief Loads the dynamic library in memory.
*
* @param libname [in] The name of the library to load. For linux, "lib" is prepended to the name.
* @param load_options [in] Ignored for Windows.
*
* @throws Runtime error if the load fails.
*/
explicit LibLoader(const std::string& libname, const int load_options) noexcept(false) :
LibLoader(libname.c_str(), load_options)
{}

/**
* @brief Releases the handle to the library.
*/
~DynLibLoader() noexcept
{
Dlclose(p_lib_handle);
}

/**
* @brief Returns the handle to the dynamic library.
*/
#if defined (__WIN32__) || defined(_WIN32)
HINSTANCE Handle() const
#elif defined(__linux__)
void* Handle() const
#endif
{
return p_lib_handle;
}

};

0 comments on commit 2f4a198

Please sign in to comment.