CppCommon  1.0.4.1
C++ Common Library
dll.cpp
Go to the documentation of this file.
1 
9 #include "system/dll.h"
10 
11 #include "errors/fatal.h"
12 #include "string/format.h"
14 
15 #include <cassert>
16 
17 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
18 #include <dlfcn.h>
19 #elif defined(_WIN32) || defined(_WIN64)
20 #include <windows.h>
21 #endif
22 
23 namespace CppCommon {
24 
26 
27 class DLL::Impl
28 {
29 public:
30  Impl() : _dll(nullptr) {}
31 
32  ~Impl()
33  {
34  try
35  {
36  if (IsLoaded())
37  Unload();
38  }
39  catch (const DLLException& ex)
40  {
41  fatality(DLLException(ex.string()).Attach(_path));
42  }
43  }
44 
45  const Path path() const { return _path; }
46 
47  bool IsLoaded() const
48  {
49  return (_dll != nullptr);
50  }
51 
52  bool IsResolve(const std::string& name) const
53  {
54  assert(IsLoaded() && "DLL must be loaded!");
55  if (!IsLoaded())
56  return false;
57 
58  return ResolveAddress(name) != nullptr;
59  }
60 
61  void Assign(const Path& path)
62  {
63  assert(!IsLoaded() && "DLL must not be loaded when assigning a new path!");
64  if (IsLoaded())
65  Unload();
66 
67  _path = path;
68 
69 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
70  // Concatenate DLL executable path
71  if (_path.IsRelative())
72  _path = Path::executable().parent().Append(_path);
73 #endif
74 
75  // Concatenate DLL prefix if not provided
76  std::string filename = _path.filename().string();
77  std::string prefix = DLL::prefix();
78  if (std::strncmp(filename.c_str(), prefix.c_str(), prefix.size()) != 0)
79  _path.ReplaceFilename(prefix + filename);
80 
81  // Concatenate DLL extension if not provided
82  if (_path.extension() != DLL::extension())
83  _path.Concat(DLL::extension());
84  }
85 
86  bool Load()
87  {
88  assert(!IsLoaded() && "DLL is already loaded!");
89  if (IsLoaded())
90  Unload();
91 
92 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
93  _dll = dlopen(_path.string().c_str(), RTLD_NOW);
94 #elif defined(_WIN32) || defined(_WIN64)
95  _dll = LoadLibraryExW(_path.wstring().c_str(), nullptr, 0);
96 #endif
97  return (_dll != nullptr);
98  }
99 
100  bool Load(const Path& path)
101  {
102  Assign(path);
103  return Load();
104  }
105 
106  void Unload()
107  {
108  assert(IsLoaded() && "DLL is not loaded!");
109  if (!IsLoaded())
110  return;
111 
112 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
113  int result = dlclose(_dll);
114  if (result != 0)
115  throwex DLLException(format("Cannot unload DLL file: {}!", dlerror())).Attach(_path);
116 #elif defined(_WIN32) || defined(_WIN64)
117  if (!FreeLibrary(_dll))
118  throwex DLLException("Cannot unload DLL file!").Attach(_path);
119 #endif
120  _dll = nullptr;
121  }
122 
123  void* ResolveAddress(const std::string& name) const
124  {
125  assert(IsLoaded() && "DLL is not loaded!");
126  if (!IsLoaded())
127  return nullptr;
128 
129 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
130  return dlsym(_dll, name.c_str());
131 #elif defined(_WIN32) || defined(_WIN64)
132  return (void*)GetProcAddress(_dll, name.c_str());
133 #endif
134  }
135 
136 private:
137  Path _path;
138 #if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
139  void* _dll;
140 #elif defined(_WIN32) || defined(_WIN64)
141  HMODULE _dll;
142 #endif
143 };
144 
146 
148 {
149  // Check implementation storage parameters
150  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
151  static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
152  static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
153 
154  // Create the implementation instance
155  new(&_storage)Impl();
156 }
157 
158 DLL::DLL(const Path& path, bool load)
159 {
160  // Check implementation storage parameters
161  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
162  static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
163  static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
164 
165  // Create the implementation instance
166  new(&_storage)Impl();
167 
168  impl().Assign(path);
169 
170  if (load)
171  impl().Load();
172 }
173 
174 DLL::DLL(const DLL& dll)
175 {
176  // Check implementation storage parameters
177  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
178  static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
179  static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
180 
181  // Create the implementation instance
182  new(&_storage)Impl();
183 
184  impl().Assign(dll.path());
185 }
186 
187 DLL::DLL(DLL&& dll) noexcept
188 {
189  // Check implementation storage parameters
190  [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
191  static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
192  static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
193 
194  // Create the implementation instance
195  new(&_storage)Impl();
196 
197  std::swap(_storage, dll._storage);
198 }
199 
201 {
202  // Delete the implementation instance
203  reinterpret_cast<Impl*>(&_storage)->~Impl();
204 }
205 
206 DLL& DLL::operator=(const Path& path)
207 {
208  impl().Assign(path);
209  return *this;
210 }
211 
212 DLL& DLL::operator=(const DLL& dll)
213 {
214  impl().Assign(dll.path());
215  return *this;
216 }
217 
218 DLL& DLL::operator=(DLL&& dll) noexcept
219 {
220  std::swap(_storage, dll._storage);
221  return *this;
222 }
223 
224 const Path DLL::path() const { return impl().path(); }
225 
226 bool DLL::IsLoaded() const { return impl().IsLoaded(); }
227 bool DLL::IsResolve(const std::string& name) const { return impl().IsResolve(name); }
228 
229 bool DLL::Load() { return impl().Load(); }
230 bool DLL::Load(const Path& path) { return impl().Load(path); }
231 void DLL::Unload() { impl().Unload(); }
232 
233 void* DLL::ResolveAddress(const std::string& name) const { return impl().ResolveAddress(name); }
234 
235 void DLL::swap(DLL& dll) noexcept
236 {
237  using std::swap;
238  swap(_storage, dll._storage);
239 }
240 
241 } // namespace CppCommon
Dynamic link library.
Definition: dll.h:56
static std::string extension()
Get the dynamic link library extension.
Definition: dll.inl:28
DLL & operator=(const Path &path)
Definition: dll.cpp:206
static std::string prefix()
Get the dynamic link library prefix.
Definition: dll.inl:17
bool IsResolve(const std::string &name) const
Is dynamic link library resolve the given symbol?
Definition: dll.cpp:227
bool Load()
Load dynamic link library.
Definition: dll.cpp:229
void Unload()
Unload dynamic link library.
Definition: dll.cpp:231
void swap(DLL &dll) noexcept
Swap two instances.
Definition: dll.cpp:235
DLL()
Initialize the dynamic link library with an empty path.
Definition: dll.cpp:147
const Path path() const
Get the dynamic link library path.
Definition: dll.cpp:224
bool IsLoaded() const
Is dynamic link library loaded?
Definition: dll.cpp:226
Filesystem path.
Definition: path.h:90
Path parent() const
Decompose parent path from the current path.
Definition: path.cpp:144
Path & Append(const Path &path)
Append the given path to the current one.
Definition: path.cpp:737
Path filename() const
Decompose filename from the current path.
Definition: path.cpp:209
const std::string & string() const noexcept
Get the path value as UTF-8 string.
Definition: path.h:151
static Path executable()
Get the executable path of the process.
Definition: path.cpp:910
Dynamic link library definition.
#define throwex
Throw extended exception macro.
Definition: exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition: fatal.h:22
Format string definition.
C++ Common project definitions.
Definition: token_bucket.h:15
std::string format(fmt::format_string< T... > pattern, T &&... args)
Format string.
Definition: format.inl:12
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition: filecache.inl:23
Aligned storage validator definition.