/ src / common / dynamic_library / dynamic_library.cpp
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