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.loader; 29 30 import std.array, 31 std.string; 32 33 import derelict.util.exception, 34 derelict.util.sharedlib, 35 derelict.util.system; 36 37 struct SharedLibVersion 38 { 39 int major; 40 int minor; 41 int patch; 42 } 43 44 abstract class SharedLibLoader 45 { 46 /++ 47 Constructs a new instance of shared lib loader with a string of one 48 or more shared library names to use as default. 49 50 Params: 51 libNames = A string containing one or more comma-separated shared 52 library names. 53 +/ 54 this(string libNames) { _libNames = libNames; } 55 56 /++ 57 Binds a function pointer to a symbol in this loader's shared library. 58 59 Params: 60 ptr = Pointer to a function pointer that will be used as the bind 61 point. 62 funcName = The name of the symbol to be bound. 63 doThrow = If true, a SymbolLoadException will be thrown if the symbol 64 is missing. If false, no exception will be thrown and the 65 ptr parameter will be set to null. 66 Throws: SymbolLoadException if doThrow is true and a the symbol 67 specified by funcName is missing from the shared library. 68 +/ 69 final void bindFunc(void** ptr, string funcName, bool doThrow = true) 70 { 71 void* func = loadSymbol(funcName, doThrow); 72 *ptr = func; 73 } 74 75 /++ 76 Binds a function pointer to a stdcall symbol in this loader's shared library. 77 78 On builds for anything other than 32-bit Windows, this simply delegates to bindFunc. 79 80 Params: 81 ptr = Pointer to a function pointer that will be used as the bind 82 point. 83 funcName = The name of the symbol to be bound. 84 doThrow = If true, a SymbolLoadException will be thrown if the symbol 85 is missing. If false, no exception will be thrown and the 86 ptr parameter will be set to null. 87 Throws: SymbolLoadException if doThrow is true and a the symbol 88 specified by funcName is missing from the shared library. 89 +/ 90 final void bindFunc_stdcall(Func)(ref Func f, string unmangledName) 91 { 92 static if(Derelict_OS_Windows && !Derelict_Arch_64) { 93 import std.format : format; 94 import std.traits : ParameterTypeTuple; 95 96 // get type-tuple of parameters 97 ParameterTypeTuple!f params; 98 99 size_t sizeOfParametersOnStack(A...)(A args) 100 { 101 size_t sum = 0; 102 foreach (arg; args) { 103 sum += arg.sizeof; 104 105 // align on 32-bit stack 106 if (sum % 4 != 0) 107 sum += 4 - (sum % 4); 108 } 109 return sum; 110 } 111 unmangledName = format("_%s@%s", unmangledName, sizeOfParametersOnStack(params)); 112 } 113 bindFunc(cast(void**)&f, unmangledName); 114 } 115 116 /++ 117 Finds and loads a shared library, using this loader's default shared library 118 names and default supported shared library version. 119 120 If multiple library names are specified as default, a SharedLibLoadException 121 will only be thrown if all of the libraries fail to load. It will be the head 122 of an exceptin chain containing one instance of the exception for each library 123 that failed. 124 125 Examples: If this loader supports versions 2.0 and 2.1 of a shared libary, 126 this method will attempt to load 2.1 and will fail if only 2.0 127 is present on the system. 128 129 Throws: SharedLibLoadException if the shared library or one of its 130 dependencies cannot be found on the file system. 131 SymbolLoadException if an expected symbol is missing from the 132 library. 133 +/ 134 final void load() { load(_libNames); } 135 136 /++ 137 Finds and loads any version of a shared library greater than or equal to 138 the required mimimum version, using this loader's default shared library 139 names. 140 141 If multiple library names are specified as default, a SharedLibLoadException 142 will only be thrown if all of the libraries fail to load. It will be the head 143 of an exceptin chain containing one instance of the exception for each library 144 that failed. 145 146 Examples: If this loader supports versions 2.0 and 2.1 of a shared library, 147 passing a SharedLibVersion with the major field set to 2 and the 148 minor field set to 0 will cause the loader to load version 2.0 149 if version 2.1 is not available on the system. 150 151 Params: 152 minRequiredVersion = the minimum version of the library that is acceptable. 153 Subclasses are free to ignore this. 154 155 Throws: SharedLibLoadException if the shared library or one of its 156 dependencies cannot be found on the file system. 157 SymbolLoadException if an expected symbol is missing from the 158 library. 159 +/ 160 final void load(SharedLibVersion minRequiredVersion) 161 { 162 configureMinimumVersion(minRequiredVersion); 163 load(); 164 } 165 166 /++ 167 Finds and loads a shared library, using libNames to find the library 168 on the file system. 169 170 If multiple library names are specified in libNames, a SharedLibLoadException 171 will only be thrown if all of the libraries fail to load. It will be the head 172 of an exceptin chain containing one instance of the exception for each library 173 that failed. 174 175 Examples: If this loader supports versions 2.0 and 2.1 of a shared libary, 176 this method will attempt to load 2.1 and will fail if only 2.0 177 is present on the system. 178 179 Params: 180 libNames = A string containing one or more comma-separated shared 181 library names. 182 Throws: SharedLibLoadException if the shared library or one of its 183 dependencies cannot be found on the file system. 184 SymbolLoadException if an expected symbol is missing from the 185 library. 186 +/ 187 final void load(string libNames) 188 { 189 if(libNames == null) 190 libNames = _libNames; 191 192 auto lnames = libNames.split(","); 193 foreach(ref string l; lnames) 194 l = l.strip(); 195 196 load(lnames); 197 } 198 199 /++ 200 Finds and loads any version of a shared library greater than or equal to 201 the required mimimum version, using libNames to find the library 202 on the file system. 203 204 If multiple library names are specified as default, a SharedLibLoadException 205 will only be thrown if all of the libraries fail to load. It will be the head 206 of an exceptin chain containing one instance of the exception for each library 207 that failed. 208 209 Examples: If this loader supports versions 2.0 and 2.1 of a shared library, 210 passing a SharedLibVersion with the major field set to 2 and the 211 minor field set to 0 will cause the loader to load version 2.0 212 if version 2.1 is not available on the system. 213 214 Params: 215 libNames = A string containing one or more comma-separated shared 216 library names. 217 minRequiredVersion = The minimum version of the library that is acceptable. 218 Subclasses are free to ignore this. 219 220 Throws: SharedLibLoadException if the shared library or one of its 221 dependencies cannot be found on the file system. 222 SymbolLoadException if an expected symbol is missing from the 223 library. 224 +/ 225 final void load(string libNames, SharedLibVersion minRequiredVersion) 226 { 227 configureMinimumVersion(minRequiredVersion); 228 load(libNames); 229 } 230 231 /++ 232 Finds and loads a shared library, using libNames to find the library 233 on the file system. 234 235 If multiple library names are specified in libNames, a SharedLibLoadException 236 will only be thrown if all of the libraries fail to load. It will be the head 237 of an exception chain containing one instance of the exception for each library 238 that failed. 239 240 241 Params: 242 libNames = An array containing one or more shared library names, 243 with one name per index. 244 245 Throws: SharedLibLoadException if the shared library or one of its 246 dependencies cannot be found on the file system. 247 SymbolLoadException if an expected symbol is missing from the 248 library. 249 +/ 250 final void load(string[] libNames) 251 { 252 _lib.load(libNames); 253 loadSymbols(); 254 } 255 256 /++ 257 Finds and loads any version of a shared library greater than or equal to 258 the required mimimum version, , using libNames to find the library 259 on the file system. 260 261 If multiple library names are specified in libNames, a SharedLibLoadException 262 will only be thrown if all of the libraries fail to load. It will be the head 263 of an exception chain containing one instance of the exception for each library 264 that failed. 265 266 Examples: If this loader supports versions 2.0 and 2.1 of a shared library, 267 passing a SharedLibVersion with the major field set to 2 and the 268 minor field set to 0 will cause the loader to load version 2.0 269 if version 2.1 is not available on the system. 270 271 272 Params: 273 libNames = An array containing one or more shared library names, 274 with one name per index. 275 minRequiredVersion = The minimum version of the library that is acceptable. 276 Subclasses are free to ignore this. 277 278 Throws: SharedLibLoadException if the shared library or one of its 279 dependencies cannot be found on the file system. 280 SymbolLoadException if an expected symbol is missing from the 281 library. 282 +/ 283 final void load(string[] libNames, SharedLibVersion minRequiredVersion) 284 { 285 configureMinimumVersion(minRequiredVersion); 286 load(libNames); 287 } 288 289 /++ 290 Unloads the shared library from memory, invalidating all function pointers 291 which were assigned a symbol by one of the load methods. 292 +/ 293 final void unload() { _lib.unload(); } 294 295 296 /// Returns: true if the shared library is loaded, false otherwise. 297 @property @nogc nothrow 298 final bool isLoaded() { return _lib.isLoaded; } 299 300 /++ 301 Sets the callback that will be called when an expected symbol is 302 missing from the shared library. 303 304 Params: 305 callback = A delegate that returns a value of type 306 derelict.util.exception.ShouldThrow and accepts 307 a string as the sole parameter. 308 +/ 309 @property @nogc nothrow 310 final void missingSymbolCallback(MissingSymbolCallbackDg callback) 311 { 312 _lib.missingSymbolCallback = callback; 313 } 314 315 /++ 316 Sets the callback that will be called when an expected symbol is 317 missing from the shared library. 318 319 Params: 320 callback = A pointer to a function that returns a value of type 321 derelict.util.exception.ShouldThrow and accepts 322 a string as the sole parameter. 323 +/ 324 @property @nogc nothrow 325 final void missingSymbolCallback(MissingSymbolCallbackFunc callback) 326 { 327 _lib.missingSymbolCallback = callback; 328 } 329 330 /++ 331 Returns the currently active missing symbol callback. 332 333 This exists primarily as a means to save the current callback before 334 setting a new one. It's useful, for example, if the new callback needs 335 to delegate to the old one. 336 +/ 337 @property @nogc nothrow 338 final MissingSymbolCallback missingSymbolCallback() 339 { 340 return _lib.missingSymbolCallback; 341 } 342 343 protected: 344 /++ 345 Must be implemented by subclasses to load all of the symbols from a 346 shared library. 347 348 This method is called by the load methods. 349 +/ 350 abstract void loadSymbols(); 351 352 /++ 353 Allows a subclass to install an exception handler for specific versions 354 of a library before loadSymbols is called. 355 356 This method is optional. If the subclass does not implement it, calls to 357 any of the overloads of the load method that take a SharedLibVersion will 358 cause a compile time assert to fire. 359 +/ 360 void configureMinimumVersion(SharedLibVersion minVersion) 361 { 362 assert(0, "SharedLibVersion is not supported by this loader."); 363 } 364 365 /++ 366 Subclasses can use this as an alternative to bindFunc, but must bind 367 the returned symbol manually. 368 369 bindFunc calls this internally, so it can be overloaded to get behavior 370 different from the default. 371 372 Params: 373 name = The name of the symbol to load.doThrow = If true, a SymbolLoadException will be thrown if the symbol 374 is missing. If false, no exception will be thrown and the 375 ptr parameter will be set to null. 376 Throws: SymbolLoadException if doThrow is true and a the symbol 377 specified by funcName is missing from the shared library. 378 Returns: The symbol matching the name parameter. 379 +/ 380 void* loadSymbol(string name, bool doThrow = true) 381 { 382 return _lib.loadSymbol(name, doThrow); 383 } 384 385 /// Returns a reference to the shared library wrapped by this loader. 386 @property @nogc nothrow 387 final ref SharedLib lib(){ return _lib; } 388 389 390 private: 391 string _libNames; 392 SharedLib _lib; 393 }