1 /* 2 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 */ 28 /** 29 Loading and unloading shared libraries. 30 */ 31 module dplug.core.sharedlib; 32 33 import dplug.core.nogc; 34 import dplug.core.vec; 35 36 //version = debugSharedLibs; 37 38 version(debugSharedLibs) 39 { 40 import core.stdc.stdio; 41 } 42 43 /// Shared library ressource 44 struct SharedLib 45 { 46 nothrow: 47 @nogc: 48 49 void load(string name) 50 { 51 version(debugSharedLibs) 52 { 53 auto lib = CString(name); 54 printf("loading dynlib '%s'\n", lib.storage); 55 } 56 57 if(isLoaded) 58 return; 59 _name = name; 60 _hlib = LoadSharedLib(name); 61 if(_hlib is null) 62 assert(false, "Couldn't open the shared library."); 63 } 64 65 bool hasSymbol(string symbolName) 66 { 67 assert(isLoaded()); 68 void* sym = GetSymbol(_hlib, symbolName); 69 return sym != null; 70 } 71 72 void* loadSymbol(string symbolName) 73 { 74 assert(isLoaded()); 75 76 version(debugSharedLibs) 77 { 78 auto sb = CString(symbolName); 79 printf(" loading symbol '%s'\n", sb.storage); 80 } 81 82 void* sym = GetSymbol(_hlib, symbolName); 83 if(!sym) 84 assert(false, "Couldn't get symbol."); 85 return sym; 86 } 87 88 void unload() 89 { 90 if(isLoaded()) 91 { 92 UnloadSharedLib(_hlib); 93 _hlib = null; 94 95 version(debugSharedLibs) 96 { 97 auto lib = CString(_name); 98 printf("unloaded dynlib '%s'\n", lib.storage); 99 } 100 } 101 } 102 103 /// Returns true if the shared library is currently loaded, false otherwise. 104 bool isLoaded() 105 { 106 return (_hlib !is null); 107 } 108 109 private: 110 string _name; 111 SharedLibHandle _hlib; 112 } 113 114 /// Loader. In debug mode, this fills functions pointers with null. 115 abstract class SharedLibLoader 116 { 117 nothrow: 118 @nogc: 119 120 this(string libName) 121 { 122 _libName = libName; 123 version(debugSharedLibs) 124 { 125 _funcPointers = makeAlignedBuffer!(void**)(); 126 } 127 } 128 129 /// Binds a function pointer to a symbol in this loader's shared library. 130 final void bindFunc(void** ptr, string funcName) 131 { 132 void* func = _lib.loadSymbol(funcName); 133 version(debugSharedLibs) 134 { 135 _funcPointers.pushBack(ptr); 136 } 137 *ptr = func; 138 } 139 140 final void load() 141 { 142 _lib.load(_libName); 143 loadSymbols(); 144 } 145 146 // Unload the library, and sets all functions pointer to null. 147 final void unload() 148 { 149 _lib.unload(); 150 151 version(debugSharedLibs) 152 { 153 // Sets all registered functions pointers to null 154 // so that they can't be reused 155 foreach(ptr; _funcPointers[]) 156 *ptr = null; 157 158 _funcPointers.clearContents(); 159 } 160 } 161 162 protected: 163 164 /// Implemented by subclasses to load all symbols with `bindFunc`. 165 abstract void loadSymbols(); 166 167 private: 168 string _libName; 169 SharedLib _lib; 170 version(debugSharedLibs) 171 Vec!(void**) _funcPointers; 172 } 173 174 175 private: 176 177 alias void* SharedLibHandle; 178 179 version(Posix) 180 { 181 import core.sys.posix.dlfcn; 182 183 private { 184 185 SharedLibHandle LoadSharedLib(string libName) nothrow @nogc 186 { 187 return dlopen(CString(libName), RTLD_NOW); 188 } 189 190 void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc 191 { 192 dlclose(hlib); 193 } 194 195 void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc 196 { 197 return dlsym(hlib, CString(symbolName)); 198 } 199 200 string GetErrorStr() 201 { 202 import std.conv : to; 203 204 auto err = dlerror(); 205 if(err is null) 206 return "Unknown Error"; 207 208 return to!string(err); 209 } 210 } 211 } 212 else version(Windows) 213 { 214 import core.sys.windows.windows; 215 216 private { 217 nothrow @nogc 218 SharedLibHandle LoadSharedLib(string libName) 219 { 220 return LoadLibraryA(CString(libName)); 221 } 222 223 nothrow @nogc 224 void UnloadSharedLib(SharedLibHandle hlib) 225 { 226 FreeLibrary(hlib); 227 } 228 229 nothrow @nogc 230 void* GetSymbol(SharedLibHandle hlib, string symbolName) 231 { 232 return GetProcAddress(hlib, CString(symbolName)); 233 } 234 235 nothrow @nogc 236 string GetErrorStr() 237 { 238 import std.windows.syserror; 239 DWORD err = GetLastError(); 240 return assumeNothrowNoGC( 241 (DWORD err) 242 { 243 return sysErrorString(err); 244 } 245 )(err); 246 } 247 } 248 } else { 249 static assert(0, "Derelict does not support this platform."); 250 }