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 module dplug.core.sharedlib; 29 30 import dplug.core.nogc; 31 import dplug.core.alignedbuffer; 32 33 //version = debugSharedLibs; 34 35 version(debugSharedLibs) 36 { 37 import core.stdc.stdio; 38 } 39 40 /// Shared library ressource 41 struct SharedLib 42 { 43 nothrow: 44 @nogc: 45 46 void load(string name) 47 { 48 version(debugSharedLibs) 49 { 50 auto lib = CString(name); 51 printf("loading dynlib '%s'\n", lib.storage); 52 } 53 54 if(isLoaded) 55 return; 56 _name = name; 57 _hlib = LoadSharedLib(name); 58 if(_hlib is null) 59 assert(false); 60 } 61 62 void* loadSymbol(string symbolName) 63 { 64 assert(isLoaded()); 65 66 version(debugSharedLibs) 67 { 68 auto sb = CString(symbolName); 69 printf(" loading symbol '%s'\n", sb.storage); 70 } 71 72 void* sym = GetSymbol(_hlib, symbolName); 73 if(!sym) 74 assert(false); 75 return sym; 76 } 77 78 void unload() 79 { 80 if(isLoaded()) 81 { 82 UnloadSharedLib(_hlib); 83 _hlib = null; 84 85 version(debugSharedLibs) 86 { 87 auto lib = CString(_name); 88 printf("unloaded dynlib '%s'\n", lib.storage); 89 } 90 } 91 } 92 93 /// Returns true if the shared library is currently loaded, false otherwise. 94 bool isLoaded() 95 { 96 return (_hlib !is null); 97 } 98 99 private: 100 string _name; 101 SharedLibHandle _hlib; 102 } 103 104 /// Loader. In debug mode, this fills functions pointers with null. 105 abstract class SharedLibLoader 106 { 107 nothrow: 108 @nogc: 109 110 this(string libName) 111 { 112 _libName = libName; 113 version(debugSharedLibs) 114 { 115 _funcPointers = makeAlignedBuffer!(void**)(); 116 } 117 } 118 119 /// Binds a function pointer to a symbol in this loader's shared library. 120 final void bindFunc(void** ptr, string funcName) 121 { 122 void* func = _lib.loadSymbol(funcName); 123 version(debugSharedLibs) 124 { 125 _funcPointers.pushBack(ptr); 126 } 127 *ptr = func; 128 } 129 130 final void load() 131 { 132 _lib.load(_libName); 133 loadSymbols(); 134 } 135 136 // Unload the library, and sets all functions pointer to null. 137 final void unload() 138 { 139 _lib.unload(); 140 141 version(debugSharedLibs) 142 { 143 // Sets all registered functions pointers to null 144 // so that they can't be reused 145 foreach(ptr; _funcPointers[]) 146 *ptr = null; 147 148 _funcPointers.clearContents(); 149 } 150 } 151 152 protected: 153 154 /// Implemented by subclasses to load all symbols with `bindFunc`. 155 abstract void loadSymbols(); 156 157 private: 158 string _libName; 159 SharedLib _lib; 160 version(debugSharedLibs) 161 AlignedBuffer!(void**) _funcPointers; 162 } 163 164 165 private: 166 167 alias void* SharedLibHandle; 168 169 version(Posix) 170 { 171 import core.sys.posix.dlfcn; 172 173 private { 174 175 SharedLibHandle LoadSharedLib(string libName) nothrow @nogc 176 { 177 return dlopen(CString(libName), RTLD_NOW); 178 } 179 180 void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc 181 { 182 dlclose(hlib); 183 } 184 185 void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc 186 { 187 return dlsym(hlib, CString(symbolName)); 188 } 189 190 string GetErrorStr() 191 { 192 import std.conv : to; 193 194 auto err = dlerror(); 195 if(err is null) 196 return "Unknown Error"; 197 198 return to!string(err); 199 } 200 } 201 } 202 else version(Windows) 203 { 204 import core.sys.windows.windows; 205 206 private { 207 nothrow @nogc 208 SharedLibHandle LoadSharedLib(string libName) 209 { 210 return LoadLibraryA(CString(libName)); 211 } 212 213 nothrow @nogc 214 void UnloadSharedLib(SharedLibHandle hlib) 215 { 216 FreeLibrary(hlib); 217 } 218 219 nothrow @nogc 220 void* GetSymbol(SharedLibHandle hlib, string symbolName) 221 { 222 return GetProcAddress(hlib, CString(symbolName)); 223 } 224 225 nothrow @nogc 226 string GetErrorStr() 227 { 228 import std.windows.syserror; 229 DWORD err = GetLastError(); 230 return assumeNothrowNoGC( 231 (DWORD err) 232 { 233 return sysErrorString(err); 234 } 235 )(err); 236 } 237 } 238 } else { 239 static assert(0, "Derelict does not support this platform."); 240 }