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 import std.string; 32 import std.conv; 33 34 import derelict.util.exception; 35 import derelict.util.system; 36 } 37 38 static if( Derelict_OS_Posix ) { 39 static if( Derelict_OS_Linux ) { 40 private import std.c.linux.linux; 41 } else { 42 extern( C ) nothrow { 43 /* From <dlfcn.h> 44 * See http://www.opengroup.org/onlinepubs/007908799/xsh/dlsym.html 45 */ 46 47 const int RTLD_NOW = 2; 48 49 void *dlopen( const( char )* file, int mode ); 50 int dlclose( void* handle ); 51 void *dlsym( void* handle, const( char* ) name ); 52 const( char )* dlerror(); 53 } 54 } 55 56 alias void* SharedLibHandle; 57 58 private { 59 SharedLibHandle LoadSharedLib( string libName ) { 60 return dlopen( libName.toStringz(), RTLD_NOW ); 61 } 62 63 void UnloadSharedLib( SharedLibHandle hlib ) { 64 dlclose( hlib ); 65 } 66 67 void* GetSymbol( SharedLibHandle hlib, string symbolName ) { 68 return dlsym( hlib, symbolName.toStringz() ); 69 } 70 71 string GetErrorStr() { 72 auto err = dlerror(); 73 if( err is null ) 74 return "Uknown Error"; 75 76 return to!string( err ); 77 } 78 } 79 } else static if( Derelict_OS_Windows ) { 80 private import derelict.util.wintypes; 81 alias HMODULE SharedLibHandle; 82 83 private { 84 SharedLibHandle LoadSharedLib( string libName ) { 85 return LoadLibraryA( libName.toStringz() ); 86 } 87 88 void UnloadSharedLib( SharedLibHandle hlib ) { 89 FreeLibrary( hlib ); 90 } 91 92 void* GetSymbol( SharedLibHandle hlib, string symbolName ) { 93 return GetProcAddress( hlib, symbolName.toStringz() ); 94 } 95 96 string GetErrorStr() { 97 import std.windows.syserror; 98 return sysErrorString( GetLastError() ); 99 } 100 } 101 } else { 102 static assert( 0, "Derelict does not support this platform." ); 103 } 104 105 /++ 106 Low-level wrapper of the even lower-level operating-specific shared library 107 loading interface. 108 109 While this interface can be used directly in applications, it is recommended 110 to use the interface specified by derelict.util.loader.SharedLibLoader 111 to implement bindings. SharedLib is designed to be the base of a higher-level 112 loader, but can be used in a program if only a handful of functions need to 113 be loaded from a given shared library. 114 +/ 115 struct SharedLib { 116 private { 117 string _name; 118 SharedLibHandle _hlib; 119 private MissingSymbolCallbackDg _onMissingSym; 120 } 121 122 public { 123 /++ 124 Finds and loads a shared library, using libNames to find the library 125 on the file system. 126 127 If multiple library names are specified in libNames, a SharedLibLoadException 128 will only be thrown if all of the libraries fail to load. It will be the head 129 of an exceptin chain containing one instance of the exception for each library 130 that failed. 131 132 133 Params: 134 libNames = An array containing one or more shared library names, 135 with one name per index. 136 Throws: SharedLibLoadException if the shared library or one of its 137 dependencies cannot be found on the file system. 138 SymbolLoadException if an expected symbol is missing from the 139 library. 140 +/ 141 void load( string[] names ) { 142 if( isLoaded ) 143 return; 144 145 string[] failedLibs; 146 string[] reasons; 147 148 foreach( n; names ) { 149 _hlib = LoadSharedLib( n ); 150 if( _hlib !is null ) { 151 _name = n; 152 break; 153 } 154 155 failedLibs ~= n; 156 reasons ~= GetErrorStr(); 157 } 158 159 if( !isLoaded ) { 160 SharedLibLoadException.throwNew( failedLibs, reasons ); 161 } 162 } 163 164 /++ 165 Loads the symbol specified by symbolName from a shared library. 166 167 Params: 168 symbolName = The name of the symbol to load. 169 doThrow = If true, a SymbolLoadException will be thrown if the symbol 170 is missing. If false, no exception will be thrown and the 171 ptr parameter will be set to null. 172 Throws: SymbolLoadException if doThrow is true and a the symbol 173 specified by funcName is missing from the shared library. 174 +/ 175 void* loadSymbol( string symbolName, bool doThrow = true ) { 176 void* sym = GetSymbol( _hlib, symbolName ); 177 if( doThrow && !sym ) { 178 auto result = ShouldThrow.Yes; 179 if( _onMissingSym !is null ) 180 result = _onMissingSym( symbolName ); 181 if( result == ShouldThrow.Yes ) 182 throw new SymbolLoadException( _name, symbolName ); 183 } 184 185 return sym; 186 } 187 188 /++ 189 Unloads the shared library from memory, invalidating all function pointers 190 which were assigned a symbol by one of the load methods. 191 +/ 192 void unload() { 193 if( isLoaded ) { 194 UnloadSharedLib( _hlib ); 195 _hlib = null; 196 } 197 } 198 199 @property { 200 /// Returns the name of the shared library. 201 string name() { 202 return _name; 203 } 204 205 /// Returns true if the shared library is currently loaded, false otherwise. 206 bool isLoaded() { 207 return ( _hlib !is null ); 208 } 209 210 /++ 211 Sets the callback that will be called when an expected symbol is 212 missing from the shared library. 213 214 Params: 215 callback = A delegate that returns a value of type 216 derelict.util.exception.ShouldThrow and accepts 217 a string as the sole parameter. 218 +/ 219 void missingSymbolCallback( MissingSymbolCallbackDg callback ) { 220 _onMissingSym = callback; 221 } 222 223 /++ 224 Sets the callback that will be called when an expected symbol is 225 missing from the shared library. 226 227 Params: 228 callback = A pointer to a function that returns a value of type 229 derelict.util.exception.ShouldThrow and accepts 230 a string as the sole parameter. 231 +/ 232 void missingSymbolCallback( MissingSymbolCallbackFunc callback ) { 233 import std.functional : toDelegate; 234 _onMissingSym = toDelegate( callback ); 235 } 236 } 237 } 238 }