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 return dlopen(CString(libName), RTLD_NOW); 186 } 187 188 void UnloadSharedLib(SharedLibHandle hlib) nothrow @nogc 189 { 190 dlclose(hlib); 191 } 192 193 void* GetSymbol(SharedLibHandle hlib, string symbolName) nothrow @nogc 194 { 195 return dlsym(hlib, CString(symbolName)); 196 } 197 } 198 } 199 else version(Windows) 200 { 201 import core.sys.windows.winbase; 202 203 private { 204 nothrow @nogc 205 SharedLibHandle LoadSharedLib(string libName) 206 { 207 return LoadLibraryA(CString(libName)); 208 } 209 210 nothrow @nogc 211 void UnloadSharedLib(SharedLibHandle hlib) 212 { 213 FreeLibrary(hlib); 214 } 215 216 nothrow @nogc 217 void* GetSymbol(SharedLibHandle hlib, string symbolName) 218 { 219 return GetProcAddress(hlib, CString(symbolName)); 220 } 221 } 222 } else { 223 static assert(0, "Derelict does not support this platform."); 224 }