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