1 /** 2 Loading and unloading shared libraries. 3 4 Copyright: Derelict Contributors 2005-2015. 5 Copyright: Guillaume Piolat 2015-2016. 6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module dplug.core.sharedlib; 9 10 import dplug.core.nogc; 11 import dplug.core.vec; 12 13 //version = debugSharedLibs; 14 15 version(debugSharedLibs) 16 { 17 import core.stdc.stdio; 18 } 19 20 alias void* SharedLibHandle; 21 22 /// Shared library ressource 23 struct SharedLib 24 { 25 nothrow: 26 @nogc: 27 28 void load(string name) 29 { 30 version(debugSharedLibs) 31 { 32 auto lib = CString(name); 33 printf("loading dynlib '%s'\n", lib.storage); 34 } 35 36 if(isLoaded) 37 return; 38 _name = name; 39 _hlib = LoadSharedLib(name); 40 if(_hlib is null) 41 assert(false, "Couldn't open the shared library."); 42 } 43 44 @disable this(this); 45 46 bool hasSymbol(string symbolName) 47 { 48 assert(isLoaded()); 49 void* sym = GetSymbol(_hlib, symbolName); 50 return sym != null; 51 } 52 53 void* loadSymbol(string symbolName) 54 { 55 assert(isLoaded()); 56 57 version(debugSharedLibs) 58 { 59 auto sb = CString(symbolName); 60 printf(" loading symbol '%s'\n", sb.storage); 61 } 62 63 void* sym = GetSymbol(_hlib, symbolName); 64 if(!sym) 65 assert(false, "Couldn't get symbol."); 66 return sym; 67 } 68 69 void unload() 70 { 71 if(isLoaded()) 72 { 73 UnloadSharedLib(_hlib); 74 _hlib = null; 75 76 version(debugSharedLibs) 77 { 78 auto lib = CString(_name); 79 printf("unloaded dynlib '%s'\n", lib.storage); 80 } 81 } 82 } 83 84 /// Returns true if the shared library is currently loaded, false otherwise. 85 bool isLoaded() 86 { 87 return (_hlib !is null); 88 } 89 90 /// Return the internal shared library handle, this is used to move ownership of such objects. 91 /// Ownership of the underlying shared library is lost.initializeWithHandle 92 SharedLibHandle disown() 93 { 94 SharedLibHandle result = _hlib; 95 _hlib = null; 96 return result; 97 } 98 99 /// Recreate a SharedLib using a `disown()` stored handle. This is used instead of postblit. 100 void initializeWithHandle(SharedLibHandle handle) 101 { 102 assert(_hlib is null); 103 _hlib = handle; 104 _name = null; 105 } 106 107 private: 108 string _name; 109 SharedLibHandle _hlib; 110 } 111 112 /// Loader. In debug mode, this fills functions pointers with null. 113 abstract class SharedLibLoader 114 { 115 nothrow: 116 @nogc: 117 118 this(string libName) 119 { 120 _libName = libName; 121 version(debugSharedLibs) 122 { 123 _funcPointers = makeAlignedBuffer!(void**)(); 124 } 125 } 126 127 /// Binds a function pointer to a symbol in this loader's shared library. 128 final void bindFunc(void** ptr, string funcName) 129 { 130 void* func = _lib.loadSymbol(funcName); 131 version(debugSharedLibs) 132 { 133 _funcPointers.pushBack(ptr); 134 } 135 *ptr = func; 136 } 137 138 final void load() 139 { 140 _lib.load(_libName); 141 loadSymbols(); 142 } 143 144 // Unload the library, and sets all functions pointer to null. 145 final void unload() 146 { 147 _lib.unload(); 148 149 version(debugSharedLibs) 150 { 151 // Sets all registered functions pointers to null 152 // so that they can't be reused 153 foreach(ptr; _funcPointers[]) 154 *ptr = null; 155 156 _funcPointers.clearContents(); 157 } 158 } 159 160 protected: 161 162 /// Implemented by subclasses to load all symbols with `bindFunc`. 163 abstract void loadSymbols(); 164 165 private: 166 string _libName; 167 SharedLib _lib; 168 version(debugSharedLibs) 169 Vec!(void**) _funcPointers; 170 } 171 172 173 private: 174 175 176 177 version(Posix) 178 { 179 import core.sys.posix.dlfcn; 180 181 private { 182 183 SharedLibHandle LoadSharedLib(string libName) nothrow @nogc 184 { 185 CString libNameZ = CString(libName); 186 return dlopen(libNameZ.storage, RTLD_NOW); 187 } 188 189 void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc 190 { 191 dlclose(hlib); 192 } 193 194 void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc 195 { 196 CString symbolNameZ = CString(symbolName); 197 return dlsym(hlib, symbolNameZ.storage); 198 } 199 } 200 } 201 else version(Windows) 202 { 203 import core.sys.windows.winbase; 204 205 private { 206 nothrow @nogc 207 SharedLibHandle LoadSharedLib(string libName) 208 { 209 CString libNameZ = CString(libName); 210 return LoadLibraryA(libNameZ.storage); 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 CString symbolNameZ = CString(symbolName); 223 return GetProcAddress(hlib, symbolNameZ.storage); 224 } 225 } 226 } else { 227 static assert(0, "Derelict does not support this platform."); 228 }