1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 module gtkc.Loader; 21 22 version(Tango) 23 { 24 import tango.io.Stdout; 25 import tango.stdc.stringz; 26 27 import gtkc.glibtypes; 28 // private alias char[] string; 29 } 30 else 31 { 32 import std.stdio; 33 import std.string; 34 } 35 36 import gtkc.paths; 37 38 public struct Linker 39 { 40 private static void*[string] loadedLibraries; 41 private static string[][string] loadFailures; 42 43 /* 44 * Links the provided symbol 45 * Params: 46 * funct = The function we are linking 47 * symbol = The name of the symbol to link 48 * libraries = One or more libraries to search for the symbol 49 */ 50 public static void link(T)(ref T funct, string symbol, LIBRARY[] libraries ...) 51 { 52 funct = cast(T)getSymbol(symbol, libraries); 53 } 54 55 /* 56 * Links the provided symbol 57 * Params: 58 * funct = The function we are linking 59 * symbol = The name of the symbol to link 60 * libraries = One or more libraries to search for the symbol 61 */ 62 public static void link(T)(ref T funct, string symbol, string[] libraries ...) 63 { 64 funct = cast(T)getSymbol(symbol, libraries); 65 } 66 67 /* 68 * Gets a simbol from one of the provided libraries 69 * Params: 70 * symbol = The name of the symbol to link 71 * libraries = One or more libraries to search for the symbol 72 */ 73 public static void* getSymbol(string symbol, LIBRARY[] libraries ...) 74 { 75 string[] libStr = new string[libraries.length]; 76 77 foreach (i, library; libraries ) 78 { 79 libStr[i] = importLibs[library]; 80 } 81 82 return getSymbol(symbol, libStr); 83 } 84 85 /* 86 * Gets a simbol from one of the provided libraries 87 * Params: 88 * symbol = The name of the symbol to link 89 * libraries = One or more libraries to search for the symbol 90 */ 91 public static void* getSymbol(string symbol, string[] libraries ...) 92 { 93 void* handle; 94 95 foreach ( library; libraries ) 96 { 97 if( !(library in loadedLibraries) ) 98 loadLibrary(library); 99 100 handle = pGetSymbol(loadedLibraries[library], symbol); 101 102 if ( handle !is null ) 103 break; 104 } 105 106 if ( handle is null ) 107 { 108 foreach ( library; libraries ) 109 loadFailures[library] ~= symbol; 110 } 111 112 return handle; 113 } 114 115 /* 116 * Loads a library 117 */ 118 public static void loadLibrary(string library) 119 { 120 void* handle = pLoadLibrary(library); 121 122 //TODO: A more general way to try more than one version. 123 if ( handle is null && library == importLibs[LIBRARY.GSV] ) 124 handle = pLoadLibrary(importLibs[LIBRARY.GSV1]); 125 126 if ( handle is null ) 127 throw new Exception("Library load failed: " ~ library); 128 129 loadedLibraries[library] = handle; 130 } 131 132 /* 133 * Unload a library 134 */ 135 public static void unloadLibrary(LIBRARY library) 136 { 137 unloadLibrary( importLibs[library] ); 138 } 139 140 /* 141 * Unload a library 142 */ 143 public static void unloadLibrary(string library) 144 { 145 pUnloadLibrary(loadedLibraries[library]); 146 147 loadedLibraries.remove(library); 148 } 149 150 /** 151 * Checks if any symbol failed to load 152 * Returns: true if ALL symbols are loaded 153 */ 154 public static bool isPerfectLoad() 155 { 156 return loadFailures.keys.length == 0; 157 } 158 159 /** 160 * Gets all libraries loaded. 161 * returns: An array with the loaded libraries 162 */ 163 public static string[] getLoadLibraries() 164 { 165 return loadedLibraries.keys; 166 } 167 168 /** 169 * Print all libraries loaded. 170 */ 171 public static void dumpLoadLibraries() 172 { 173 foreach ( lib; getLoadLibraries() ) 174 { 175 version(Tango) 176 Stdout.formatln("Loaded lib = {}", lib); 177 else 178 writefln("Loaded lib = %s", lib); 179 } 180 } 181 182 /** 183 * Checks if a library is loaded. 184 * Returns: true is the library was loaded sucsessfully. 185 */ 186 public static bool isLoaded(LIBRARY library) 187 { 188 return isLoaded(importLibs[library]); 189 } 190 191 /** 192 * Checks if a library is loaded. 193 * Returns: true is the library was loaded sucsessfully. 194 */ 195 public static bool isLoaded(string library) 196 { 197 if ( library in loadedLibraries ) 198 return true; 199 else 200 return false; 201 } 202 203 /** 204 * Gets all the failed loads for a specific library. 205 * returns: An array of the names hat failed to load for a specific library 206 * or null if none was found 207 */ 208 public static string[] getLoadFailures(LIBRARY library) 209 { 210 return getLoadFailures(importLibs[library]); 211 } 212 213 /** 214 * Gets all the failed loads for a specific library. 215 * returns: An array of the names hat failed to load for a specific library 216 * or null if none was found 217 */ 218 public static string[] getLoadFailures(string library) 219 { 220 if ( library in loadFailures ) 221 return loadFailures[library]; 222 else 223 return null; 224 } 225 226 /** 227 * Print all symbols that failed to load 228 */ 229 public static void dumpFailedLoads() 230 { 231 foreach ( library; loadedLibraries.keys ) 232 { 233 foreach ( symbol; getLoadFailures(library) ) 234 { 235 version(Tango) 236 Stdout.formatln("failed ({}) {}", library, symbol); 237 else 238 writefln("failed (%s) %s", library, symbol); 239 } 240 } 241 } 242 243 static ~this() 244 { 245 foreach ( library; loadedLibraries.keys ) 246 unloadLibrary(library); 247 } 248 } 249 250 // Platform specific implementation below. 251 252 version(Windows) 253 { 254 extern(Windows) 255 { 256 void* LoadLibraryA(char*); 257 void* GetProcAddress(void*, char*); 258 void FreeLibrary(void*); 259 } 260 261 private void* pLoadLibrary(string libraryName) 262 { 263 return LoadLibraryA(cast(char*)toStringz(libraryName)); 264 } 265 266 private void* pGetSymbol(void* handle, string symbol) 267 { 268 return GetProcAddress(handle, cast(char*)toStringz(symbol)); 269 } 270 271 private alias FreeLibrary pUnloadLibrary; 272 } 273 else 274 { 275 extern(C) 276 { 277 void* dlopen(char*, int); 278 char* dlerror(); 279 void* dlsym(void*,char*); 280 int dlclose(void*); 281 } 282 283 enum RTLD 284 { 285 GDC_BUG_WORKAROUND, 286 LAZY = 0x00001, // Lazy function call binding 287 NOW = 0x00002, // Immediate function call binding 288 NOLOAD = 0x00004, // No object load 289 DEEPBIND = 0x00008, // 290 GLOBAL = 0x00100 // Make object available to whole program 291 } 292 293 private void* pLoadLibrary(string libraryName, RTLD flag = RTLD.NOW) 294 { 295 void* handle = dlopen(cast(char*)toStringz(libraryName), flag); 296 297 // clear the error buffer 298 dlerror(); 299 300 return handle; 301 } 302 303 private void* pGetSymbol(void* libraryHandle, string symbol) 304 { 305 void* symbolHandle = dlsym(libraryHandle, cast(char*)toStringz(symbol)); 306 307 // clear the error buffer 308 dlerror(); 309 310 return symbolHandle; 311 } 312 313 private int pUnloadLibrary(void* libraryHandle) 314 { 315 return dlclose(libraryHandle); 316 } 317 318 version(build) version(linux) 319 { 320 pragma(link, "dl"); // tell dsss to link libdl 321 } 322 }