// Copyright 2023 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #if defined(_WIN32) #include #else #include #endif #include "dynamic_library.h" namespace Common { DynamicLibrary::DynamicLibrary() = default; DynamicLibrary::DynamicLibrary(void* handle_) : handle{handle_} {} DynamicLibrary::DynamicLibrary(std::string_view name, int major, int minor) { auto full_name = GetLibraryName(name, major, minor); void(Load(full_name)); } DynamicLibrary::~DynamicLibrary() { if (handle) { #if defined(_WIN32) FreeLibrary(reinterpret_cast(handle)); #else dlclose(handle); #endif // defined(_WIN32) handle = nullptr; } } bool DynamicLibrary::Load(std::string_view filename) { #if defined(_WIN32) handle = reinterpret_cast(LoadLibraryA(filename.data())); if (!handle) { DWORD error_message_id = GetLastError(); LPSTR message_buffer = nullptr; std::size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_message_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&message_buffer), 0, nullptr); std::string message(message_buffer, size); load_error = message; return false; } #else handle = dlopen(filename.data(), RTLD_LAZY); if (!handle) { load_error = dlerror(); return false; } #endif // defined(_WIN32) return true; } void* DynamicLibrary::GetRawSymbol(std::string_view name) const { #if defined(_WIN32) return reinterpret_cast(GetProcAddress(reinterpret_cast(handle), name.data())); #else return dlsym(handle, name.data()); #endif // defined(_WIN32) } std::string DynamicLibrary::GetLibraryName(std::string_view name, int major, int minor) { #if defined(_WIN32) if (major >= 0 && minor >= 0) { return fmt::format("{}-{}-{}.dll", name, major, minor); } else if (major >= 0) { return fmt::format("{}-{}.dll", name, major); } else { return fmt::format("{}.dll", name); } #elif defined(__APPLE__) auto prefix = name.starts_with("lib") ? "" : "lib"; if (major >= 0 && minor >= 0) { return fmt::format("{}{}.{}.{}.dylib", prefix, name, major, minor); } else if (major >= 0) { return fmt::format("{}{}.{}.dylib", prefix, name, major); } else { return fmt::format("{}{}.dylib", prefix, name); } #else auto prefix = name.starts_with("lib") ? "" : "lib"; if (major >= 0 && minor >= 0) { return fmt::format("{}{}.so.{}.{}", prefix, name, major, minor); } else if (major >= 0) { return fmt::format("{}{}.so.{}", prefix, name, major); } else { return fmt::format("{}{}.so", prefix, name); } #endif } } // namespace Common