Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
helios::utils::DynamicLibrary Class Reference

#include <dynamic_library.hpp>

Public Types

using HandleType = void *
 Native handle type (void* on all platforms for ABI stability)
 

Public Member Functions

 DynamicLibrary ()=default
 
 DynamicLibrary (const std::filesystem::path &path)
 Constructs and loads a library from the specified path.
 
 DynamicLibrary (const DynamicLibrary &)=delete
 
 DynamicLibrary (DynamicLibrary &&other) noexcept
 
 ~DynamicLibrary () noexcept
 Destructor that unloads the library if loaded.
 
DynamicLibraryoperator= (const DynamicLibrary &)=delete
 
DynamicLibraryoperator= (DynamicLibrary &&other) noexcept
 
auto Load (const std::filesystem::path &path) -> std::expected< void, DynamicLibraryError >
 Loads a dynamic library from the specified path.
 
auto Unload () -> std::expected< void, DynamicLibraryError >
 Unloads the currently loaded library.
 
auto Reload () -> std::expected< void, DynamicLibraryError >
 Reloads the library from the same path.
 
auto GetSymbolAddress (std::string_view name) const -> std::expected< void *, DynamicLibraryError >
 Gets a raw symbol address from the library.
 
template<typename T >
requires std::is_pointer_v<T>
auto GetSymbol (std::string_view name) const -> std::expected< T, DynamicLibraryError >
 Gets a typed function pointer from the library.
 
bool Loaded () const noexcept
 Checks if a library is currently loaded.
 
const std::filesystem::path & Path () const noexcept
 Gets the path of the loaded library.
 
HandleType Handle () const noexcept
 Gets the native handle of the loaded library.
 

Static Public Member Functions

static auto FromPath (const std::filesystem::path &path) -> std::expected< DynamicLibrary, DynamicLibraryError >
 
static std::string GetLastErrorMessage () noexcept
 Gets the last platform-specific error message.
 
static constexpr std::string_view GetPlatformExtension () noexcept
 Gets the platform-specific file extension for dynamic libraries.
 
static constexpr std::string_view GetPlatformPrefix () noexcept
 Gets the platform-specific library prefix.
 

Static Public Attributes

static constexpr HandleType kInvalidHandle = nullptr
 

Detailed Description

Definition at line 74 of file dynamic_library.hpp.

Member Typedef Documentation

◆ HandleType

Native handle type (void* on all platforms for ABI stability)

Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 77 of file dynamic_library.hpp.

Constructor & Destructor Documentation

◆ DynamicLibrary() [1/4]

helios::utils::DynamicLibrary::DynamicLibrary ( )
default

◆ DynamicLibrary() [2/4]

helios::utils::DynamicLibrary::DynamicLibrary ( const std::filesystem::path &  path)
inlineexplicit

Constructs and loads a library from the specified path.

Parameters
pathPath to the dynamic library

Definition at line 193 of file dynamic_library.hpp.

193 {
194 auto result = Load(path);
195 if (!result) {
196 HELIOS_ERROR("Failed to load dynamic library '{}': {}!", path.string(),
197 DynamicLibraryErrorToString(result.error()));
198 }
199}
auto Load(const std::filesystem::path &path) -> std::expected< void, DynamicLibraryError >
Loads a dynamic library from the specified path.
#define HELIOS_ERROR(...)
Definition logger.hpp:689
constexpr std::string_view DynamicLibraryErrorToString(DynamicLibraryError error) noexcept
Gets a human-readable description for a DynamicLibraryError.

◆ DynamicLibrary() [3/4]

helios::utils::DynamicLibrary::DynamicLibrary ( const DynamicLibrary )
delete

◆ DynamicLibrary() [4/4]

helios::utils::DynamicLibrary::DynamicLibrary ( DynamicLibrary &&  other)
inlinenoexcept

Definition at line 201 of file dynamic_library.hpp.

202 : handle_(other.handle_), path_(std::move(other.path_)) {
203 other.handle_ = kInvalidHandle;
204}
static constexpr HandleType kInvalidHandle

◆ ~DynamicLibrary()

helios::utils::DynamicLibrary::~DynamicLibrary ( )
inlinenoexcept

Destructor that unloads the library if loaded.

Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 206 of file dynamic_library.hpp.

206 {
207 if (Loaded()) {
208 auto result = Unload();
209 if (!result) {
210 HELIOS_WARN("Failed to unload dynamic library '{}': {}!", path_.string(),
211 DynamicLibraryErrorToString(result.error()));
212 }
213 }
214}
bool Loaded() const noexcept
Checks if a library is currently loaded.
auto Unload() -> std::expected< void, DynamicLibraryError >
Unloads the currently loaded library.
#define HELIOS_WARN(...)
Definition logger.hpp:687

Member Function Documentation

◆ FromPath()

static auto helios::utils::DynamicLibrary::FromPath ( const std::filesystem::path &  path) -> std::expected< DynamicLibrary, DynamicLibraryError >
static

◆ GetLastErrorMessage()

std::string helios::utils::DynamicLibrary::GetLastErrorMessage ( )
staticnoexcept

Gets the last platform-specific error message.

Returns
Error message string
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 100 of file dynamic_library.cpp.

100 {
101#ifdef HELIOS_PLATFORM_WINDOWS
102 DWORD error_code = GetLastError();
103 if (error_code == 0) {
104 return "No error";
105 }
106
107 LPSTR message_buffer = nullptr;
108 const size_t size = FormatMessageA(
109 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code,
110 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPSTR>(&message_buffer), 0, nullptr);
111
112 std::string message(message_buffer, size);
113 LocalFree(message_buffer);
114
115 // Remove trailing newline
116 while (!message.empty() && (message.back() == '\n' || message.back() == '\r')) {
117 message.pop_back();
118 }
119
120 return message;
121#else
122 const char* error = dlerror();
123 return error != nullptr ? std::string(error) : "No error";
124#endif
125}

◆ GetPlatformExtension()

static constexpr std::string_view helios::utils::DynamicLibrary::GetPlatformExtension ( )
inlinestaticconstexprnoexcept

Gets the platform-specific file extension for dynamic libraries.

Returns
".dll" on Windows, ".so" on Linux, ".dylib" on macOS
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 166 of file dynamic_library.hpp.

166 {
167#ifdef HELIOS_PLATFORM_WINDOWS
168 return ".dll";
169#elifdef HELIOS_PLATFORM_MACOS
170 return ".dylib";
171#else
172 return ".so";
173#endif
174 }

◆ GetPlatformPrefix()

static constexpr std::string_view helios::utils::DynamicLibrary::GetPlatformPrefix ( )
inlinestaticconstexprnoexcept

Gets the platform-specific library prefix.

Returns
Empty on Windows, "lib" on Unix-like systems
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 180 of file dynamic_library.hpp.

180 {
181#ifdef HELIOS_PLATFORM_WINDOWS
182 return "";
183#else
184 return "lib";
185#endif
186 }

◆ GetSymbol()

template<typename T >
requires std::is_pointer_v<T>
auto helios::utils::DynamicLibrary::GetSymbol ( std::string_view  name) const -> std::expected<T, DynamicLibraryError>
inline

Gets a typed function pointer from the library.

Template Parameters
TFunction pointer type
Parameters
nameName of the symbol to retrieve
Returns
Expected with function pointer on success, or error on failure
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 253 of file dynamic_library.hpp.

253 {
254 auto result = GetSymbolAddress(name);
255 if (!result) {
256 return std::unexpected(result.error());
257 }
258
259 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
260 return reinterpret_cast<T>(*result);
261}
auto GetSymbolAddress(std::string_view name) const -> std::expected< void *, DynamicLibraryError >
Gets a raw symbol address from the library.

◆ GetSymbolAddress()

auto helios::utils::DynamicLibrary::GetSymbolAddress ( std::string_view  name) const -> std::expected<void*, DynamicLibraryError>

Gets a raw symbol address from the library.

Parameters
nameName of the symbol to retrieve
Returns
Expected with void pointer on success, or error on failure
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 76 of file dynamic_library.cpp.

76 {
77 if (!Loaded()) {
78 return std::unexpected(DynamicLibraryError::NotLoaded);
79 }
80
81 // Need null-terminated string for platform APIs
82 std::string name_str(name);
83
84 void* symbol = nullptr;
85#ifdef HELIOS_PLATFORM_WINDOWS
86 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
87 symbol = reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle_), name_str.c_str()));
88#else
89 symbol = dlsym(handle_, name_str.c_str());
90#endif
91
92 if (symbol == nullptr) {
93 HELIOS_WARN("Symbol '{}' not found in library '{}': {}!", name, path_.string(), GetLastErrorMessage());
94 return std::unexpected(DynamicLibraryError::SymbolNotFound);
95 }
96
97 return symbol;
98}
static std::string GetLastErrorMessage() noexcept
Gets the last platform-specific error message.
@ NotLoaded
Library is not loaded.
@ SymbolNotFound
Symbol not found in library.

◆ Handle()

HandleType helios::utils::DynamicLibrary::Handle ( ) const
inlinenoexcept

Gets the native handle of the loaded library.

Returns
Native handle, or kInvalidHandle if not loaded
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 154 of file dynamic_library.hpp.

154{ return handle_; }

◆ Load()

auto helios::utils::DynamicLibrary::Load ( const std::filesystem::path &  path) -> std::expected<void, DynamicLibraryError>

Loads a dynamic library from the specified path.

Parameters
pathPath to the dynamic library
Returns
Expected with void on success, or error on failure
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 26 of file dynamic_library.cpp.

26 {
27 if (Loaded()) {
28 return std::unexpected(DynamicLibraryError::AlreadyLoaded);
29 }
30
31 if (!std::filesystem::exists(path)) {
32 return std::unexpected(DynamicLibraryError::FileNotFound);
33 }
34
35#ifdef HELIOS_PLATFORM_WINDOWS
36 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
37 handle_ = reinterpret_cast<HandleType>(LoadLibraryW(path.wstring().c_str()));
38#else
39 handle_ = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
40#endif
41
42 if (handle_ == kInvalidHandle) {
43 HELIOS_ERROR("Failed to load library '{}': {}!", path.string(), GetLastErrorMessage());
44 return std::unexpected(DynamicLibraryError::LoadFailed);
45 }
46
47 path_ = path;
48 HELIOS_DEBUG("Loaded dynamic library: {}", path_.string());
49 return {};
50}
void * HandleType
Native handle type (void* on all platforms for ABI stability)
#define HELIOS_DEBUG(...)
Definition logger.hpp:667
@ FileNotFound
Library file not found.
@ LoadFailed
Failed to load library.
@ AlreadyLoaded
Library is already loaded.

◆ Loaded()

bool helios::utils::DynamicLibrary::Loaded ( ) const
inlinenoexcept

Checks if a library is currently loaded.

Returns
True if a library is loaded
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 142 of file dynamic_library.hpp.

142{ return handle_ != kInvalidHandle; }

◆ operator=() [1/2]

◆ operator=() [2/2]

DynamicLibrary & helios::utils::DynamicLibrary::operator= ( DynamicLibrary &&  other)
inlinenoexcept

Definition at line 216 of file dynamic_library.hpp.

216 {
217 if (this != &other) {
218 if (Loaded()) {
219 [[maybe_unused]] auto _ = Unload();
220 }
221 handle_ = other.handle_;
222 path_ = std::move(other.path_);
223 other.handle_ = kInvalidHandle;
224 }
225 return *this;
226}

◆ Path()

const std::filesystem::path & helios::utils::DynamicLibrary::Path ( ) const
inlinenoexcept

Gets the path of the loaded library.

Returns
Path to the library, or empty if not loaded
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 148 of file dynamic_library.hpp.

148{ return path_; }

◆ Reload()

auto helios::utils::DynamicLibrary::Reload ( ) -> std::expected<void, DynamicLibraryError>
inline

Reloads the library from the same path.

Unloads the current library and loads it again.

Returns
Expected with void on success, or error on failure
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 236 of file dynamic_library.hpp.

236 {
237 if (!Loaded()) {
238 return std::unexpected(DynamicLibraryError::NotLoaded);
239 }
240
241 const auto saved_path = path_;
242
243 auto unload_result = Unload();
244 if (!unload_result) {
245 return unload_result;
246 }
247
248 return Load(saved_path);
249}

◆ Unload()

auto helios::utils::DynamicLibrary::Unload ( ) -> std::expected<void, DynamicLibraryError>

Unloads the currently loaded library.

Returns
Expected with void on success, or error on failure
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/utils/dynamic_library.hpp.

Definition at line 52 of file dynamic_library.cpp.

52 {
53 if (!Loaded()) {
54 return std::unexpected(DynamicLibraryError::NotLoaded);
55 }
56
57 bool success = false;
58#ifdef HELIOS_PLATFORM_WINDOWS
59 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
60 success = FreeLibrary(reinterpret_cast<HMODULE>(handle_)) != 0;
61#else
62 success = dlclose(handle_) == 0;
63#endif
64
65 if (!success) {
66 HELIOS_ERROR("Failed to unload library '{}': {}!", path_.string(), GetLastErrorMessage());
67 return std::unexpected(DynamicLibraryError::PlatformError);
68 }
69
70 HELIOS_DEBUG("Unloaded dynamic library: {}", path_.string());
71 handle_ = kInvalidHandle;
72 path_.clear();
73 return {};
74}
@ PlatformError
Platform-specific error.

Member Data Documentation

◆ kInvalidHandle

constexpr HandleType helios::utils::DynamicLibrary::kInvalidHandle = nullptr
staticconstexpr