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 derelict.util.sharedlib; 29 30 private 31 { 32 import derelict.util.exception; 33 import derelict.util.compat; 34 } 35 36 version(linux) 37 { 38 version = Nix; 39 } 40 else version(darwin) 41 { 42 version = Nix; 43 } 44 else version(OSX) 45 { 46 version = Nix; 47 } 48 else version(FreeBSD) 49 { 50 version = Nix; 51 version = freebsd; 52 } 53 else version(freebsd) 54 { 55 version = Nix; 56 } 57 else version(Unix) 58 { 59 version = Nix; 60 } 61 else version(Posix) 62 { 63 version = Nix; 64 } 65 66 version(Nix) 67 { 68 // for people using DSSS, tell it to link the executable with libdl 69 version(build) 70 { 71 version(freebsd) 72 { 73 // the dl* functions are in libc on FreeBSD 74 } 75 else pragma(link, "dl"); 76 } 77 78 version(Tango) 79 { 80 private import tango.sys.Common; 81 } 82 else version(linux) 83 { 84 private import core.sys.posix.dlfcn; 85 } 86 else 87 { 88 extern(C) 89 { 90 /* From <dlfcn.h> 91 * See http://www.opengroup.org/onlinepubs/007908799/xsh/dlsym.html 92 */ 93 94 const int RTLD_NOW = 2; 95 96 void *dlopen(CCPTR file, int mode); 97 int dlclose(void* handle); 98 void *dlsym(void* handle, CCPTR name); 99 CCPTR dlerror(); 100 } 101 } 102 103 alias void* SharedLibHandle; 104 105 private SharedLibHandle LoadSharedLib(string libName) 106 { 107 return dlopen(toCString(libName), RTLD_NOW); 108 } 109 110 private void UnloadSharedLib(SharedLibHandle hlib) 111 { 112 dlclose(hlib); 113 } 114 115 private void* GetSymbol(SharedLibHandle hlib, string symbolName) 116 { 117 return dlsym(hlib, toCString(symbolName)); 118 } 119 120 private string GetErrorStr() 121 { 122 CCPTR err = dlerror(); 123 if(err is null) 124 return "Uknown Error"; 125 126 return toDString(err); 127 } 128 129 } 130 else version(Windows) 131 { 132 private import derelict.util.wintypes; 133 alias HMODULE SharedLibHandle; 134 135 private SharedLibHandle LoadSharedLib(string libName) 136 { 137 return LoadLibraryA(toCString(libName)); 138 } 139 140 private void UnloadSharedLib(SharedLibHandle hlib) 141 { 142 FreeLibrary(hlib); 143 } 144 145 private void* GetSymbol(SharedLibHandle hlib, string symbolName) 146 { 147 return GetProcAddress(hlib, toCString(symbolName)); 148 } 149 150 private string GetErrorStr() 151 { 152 // adapted from Tango 153 154 DWORD errcode = GetLastError(); 155 156 LPCSTR msgBuf; 157 DWORD i = FormatMessageA( 158 FORMAT_MESSAGE_ALLOCATE_BUFFER | 159 FORMAT_MESSAGE_FROM_SYSTEM | 160 FORMAT_MESSAGE_IGNORE_INSERTS, 161 null, 162 errcode, 163 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 164 cast(LPCSTR)&msgBuf, 165 0, 166 null); 167 168 string text = toDString(msgBuf); 169 LocalFree(cast(HLOCAL)msgBuf); 170 171 if(i >= 2) 172 i -= 2; 173 return text[0 .. i]; 174 } 175 } 176 else 177 { 178 static assert(0, "Derelict does not support this platform."); 179 } 180 181 final class SharedLib 182 { 183 public: 184 this() 185 { 186 } 187 188 string name() 189 { 190 return _name; 191 } 192 193 bool isLoaded() 194 { 195 return (_hlib !is null); 196 } 197 198 void load(string[] names) 199 { 200 if(isLoaded) 201 return; 202 203 string[] failedLibs; 204 string[] reasons; 205 206 foreach(n; names) 207 { 208 _hlib = LoadSharedLib(n); 209 if(_hlib !is null) 210 { 211 _name = n; 212 break; 213 } 214 215 failedLibs ~= n; 216 reasons ~= GetErrorStr(); 217 } 218 219 if(!isLoaded) 220 { 221 SharedLibLoadException.throwNew(failedLibs, reasons); 222 } 223 } 224 225 void* loadSymbol(string symbolName, bool doThrow = true) 226 { 227 void* sym = GetSymbol(_hlib, symbolName); 228 if(doThrow && (sym is null)) 229 Derelict_HandleMissingSymbol(name, symbolName); 230 231 return sym; 232 } 233 234 void unload() 235 { 236 if(isLoaded) 237 { 238 UnloadSharedLib(_hlib); 239 _hlib = null; 240 } 241 } 242 243 private: 244 string _name; 245 SharedLibHandle _hlib; 246 }