Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/common/dynamic_library.cpp
4214 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: 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_CHANNEL(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
}
174
175