duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

dynamic_library.cpp (4514B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "common/dynamic_library.h"
      5 #include "common/assert.h"
      6 #include "common/error.h"
      7 #include "common/file_system.h"
      8 #include "common/log.h"
      9 #include "common/path.h"
     10 #include "common/small_string.h"
     11 #include "common/string_util.h"
     12 
     13 #include "fmt/format.h"
     14 #include <cstring>
     15 
     16 #ifdef _WIN32
     17 #include "common/windows_headers.h"
     18 #else
     19 #include <dlfcn.h>
     20 #ifdef __APPLE__
     21 #include "common/cocoa_tools.h"
     22 #endif
     23 #endif
     24 
     25 Log_SetChannel(DynamicLibrary);
     26 
     27 DynamicLibrary::DynamicLibrary() = default;
     28 
     29 DynamicLibrary::DynamicLibrary(const char* filename)
     30 {
     31   Error error;
     32   if (!Open(filename, &error))
     33     ERROR_LOG(error.GetDescription());
     34 }
     35 
     36 DynamicLibrary::DynamicLibrary(DynamicLibrary&& move) : m_handle(move.m_handle)
     37 {
     38   move.m_handle = nullptr;
     39 }
     40 
     41 DynamicLibrary::~DynamicLibrary()
     42 {
     43   Close();
     44 }
     45 
     46 std::string DynamicLibrary::GetUnprefixedFilename(const char* filename)
     47 {
     48 #if defined(_WIN32)
     49   return std::string(filename) + ".dll";
     50 #elif defined(__APPLE__)
     51   return std::string(filename) + ".dylib";
     52 #else
     53   return std::string(filename) + ".so";
     54 #endif
     55 }
     56 
     57 std::string DynamicLibrary::GetVersionedFilename(const char* libname, int major, int minor, int patch)
     58 {
     59 #if defined(_WIN32)
     60   if (major >= 0 && minor >= 0 && patch >= 0)
     61     return fmt::format("{}-{}-{}-{}.dll", libname, major, minor, patch);
     62   else if (major >= 0 && minor >= 0)
     63     return fmt::format("{}-{}-{}.dll", libname, major, minor);
     64   else if (major >= 0)
     65     return fmt::format("{}-{}.dll", libname, major);
     66   else
     67     return fmt::format("{}.dll", libname);
     68 #elif defined(__APPLE__)
     69   const char* prefix = std::strncmp(libname, "lib", 3) ? "lib" : "";
     70   if (major >= 0 && minor >= 0 && patch >= 0)
     71     return fmt::format("{}{}.{}.{}.{}.dylib", prefix, libname, major, minor, patch);
     72   else if (major >= 0 && minor >= 0)
     73     return fmt::format("{}{}.{}.{}.dylib", prefix, libname, major, minor);
     74   else if (major >= 0)
     75     return fmt::format("{}{}.{}.dylib", prefix, libname, major);
     76   else
     77     return fmt::format("{}{}.dylib", prefix, libname);
     78 #else
     79   const char* prefix = std::strncmp(libname, "lib", 3) ? "lib" : "";
     80   if (major >= 0 && minor >= 0 && patch >= 0)
     81     return fmt::format("{}{}.so.{}.{}.{}", prefix, libname, major, minor, patch);
     82   else if (major >= 0 && minor >= 0)
     83     return fmt::format("{}{}.so.{}.{}", prefix, libname, major, minor);
     84   else if (major >= 0)
     85     return fmt::format("{}{}.so.{}", prefix, libname, major);
     86   else
     87     return fmt::format("{}{}.so", prefix, libname);
     88 #endif
     89 }
     90 
     91 bool DynamicLibrary::Open(const char* filename, Error* error)
     92 {
     93 #ifdef _WIN32
     94   m_handle = reinterpret_cast<void*>(LoadLibraryW(StringUtil::UTF8StringToWideString(filename).c_str()));
     95   if (!m_handle)
     96   {
     97     Error::SetWin32(error, TinyString::from_format("Loading {} failed: ", filename), GetLastError());
     98     return false;
     99   }
    100 
    101   return true;
    102 #else
    103   m_handle = dlopen(filename, RTLD_NOW);
    104   if (!m_handle)
    105   {
    106 #ifdef __APPLE__
    107     // On MacOS, try searching in Frameworks.
    108     if (!Path::IsAbsolute(filename))
    109     {
    110       std::optional<std::string> bundle_path = CocoaTools::GetBundlePath();
    111       if (bundle_path.has_value())
    112       {
    113         std::string frameworks_path = fmt::format("{}/Contents/Frameworks/{}", bundle_path.value(), filename);
    114         if (FileSystem::FileExists(frameworks_path.c_str()))
    115         {
    116           m_handle = dlopen(frameworks_path.c_str(), RTLD_NOW);
    117           if (m_handle)
    118           {
    119             Error::Clear(error);
    120             return true;
    121           }
    122         }
    123       }
    124     }
    125 #endif
    126 
    127     const char* err = dlerror();
    128     Error::SetStringFmt(error, "Loading {} failed: {}", filename, err ? err : "<UNKNOWN>");
    129     return false;
    130   }
    131 
    132   return true;
    133 #endif
    134 }
    135 
    136 void DynamicLibrary::Adopt(void* handle)
    137 {
    138   AssertMsg(handle, "Handle is valid");
    139 
    140   Close();
    141 
    142   m_handle = handle;
    143 }
    144 
    145 void DynamicLibrary::Close()
    146 {
    147   if (!IsOpen())
    148     return;
    149 
    150 #ifdef _WIN32
    151   FreeLibrary(reinterpret_cast<HMODULE>(m_handle));
    152 #else
    153   dlclose(m_handle);
    154 #endif
    155   m_handle = nullptr;
    156 }
    157 
    158 void* DynamicLibrary::GetSymbolAddress(const char* name) const
    159 {
    160 #ifdef _WIN32
    161   return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(m_handle), name));
    162 #else
    163   return reinterpret_cast<void*>(dlsym(m_handle, name));
    164 #endif
    165 }
    166 
    167 DynamicLibrary& DynamicLibrary::operator=(DynamicLibrary&& move)
    168 {
    169   Close();
    170   m_handle = move.m_handle;
    171   move.m_handle = nullptr;
    172   return *this;
    173 }