dynamic_library.cpp
1 // Copyright 2023 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include <fmt/format.h> 6 #if defined(_WIN32) 7 #include <windows.h> 8 #else 9 #include <dlfcn.h> 10 #endif 11 #include "dynamic_library.h" 12 13 namespace Common { 14 15 DynamicLibrary::DynamicLibrary() = default; 16 17 DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {} 18 19 DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) { 20 auto full_name = GetLibraryName(name, major, minor); 21 void(Load(full_name)); 22 } 23 24 DynamicLibrary::~DynamicLibrary() { 25 if (handle) { 26 #if defined(_WIN32) 27 FreeLibrary(reinterpret_cast<HMODULE>(handle)); 28 #else 29 dlclose(handle); 30 #endif // defined(_WIN32) 31 handle = nullptr; 32 } 33 } 34 35 bool DynamicLibrary::Load(std::string_view filename) { 36 #if defined(_WIN32) 37 handle = reinterpret_cast<void*>(LoadLibraryA(filename.data())); 38 if (!handle) { 39 DWORD error_message_id = GetLastError(); 40 LPSTR message_buffer = nullptr; 41 std::size_t size = 42 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 43 FORMAT_MESSAGE_IGNORE_INSERTS, 44 nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 45 reinterpret_cast<LPSTR>(&message_buffer), 0, nullptr); 46 std::string message(message_buffer, size); 47 load_error = message; 48 return false; 49 } 50 #else 51 handle = dlopen(filename.data(), RTLD_LAZY); 52 if (!handle) { 53 load_error = dlerror(); 54 return false; 55 } 56 #endif // defined(_WIN32) 57 return true; 58 } 59 60 void* DynamicLibrary::GetRawSymbol(std::string_view name) const { 61 #if defined(_WIN32) 62 return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle), name.data())); 63 #else 64 return dlsym(handle, name.data()); 65 #endif // defined(_WIN32) 66 } 67 68 std::string DynamicLibrary::GetLibraryName(std::string_view name, int major, int minor) { 69 #if defined(_WIN32) 70 if (major >= 0 && minor >= 0) { 71 return fmt::format("{}-{}-{}.dll", name, major, minor); 72 } else if (major >= 0) { 73 return fmt::format("{}-{}.dll", name, major); 74 } else { 75 return fmt::format("{}.dll", name); 76 } 77 #elif defined(__APPLE__) 78 auto prefix = name.starts_with("lib") ? "" : "lib"; 79 if (major >= 0 && minor >= 0) { 80 return fmt::format("{}{}.{}.{}.dylib", prefix, name, major, minor); 81 } else if (major >= 0) { 82 return fmt::format("{}{}.{}.dylib", prefix, name, major); 83 } else { 84 return fmt::format("{}{}.dylib", prefix, name); 85 } 86 #else 87 auto prefix = name.starts_with("lib") ? "" : "lib"; 88 if (major >= 0 && minor >= 0) { 89 return fmt::format("{}{}.so.{}.{}", prefix, name, major, minor); 90 } else if (major >= 0) { 91 return fmt::format("{}{}.so.{}", prefix, name, major); 92 } else { 93 return fmt::format("{}{}.so", prefix, name); 94 } 95 #endif 96 } 97 98 } // namespace Common